예제 #1
0
 /**
  * Websocket handshake.
  *
  * @param string                              $buffer
  * @param \Workerman\Connection\TcpConnection $connection
  * @return int
  */
 protected static function dealHandshake($buffer, $connection)
 {
     // HTTP protocol.
     if (0 === strpos($buffer, 'GET')) {
         // Find \r\n\r\n.
         $heder_end_pos = strpos($buffer, "\r\n\r\n");
         if (!$heder_end_pos) {
             return 0;
         }
         $header_length = $heder_end_pos + 4;
         // Get Sec-WebSocket-Key.
         $Sec_WebSocket_Key = '';
         if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) {
             $Sec_WebSocket_Key = $match[1];
         } else {
             $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Sec-WebSocket-Key not found.<br>This is a WebSocket service and can not be accessed via HTTP.", true);
             $connection->close();
             return 0;
         }
         // Calculation websocket key.
         $new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));
         // Handshake response data.
         $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n";
         $handshake_message .= "Upgrade: websocket\r\n";
         $handshake_message .= "Sec-WebSocket-Version: 13\r\n";
         $handshake_message .= "Connection: Upgrade\r\n";
         $handshake_message .= "Server: workerman/" . Worker::VERSION . "\r\n";
         $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
         // Mark handshake complete..
         $connection->websocketHandshake = true;
         // Websocket data buffer.
         $connection->websocketDataBuffer = '';
         // Current websocket frame length.
         $connection->websocketCurrentFrameLength = 0;
         // Current websocket frame data.
         $connection->websocketCurrentFrameBuffer = '';
         // Consume handshake data.
         $connection->consumeRecvBuffer($header_length);
         // Send handshake response.
         $connection->send($handshake_message, true);
         // There are data waiting to be sent.
         if (!empty($connection->tmpWebsocketData)) {
             $connection->send($connection->tmpWebsocketData, true);
             $connection->tmpWebsocketData = '';
         }
         // blob or arraybuffer
         if (empty($connection->websocketType)) {
             $connection->websocketType = self::BINARY_TYPE_BLOB;
         }
         // Try to emit onWebSocketConnect callback.
         if (isset($connection->onWebSocketConnect)) {
             self::parseHttpHeader($buffer);
             try {
                 call_user_func($connection->onWebSocketConnect, $connection, $buffer);
             } catch (\Exception $e) {
                 Worker::log($e);
                 exit(250);
             } catch (\Error $e) {
                 Worker::log($e);
                 exit(250);
             }
             if (!empty($_SESSION) && class_exists('\\GatewayWorker\\Lib\\Context')) {
                 $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION);
             }
             $_GET = $_SERVER = $_SESSION = $_COOKIE = array();
         }
         if (strlen($buffer) > $header_length) {
             return self::input(substr($buffer, $header_length), $connection);
         }
         return 0;
     } elseif (0 === strpos($buffer, '<polic')) {
         $policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . "";
         $connection->send($policy_xml, true);
         $connection->consumeRecvBuffer(strlen($buffer));
         return 0;
     }
     // Bad websocket handshake request.
     $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Invalid handshake data for websocket. ", true);
     $connection->close();
     return 0;
 }
