HyBi-10 handshake

Hackishly implemented the HyBi-10 handshake
This commit is contained in:
Chris Boden 2011-10-27 13:07:24 -04:00
parent 3af575b4e9
commit ed1a35ff74
7 changed files with 111 additions and 13 deletions

View File

@ -1,7 +1,8 @@
<?php <?php
namespace Ratchet\Protocol; namespace Ratchet\Protocol;
use Ratchet\Server; use Ratchet\Server;
use Ratchet\Server\Client; use Ratchet\Protocol\WebSocket\Client;
use Ratchet\Protocol\WebSocket\Version;
use Ratchet\Server\Message; use Ratchet\Server\Message;
use Ratchet\Socket; use Ratchet\Socket;
@ -15,22 +16,24 @@ class WebSocket implements ProtocolInterface {
protected $_server; protected $_server;
/** /**
* @type Ratchet\Protocol\WebSocket\Version\VersionInterface * @type SplObjectStorage
*/ */
protected $_version = null; protected $_lookup;
protected $_shook_hands = false; public function __construct() {
$this->_lookup = new \SplObjectStorage;
}
/** /**
* @return Array * @return Array
*/ */
public static function getDefaultConfig() { public static function getDefaultConfig() {
return Array( return array(
'domain' => AF_INET 'domain' => AF_INET
, 'type' => SOCK_STREAM , 'type' => SOCK_STREAM
, 'protocol' => SOL_TCP , 'protocol' => SOL_TCP
, 'options' => Array( , 'options' => array(
SOL_SOCKET => Array(SO_REUSEADDR => 1) SOL_SOCKET => array(SO_REUSEADDR => 1)
) )
); );
} }
@ -38,7 +41,7 @@ class WebSocket implements ProtocolInterface {
/** /**
* @return string * @return string
*/ */
function getName() { public function getName() {
return 'WebSocket'; return 'WebSocket';
} }
@ -46,12 +49,49 @@ class WebSocket implements ProtocolInterface {
$this->_server = $server; $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');
} }
} }

View File

@ -0,0 +1,31 @@
<?php
namespace Ratchet\Protocol\WebSocket;
use Ratchet\Protocol\WebSocket\Version\VersionInterface;
class Client {
/**
* @type Ratchet\Protocol\WebSocket\Version\VersionInterface
*/
protected $_version = null;
/**
* @type bool
*/
protected $_hands_shook = false;
public function doHandshake(VersionInterface $version) {
$key = $version->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;
}
}

View File

@ -2,6 +2,11 @@
namespace Ratchet\Protocol\WebSocket\Version; namespace Ratchet\Protocol\WebSocket\Version;
class Hixie76 implements VersionInterface { class Hixie76 implements VersionInterface {
protected $_headers = array();
public function __construct(array $headers) {
}
/** /**
* @param Headers * @param Headers
* @return string * @return string

View File

@ -4,7 +4,17 @@ namespace Ratchet\Protocol\WebSocket\Version;
class Hybi10 implements VersionInterface { class Hybi10 implements VersionInterface {
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; 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)); return base64_encode(sha1($key . static::GUID, 1));
} }
} }

View File

@ -2,6 +2,11 @@
namespace Ratchet\Protocol\WebSocket\Version; namespace Ratchet\Protocol\WebSocket\Version;
interface VersionInterface { interface VersionInterface {
/**
* @param array
*/
function __construct(array $headers);
/** /**
* @param string * @param string
* @return string * @return string

View File

@ -89,6 +89,10 @@ class Server implements ServerInterface {
return $this->_connections; return $this->_connections;
} }
public function log($msg, $type = 'note') {
call_user_func(array($this->_log, $type), $msg);
}
/* /*
* @param mixed * @param mixed
* @param int * @param int
@ -112,6 +116,8 @@ class Server implements ServerInterface {
throw new Exception; throw new Exception;
} }
$this->_master->set_nonblock();
do { do {
try { try {
$changed = $this->_resources; $changed = $this->_resources;
@ -156,7 +162,7 @@ class Server implements ServerInterface {
} }
protected function onMessage($msg, Socket $from) { protected function onMessage($msg, Socket $from) {
$this->_log->note('New message "' . trim($msg) . '"'); $this->_log->note('New message "' . $msg . '"');
$this->tmpRIterator('handleMessage', $msg, $from); $this->tmpRIterator('handleMessage', $msg, $from);
} }

View File

@ -5,6 +5,7 @@ use Ratchet\Protocol\ProtocolInterface;
/** /**
* A wrapper for the PHP socket_ functions * A wrapper for the PHP socket_ functions
* @author Chris Boden <shout at chrisboden dot ca> * @author Chris Boden <shout at chrisboden dot ca>
* @todo Needs to be observable, Server needs to know when an applicaiton closes a connection
*/ */
class Socket { class Socket {
/** /**