Skip to content

Commit 0d69ad9

Browse files
author
prophet777
committed
Fix client disconnect webscoket
1 parent d897519 commit 0d69ad9

File tree

5 files changed

+151
-48
lines changed

5 files changed

+151
-48
lines changed

Auth/AuthenticationInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Gos\Component\WebSocketClient\Auth;
4+
5+
interface AuthenticationInterface
6+
{
7+
}

Auth/CookieAuthentication.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Gos\Component\WebSocketClient\Auth;
4+
5+
/**
6+
* @author Johann Saunier <[email protected]>
7+
*/
8+
class CookieAuthentication implements AuthenticationInterface
9+
{
10+
}

Wamp/Client.php

Lines changed: 119 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
use Gos\Component\WebSocketClient\Exception\BadResponseException;
66
use Gos\Component\WebSocketClient\Exception\WebsocketException;
7+
use Psr\Log\LoggerInterface;
78

89
/**
9-
* WS Client
10+
* WS Client.
1011
*
1112
* @author Martin Bažík <[email protected]>
1213
* @author Johann Saunier <[email protected]>
@@ -31,31 +32,76 @@ class Client
3132
/** @var string */
3233
protected $sessionId;
3334

35+
/** @var string */
36+
protected $origin;
37+
38+
/** @var LoggerInterface */
39+
protected $logger;
40+
41+
/** @var bool */
42+
protected $closing;
43+
44+
/** @var bool */
45+
protected $secured;
46+
3447
/**
35-
* @param string $endpoint
48+
* @param string $host
49+
* @param int|string $port
50+
* @param bool $secured
51+
* @param string $origin
3652
*/
37-
public function __construct($endpoint)
53+
public function __construct($host, $port, $secured = false, $origin = null)
3854
{
39-
$this->endpoint = $endpoint;
40-
$this->parseUrl();
55+
$this->serverHost = $host;
4156
$this->connected = false;
42-
$this->serverPort = 80;
57+
$this->closing = false;
58+
$this->secured = $secured;
59+
$this->serverPort = $port;
60+
61+
if (null === $origin) {
62+
$origin = $host;
63+
}
64+
65+
$this->origin = $origin;
66+
67+
$protocol = (true === $this->secured ? 'ssl' : 'tcp');
68+
69+
$this->endpoint = sprintf(
70+
'%s://%s:%s',
71+
$protocol,
72+
$host,
73+
$port
74+
);
75+
}
76+
77+
/**
78+
* @param LoggerInterface $logger
79+
*/
80+
public function setLogger(LoggerInterface $logger = null)
81+
{
82+
$this->logger = $logger;
83+
}
84+
85+
public function setAuthenticationToken()
86+
{
87+
/* @todo **/
4388
}
4489

4590
/**
4691
* @param string $target
4792
*
4893
* @return string
94+
*
4995
* @throws BadResponseException
5096
* @throws WebsocketException
5197
*/
52-
public function connect($target = '/websocket/')
98+
public function connect($target = '/')
5399
{
54100
if ($this->connected) {
55101
return $this->sessionId;
56102
}
57103

58-
$this->socket = stream_socket_client($this->serverHost . ':' . $this->serverPort, $errno, $errstr);
104+
$this->socket = stream_socket_client($this->endpoint, $errno, $errstr);
59105

60106
if (!$this->socket) {
61107
throw new BadResponseException('Could not open socket. Reason: ' . $errstr);
@@ -73,6 +119,8 @@ public function connect($target = '/websocket/')
73119

74120
$this->sessionId = $payload[1];
75121

122+
$this->connected = true;
123+
76124
return $this->sessionId;
77125
}
78126

@@ -91,13 +139,22 @@ protected function upgradeProtocol($target)
91139
throw new WebsocketException('Wamp Server Target is wrong.');
92140
}
93141

94-
$out = "GET " . $target . " HTTP/1.1\r\n";
95-
$out .= "Host: {$this->serverHost} \r\n";
142+
$protocol = true === $this->secured ? 'wss' : 'ws';
143+
144+
$out = "GET {$protocol}://{$this->serverHost}:{$this->serverPort}{$target} HTTP/1.1\r\n";
145+
$out .= "Host: {$this->serverHost}:{$this->serverPort}\r\n";
146+
$out .= "Pragma: no-cache\r\n";
147+
$out .= "Cache-Control: no-cache\r\n";
96148
$out .= "Upgrade: WebSocket\r\n";
97149
$out .= "Connection: Upgrade\r\n";
98-
$out .= "Sec-WebSocket-Key: $key \r\n";
150+
$out .= "Sec-WebSocket-Key: $key\r\n";
151+
$out .= "Sec-WebSocket-Protocol: wamp\r\n";
152+
153+
//@todo support auth
154+
// $out .= "Cookie: PHPSESSID=2okar2mng0mklk62iutc0bert0\r\n";
155+
99156
$out .= "Sec-WebSocket-Version: 13\r\n";
100-
$out .= "Origin: *\r\n\r\n";
157+
$out .= "Origin: {$this->origin}\r\n\r\n";
101158

102159
fwrite($this->socket, $out);
103160

@@ -123,9 +180,10 @@ protected function verifyResponse($response)
123180
}
124181

125182
/**
126-
* Read the buffer and return the oldest event in stack
183+
* Read the buffer and return the oldest event in stack.
127184
*
128185
* @see https://tools.ietf.org/html/rfc6455#section-5.2
186+
*
129187
* @return string
130188
*/
131189
protected function read()
@@ -150,14 +208,36 @@ protected function read()
150208
}
151209