예제 #2
0
 /**
  * 当gateway转发来数据时
  * @param TcpConnection $connection
  * @param mixed $data
  */
 public function onGatewayMessage($connection, $data)
 {
     // 上下文数据
     Context::$client_ip = $data['client_ip'];
     Context::$client_port = $data['client_port'];
     Context::$local_ip = $data['local_ip'];
     Context::$local_port = $data['local_port'];
     Context::$client_id = $data['client_id'];
     // $_SERVER变量
     $_SERVER = array('REMOTE_ADDR' => Context::$client_ip, 'REMOTE_PORT' => Context::$client_port, 'GATEWAY_ADDR' => Context::$local_ip, 'GATEWAY_PORT' => Context::$local_port, 'GATEWAY_CLIENT_ID' => Context::$client_id);
     // 尝试解析session
     if ($data['ext_data'] != '') {
         $_SESSION = Context::sessionDecode($data['ext_data']);
     } else {
         $_SESSION = null;
     }
     // 备份一次$data['ext_data'],请求处理完毕后判断session是否和备份相等,不相等就更新session
     $session_str_copy = $data['ext_data'];
     $cmd = $data['cmd'];
     // 尝试执行Event::onConnection、Event::onMessage、Event::onClose
     try {
         switch ($cmd) {
             case GatewayProtocol::CMD_ON_CONNECTION:
                 Event::onConnect(Context::$client_id);
                 break;
             case GatewayProtocol::CMD_ON_MESSAGE:
                 Event::onMessage(Context::$client_id, $data['body']);
                 break;
             case GatewayProtocol::CMD_ON_CLOSE:
                 Event::onClose(Context::$client_id);
                 break;
         }
     } catch (\Exception $e) {
         $msg = 'client_id:' . Context::$client_id . "\tclient_ip:" . Context::$client_ip . "\n" . $e->__toString();
         $this->log($msg);
     }
     // 判断session是否被更改
     $session_str_now = $_SESSION !== null ? Context::sessionEncode($_SESSION) : '';
     if ($session_str_copy != $session_str_now) {
         \GatewayWorker\Lib\Gateway::updateSocketSession(Context::$client_id, $session_str_now);
     }
     Context::clear();
 }
 /**
  * 当gateway转发来数据时
  * @param TcpConnection $connection
  * @param mixed $data
  */
 public function onGatewayMessage($connection, $data)
 {
     // 上下文数据
     Context::$client_ip = $data['client_ip'];
     Context::$client_port = $data['client_port'];
     Context::$local_ip = $data['local_ip'];
     Context::$local_port = $data['local_port'];
     Context::$connection_id = $data['connection_id'];
     Context::$client_id = Context::addressToClientId($data['local_ip'], $data['local_port'], $data['connection_id']);
     // $_SERVER变量
     $_SERVER = array('REMOTE_ADDR' => long2ip($data['client_ip']), 'REMOTE_PORT' => $data['client_port'], 'GATEWAY_ADDR' => long2ip($data['local_ip']), 'GATEWAY_PORT' => $data['gateway_port'], 'GATEWAY_CLIENT_ID' => Context::$client_id);
     // 尝试解析session
     if ($data['ext_data'] != '') {
         $_SESSION = Context::sessionDecode($data['ext_data']);
     } else {
         $_SESSION = null;
     }
     // 备份一次$data['ext_data'],请求处理完毕后判断session是否和备份相等,不相等就更新session
     $session_str_copy = $data['ext_data'];
     $cmd = $data['cmd'];
     if ($this->processTimeout) {
         pcntl_alarm($this->processTimeout);
     }
     // 尝试执行Event::onConnection、Event::onMessage、Event::onClose
     switch ($cmd) {
         case GatewayProtocol::CMD_ON_CONNECTION:
             if ($this->_eventOnConnect) {
                 call_user_func($this->_eventOnConnect, Context::$client_id);
             }
             break;
         case GatewayProtocol::CMD_ON_MESSAGE:
             if ($this->_eventOnMessage) {
                 call_user_func($this->_eventOnMessage, Context::$client_id, $data['body']);
             }
             break;
         case GatewayProtocol::CMD_ON_CLOSE:
             if ($this->_eventOnClose) {
                 call_user_func($this->_eventOnClose, Context::$client_id);
             }
             break;
     }
     if ($this->processTimeout) {
         pcntl_alarm(0);
     }
     // 判断session是否被更改
     $session_str_now = $_SESSION !== null ? Context::sessionEncode($_SESSION) : '';
     if ($session_str_copy != $session_str_now) {
         \GatewayWorker\Lib\Gateway::updateSocketSession(Context::$client_id, $session_str_now);
     }
     Context::clear();
 }
예제 #4
0
 /**
  * 想某个用户网关发送命令和消息
  * @param int $client_id
  * @param int $cmd
  * @param string $message
  * @return boolean
  */
 protected static function sendCmdAndMessageToClient($client_id, $cmd, $message, $ext_data = '')
 {
     // 如果是发给当前用户则直接获取上下文中的地址
     if ($client_id === Context::$client_id || $client_id === null) {
         $address = long2ip(Context::$local_ip) . ':' . Context::$local_port;
         $connection_id = Context::$connection_id;
     } else {
         $address_data = Context::clientIdToAddress($client_id);
         $address = long2ip($address_data['local_ip']) . ":{$address_data['local_port']}";
         $connection_id = $address_data['connection_id'];
     }
     $gateway_data = GatewayProtocol::$empty;
     $gateway_data['cmd'] = $cmd;
     $gateway_data['connection_id'] = $connection_id;
     $gateway_data['body'] = $message;
     if (!empty($ext_data)) {
         $gateway_data['ext_data'] = $ext_data;
     }
     return self::sendToGateway($address, $gateway_data);
 }
예제 #5
0
 /**
  * 更新session
  * @param int $client_id
  * @param array $session
  */
 public static function updateSession($client_id, array $session)
 {
     self::updateSocketSession($client_id, Context::sessionEncode($session));
 }