|
|
@@ -71,6 +71,13 @@ class Ws
|
|
|
$data_len = $secondbyte & 127;
|
|
|
$is_fin_frame = $firstbyte >> 7;
|
|
|
$masked = $secondbyte >> 7;
|
|
|
+
|
|
|
+ if ($masked) {
|
|
|
+ echo "frame masked\n";
|
|
|
+ $connection->close();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
$opcode = $firstbyte & 0xf;
|
|
|
|
|
|
switch ($opcode) {
|
|
|
@@ -119,7 +126,7 @@ class Ws
|
|
|
}
|
|
|
// Consume data from receive buffer.
|
|
|
if (!$data_len) {
|
|
|
- $head_len = $masked ? 6 : 2;
|
|
|
+ $head_len = 2;
|
|
|
$connection->consumeRecvBuffer($head_len);
|
|
|
if ($recv_len > $head_len) {
|
|
|
return self::input(substr($buffer, $head_len), $connection);
|
|
|
@@ -143,7 +150,7 @@ class Ws
|
|
|
}
|
|
|
// Consume data from receive buffer.
|
|
|
if (!$data_len) {
|
|
|
- $head_len = $masked ? 6 : 2;
|
|
|
+ $head_len = 2;
|
|
|
$connection->consumeRecvBuffer($head_len);
|
|
|
if ($recv_len > $head_len) {
|
|
|
return self::input(substr($buffer, $head_len), $connection);
|
|
|
@@ -159,7 +166,7 @@ class Ws
|
|
|
}
|
|
|
// Calculate packet length.
|
|
|
if ($data_len === 126) {
|
|
|
- if (strlen($buffer) < 6) {
|
|
|
+ if (strlen($buffer) < 4) {
|
|
|
return 0;
|
|
|
}
|
|
|
$pack = unpack('nn/ntotal_len', $buffer);
|
|
|
@@ -289,31 +296,14 @@ class Ws
|
|
|
*/
|
|
|
public static function decode($bytes, $connection)
|
|
|
{
|
|
|
- $masked = ord($bytes[1]) >> 7;
|
|
|
- $data_length = $masked ? ord($bytes[1]) & 127 : ord($bytes[1]);
|
|
|
- $decoded_data = '';
|
|
|
- if ($masked === true) {
|
|
|
- if ($data_length === 126) {
|
|
|
- $mask = substr($bytes, 4, 4);
|
|
|
- $coded_data = substr($bytes, 8);
|
|
|
- } else if ($data_length === 127) {
|
|
|
- $mask = substr($bytes, 10, 4);
|
|
|
- $coded_data = substr($bytes, 14);
|
|
|
- } else {
|
|
|
- $mask = substr($bytes, 2, 4);
|
|
|
- $coded_data = substr($bytes, 6);
|
|
|
- }
|
|
|
- for ($i = 0; $i < strlen($coded_data); $i++) {
|
|
|
- $decoded_data .= $coded_data[$i] ^ $mask[$i % 4];
|
|
|
- }
|
|
|
+ $data_length = ord($bytes[1]);
|
|
|
+
|
|
|
+ if ($data_length === 126) {
|
|
|
+ $decoded_data = substr($bytes, 4);
|
|
|
+ } else if ($data_length === 127) {
|
|
|
+ $decoded_data = substr($bytes, 10);
|
|
|
} else {
|
|
|
- if ($data_length === 126) {
|
|
|
- $decoded_data = substr($bytes, 4);
|
|
|
- } else if ($data_length === 127) {
|
|
|
- $decoded_data = substr($bytes, 10);
|
|
|
- } else {
|
|
|
- $decoded_data = substr($bytes, 2);
|
|
|
- }
|
|
|
+ $decoded_data = substr($bytes, 2);
|
|
|
}
|
|
|
if ($connection->websocketCurrentFrameLength) {
|
|
|
$connection->websocketDataBuffer .= $decoded_data;
|
|
|
@@ -369,13 +359,15 @@ class Ws
|
|
|
$port = $connection->getRemotePort();
|
|
|
$host = $port === 80 ? $connection->getRemoteHost() : $connection->getRemoteHost() . ':' . $port;
|
|
|
// Handshake header.
|
|
|
+ $connection->websocketSecKey = base64_encode(md5(mt_rand(), true));
|
|
|
$header = 'GET ' . $connection->getRemoteURI() . " HTTP/1.1\r\n".
|
|
|
"Host: $host\r\n".
|
|
|
"Connection: Upgrade\r\n".
|
|
|
"Upgrade: websocket\r\n".
|
|
|
"Origin: ". (isset($connection->websocketOrigin) ? $connection->websocketOrigin : '*') ."\r\n".
|
|
|
+ (isset($connection->WSClientProtocol)?"Sec-WebSocket-Protocol: ".$connection->WSClientProtocol."\r\n":'').
|
|
|
"Sec-WebSocket-Version: 13\r\n".
|
|
|
- "Sec-WebSocket-Key: " . base64_encode(md5(mt_rand(), true)) . "\r\n\r\n";
|
|
|
+ "Sec-WebSocket-Key: " . $connection->websocketSecKey . "\r\n\r\n";
|
|
|
$connection->send($header, true);
|
|
|
$connection->handshakeStep = 1;
|
|
|
$connection->websocketCurrentFrameLength = 0;
|
|
|
@@ -394,7 +386,26 @@ class Ws
|
|
|
{
|
|
|
$pos = strpos($buffer, "\r\n\r\n");
|
|
|
if ($pos) {
|
|
|
+ //checking Sec-WebSocket-Accept
|
|
|
+ if (preg_match("/Sec-WebSocket-Accept: *(.*?)\r\n/i", $buffer, $match)) {
|
|
|
+ if ($match[1] !== base64_encode(sha1($connection->websocketSecKey . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true))) {
|
|
|
+ echo "Sec-WebSocket-Accept not match. Header:\n" . substr($buffer, 0, $pos) . "\n";
|
|
|
+ $connection->close();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ echo "Sec-WebSocket-Accept not found. Header:\n" . substr($buffer, 0, $pos) . "\n";
|
|
|
+ $connection->close();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
// handshake complete
|
|
|
+
|
|
|
+ // Get WebSocket subprotocol (if specified by server)
|
|
|
+ if (preg_match("/Sec-WebSocket-Protocol: *(.*?)\r\n/i", $buffer, $match)) {
|
|
|
+ $connection->WSServerProtocol = trim($match[1]);
|
|
|
+ }
|
|
|
+
|
|
|
$connection->handshakeStep = 2;
|
|
|
$handshake_response_length = $pos + 4;
|
|
|
// Try to emit onWebSocketConnect callback.
|
|
|
@@ -430,4 +441,13 @@ class Ws
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+ public static function WSSetProtocol($connection, $params) {
|
|
|
+ $connection->WSClientProtocol = $params[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function WSGetServerProtocol($connection) {
|
|
|
+ return (property_exists($connection, 'WSServerProtocol')?$connection->WSServerProtocol:null);
|
|
|
+ }
|
|
|
+
|
|
|
}
|