From ed1a35ff7434087bfe35585a59d02dec38b1fd1c Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 27 Oct 2011 13:07:24 -0400 Subject: [PATCH] HyBi-10 handshake Hackishly implemented the HyBi-10 handshake --- lib/Ratchet/Protocol/WebSocket.php | 62 +++++++++++++++---- lib/Ratchet/Protocol/WebSocket/Client.php | 31 ++++++++++ .../Protocol/WebSocket/Version/Hixie76.php | 5 ++ .../Protocol/WebSocket/Version/Hybi10.php | 12 +++- .../WebSocket/Version/VersionInterface.php | 5 ++ lib/Ratchet/Server.php | 8 ++- lib/Ratchet/Socket.php | 1 + 7 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 lib/Ratchet/Protocol/WebSocket/Client.php diff --git a/lib/Ratchet/Protocol/WebSocket.php b/lib/Ratchet/Protocol/WebSocket.php index 060a354..7d007bd 100644 --- a/lib/Ratchet/Protocol/WebSocket.php +++ b/lib/Ratchet/Protocol/WebSocket.php @@ -1,7 +1,8 @@ _lookup = new \SplObjectStorage; + } /** * @return Array */ public static function getDefaultConfig() { - return Array( + return array( 'domain' => AF_INET , 'type' => SOCK_STREAM , 'protocol' => SOL_TCP - , 'options' => Array( - SOL_SOCKET => Array(SO_REUSEADDR => 1) + , 'options' => array( + SOL_SOCKET => array(SO_REUSEADDR => 1) ) ); } @@ -38,7 +41,7 @@ class WebSocket implements ProtocolInterface { /** * @return string */ - function getName() { + public function getName() { return 'WebSocket'; } @@ -46,12 +49,49 @@ class WebSocket implements ProtocolInterface { $this->_server = $server; } - function handleConnect(Socket $client) { + public function handleConnect(Socket $client) { + $this->_lookup[$client] = new Client; } - function handleMessage($message, Socket $from) { + public function handleMessage($message, Socket $from) { + $headers = $this->getHeaders($message); + $client = $this->_lookup[$from]; + if (true !== $client->isHandshakeComplete()) { + $header = $client->doHandshake($this->getVersion($headers)); + + $from->write($header, strlen($header)); + } } - function handleClose(Socket $client) { + public function handleClose(Socket $client) { + unset($this->_lookup[$client]); + } + + /** + * @param string + */ + public function setSubProtocol($name) { + } + + /** + * @param string + * @return array + */ + protected function getHeaders($http_message) { + return http_parse_headers($http_message); + } + + /** + * @return Version\VersionInterface + */ + protected function getVersion(array $headers) { + if (isset($headers['Sec-Websocket-Version'])) { // HyBi + if ($headers['Sec-Websocket-Version'] == '8') { + return new Version\Hybi10($headers); + } + } elseif (isset($headers['Sec-Websocket-Key2'])) { // Hixie + } + + throw new \UnexpectedValueException('Could not identify WebSocket protocol'); } } \ No newline at end of file diff --git a/lib/Ratchet/Protocol/WebSocket/Client.php b/lib/Ratchet/Protocol/WebSocket/Client.php new file mode 100644 index 0000000..ec0760b --- /dev/null +++ b/lib/Ratchet/Protocol/WebSocket/Client.php @@ -0,0 +1,31 @@ +sign(); +// $tosend['Sec-WebSocket-Accept'] = $key; + + $this->_hands_shook = true; + + return "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: {$key}\r\nSec-WebSocket-Protocol: test\r\n\r\n"; + } + + /** + * @return bool + */ + public function isHandshakeComplete() { + return $this->_hands_shook; + } +} \ No newline at end of file diff --git a/lib/Ratchet/Protocol/WebSocket/Version/Hixie76.php b/lib/Ratchet/Protocol/WebSocket/Version/Hixie76.php index 24d55ae..3ee2fce 100644 --- a/lib/Ratchet/Protocol/WebSocket/Version/Hixie76.php +++ b/lib/Ratchet/Protocol/WebSocket/Version/Hixie76.php @@ -2,6 +2,11 @@ namespace Ratchet\Protocol\WebSocket\Version; class Hixie76 implements VersionInterface { + protected $_headers = array(); + + public function __construct(array $headers) { + } + /** * @param Headers * @return string diff --git a/lib/Ratchet/Protocol/WebSocket/Version/Hybi10.php b/lib/Ratchet/Protocol/WebSocket/Version/Hybi10.php index 7db87a1..08d0f94 100644 --- a/lib/Ratchet/Protocol/WebSocket/Version/Hybi10.php +++ b/lib/Ratchet/Protocol/WebSocket/Version/Hybi10.php @@ -4,7 +4,17 @@ namespace Ratchet\Protocol\WebSocket\Version; class Hybi10 implements VersionInterface { const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; - public function sign($key) { + protected $_headers = array(); + + public function __construct(array $headers) { + $this->_headers = $headers; + } + + public function sign($key = null) { +if (null === $key) { + $key = $this->_headers['Sec-Websocket-Key']; +} + return base64_encode(sha1($key . static::GUID, 1)); } } \ No newline at end of file diff --git a/lib/Ratchet/Protocol/WebSocket/Version/VersionInterface.php b/lib/Ratchet/Protocol/WebSocket/Version/VersionInterface.php index 54bb3c0..53d1d1b 100644 --- a/lib/Ratchet/Protocol/WebSocket/Version/VersionInterface.php +++ b/lib/Ratchet/Protocol/WebSocket/Version/VersionInterface.php @@ -2,6 +2,11 @@ namespace Ratchet\Protocol\WebSocket\Version; interface VersionInterface { + /** + * @param array + */ + function __construct(array $headers); + /** * @param string * @return string diff --git a/lib/Ratchet/Server.php b/lib/Ratchet/Server.php index 4e760a5..1ca45d0 100644 --- a/lib/Ratchet/Server.php +++ b/lib/Ratchet/Server.php @@ -89,6 +89,10 @@ class Server implements ServerInterface { return $this->_connections; } + public function log($msg, $type = 'note') { + call_user_func(array($this->_log, $type), $msg); + } + /* * @param mixed * @param int @@ -112,6 +116,8 @@ class Server implements ServerInterface { throw new Exception; } + $this->_master->set_nonblock(); + do { try { $changed = $this->_resources; @@ -156,7 +162,7 @@ class Server implements ServerInterface { } protected function onMessage($msg, Socket $from) { - $this->_log->note('New message "' . trim($msg) . '"'); + $this->_log->note('New message "' . $msg . '"'); $this->tmpRIterator('handleMessage', $msg, $from); } diff --git a/lib/Ratchet/Socket.php b/lib/Ratchet/Socket.php index a9ca67a..ddbbe63 100644 --- a/lib/Ratchet/Socket.php +++ b/lib/Ratchet/Socket.php @@ -5,6 +5,7 @@ use Ratchet\Protocol\ProtocolInterface; /** * A wrapper for the PHP socket_ functions * @author Chris Boden + * @todo Needs to be observable, Server needs to know when an applicaiton closes a connection */ class Socket { /**