152210
/**
153-
* Disconnect
211+
* Disconnect.
154212
*
155213
* @return boolean
156214
*/
157215
public function disconnect()
158216
{
217+
if (false === $this->connected) {
218+
return true;
219+
}
220+
159221
if ($this->socket) {
222+
$this->send(WebsocketPayload::generateClosePayload(), WebsocketPayload::OPCODE_CLOSE);
223+
$this->closing = true;
224+
225+
$payloadLength = ord(fread($this->socket, 1));
226+
$payload = fread($this->socket, $payloadLength);
227+
228+
if ($payloadLength >= 2) {
229+
$bin = $payload[0] . $payload[1];
230+
$status = bindec(sprintf("%08b%08b", ord($payload[0]), ord($payload[1])));
231+
}
232+
233+
if ($this->closing) {
234+
$this->closing = false;
235+
} else {
236+
$this->send($bin . 'Close acknowledged: ' . $status, WebsocketPayload::OPCODE_CLOSE);
237+
}
238+
160239
fclose($this->socket);
240+
$this->connected = false;
161241

162242
return true;
163243
}
@@ -166,19 +246,21 @@ public function disconnect()
166246
}
167247

168248
/**
169-
* Send message to the websocket
249+
* Send message to the websocket.
170250
*
171251
* @access private
172-
* @param array $data
252+
*
253+
* @param array $data
254+
*
173255
* @return $this|Client
174256
*/
175-
protected function send($data)
257+
protected function send($data, $opcode = WebsocketPayload::OPCODE_TEXT, $masked = true)
176258
{
177259
$rawMessage = json_encode($data);
178260
$payload = new WebsocketPayload();
179261
$payload
180-
->setOpcode(WebsocketPayload::OPCODE_TEXT)
181-
->setMask(true)
262+
->setOpcode($opcode)
263+
->setMask($masked)
182264
->setPayload($rawMessage);
183265

184266
$encoded = $payload->encodePayload();
@@ -188,8 +270,10 @@ protected function send($data)
188270
}
189271

190272
/**
191-
* Establish a prefix on server
273+
* Establish a prefix on server.
274+
*
192275
* @see http://wamp.ws/spec#prefix_message
276+
*
193277
* @param string $prefix
194278
* @param string $uri
195279
*/
@@ -201,8 +285,10 @@ public function prefix($prefix, $uri)
201285
}
202286

203287
/**
204-
* Call a procedure on server
288+
* Call a procedure on server.
289+
*
205290
* @see http://wamp.ws/spec#call_message
291+
*
206292
* @param string $procURI
207293
* @param mixed $arguments
208294
*/
@@ -218,22 +304,31 @@ public function call($procUri, $arguments = [])
218304
}
219305

220306
/**
221-
* The client will send an event to all clients connected to the server who have subscribed to the topicURI
307+
* The client will send an event to all clients connected to the server who have subscribed to the topicURI.
308+
*
222309
* @see http://wamp.ws/spec#publish_message
310+
*
223311
* @param string $topicUri
224312
* @param string $payload
225313
* @param string $exclude
226314
* @param string $eligible
227315
*/
228316
public function publish($topicUri, $payload, $exclude = [], $eligible = [])
229317
{
230-
$type = Protocol::MSG_PUBLISH;
231-
$data = array($type, $topicUri, $payload, $exclude, $eligible);
318+
if (null !== $this->logger) {
319+
$this->logger->info(sprintf(
320+
'Publish in %s',
321+
$topicUri
322+
));
323+
}
324+
325+
$data = array(Protocol::MSG_PUBLISH, $topicUri, $payload, $exclude, $eligible);
232326
$this->send($data);
233327
}
234328

235329
/**
236330
* Subscribers receive PubSub events published by subscribers via the EVENT message. The EVENT message contains the topicURI, the topic under which the event was published, and event, the PubSub event payload.
331+
*
237332
* @param string $topicUri
238333
* @param string $payload
239334
*/
@@ -260,27 +355,4 @@ protected function generateKey($length = 16)
260355

261356
return base64_encode(substr($tmp, 0, $length));
262357
}
263-
264-
/**
265-
* Parse the url and set server parameters
266-
*
267-
* @access private
268-
* @return bool
269-
*/
270-
protected function parseUrl()
271-
{
272-
$url = parse_url($this->endpoint);
273-
274-
$this->serverHost = $url['host'];
275-
$this->serverPort = isset($url['port']) ? $url['port'] : null;
276-
277-
if (array_key_exists('scheme', $url) && $url['scheme'] == 'https') {
278-
$this->serverHost = 'ssl://' . $this->serverHost;
279-
if (!$this->serverPort) {
280-
$this->serverPort = 443;
281-
}
282-
}
283-
284-
return true;
285-
}
286358
}

Wamp/Protocol.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Gos\Component\WebSocketClient\Wamp;
44

55
/**
6-
* Description of Protocol
6+
* Description of Protocol.
77
*
88
* @author Martin Bažík <[email protected]>
99
* @author Johann Saunier <[email protected]>

Wamp/WebsocketPayload.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,20 @@ public function encodePayload()
177177
return $payload;
178178
}
179179

180+
public static function generateClosePayload()
181+
{
182+
$status = 1000;
183+
$message = 'ttfn';
184+
$bin = sprintf('%016b', $status);
185+
$str = '';
186+
187+
foreach (str_split($bin, 8) as $binstr) {
188+
$str .= chr(bindec($binstr));
189+
}
190+
191+
return $str . $message;
192+
}
193+
180194
public function maskData($data, $key)
181195
{
182196
$masked = '';

0 commit comments

Comments
 (0)