Html – WebSocket Server using latest protocol (hybi 10)

htmlphpwebsocketwebsocket

I have browsed the forums here and this was the closest question I found:

How to (de)construct data frames in WebSockets hybi 08+?

The difference is that I am unable to get a successful handshake. I am assuming that framing doesn't play a roll until AFTER the handshake is complete, is this correct?

I was about to launch a proof of concept when Chrome conveniently updated to version 14 which uses the HyBi 10 websocket protocol (https://datatracker.ietf.org/doc/html/draft-ietf-hybi-thewebsocketprotocol-10). Based on the information in the spec on the handshake (https://datatracker.ietf.org/doc/html/draft-ietf-hybi-thewebsocketprotocol-10#section-5.2.2) I have been able to successfully create a Sec-WebSocket-Accept key (success based on their example), but on the client-side the socket.onopen function never fires.

Last time I had an issue with the WebSocket protocol handshake, it was an issue with terminating the handshake with the correct bytes (or I suppose characters is more accurate?). I am using PHP for the current implementation and that has meant trying to decode Python or C# implementations, with no success so far.

Here is my client-side Javascript running in Chrome 14 (for Windows):

var socket;
socket = new WebSocket(host);
socket.onopen = function(msg){
    // process onopen
};
socket.onmessage = function(msg){ 
    // process message
};
socket.close = function(msg){
    // process close
};

And here is my server-side PHP code for the handshake:

function dohandshake($user,$buffer){
    // getheaders and calcKey are confirmed working, can provide source if desired
    list($resource,$host,$origin,$key,$version) = $this->getheaders($buffer);
    $request = "HTTP/1.1 101 Switching Protocols\r\n" .
            "Upgrade: WebSocket\r\n" .
            "Connection: Upgrade\r\n" .
            "Sec-WebSocket-Accept: " . $this->calcKey($key) . "\r\n";
    socket_write($user->socket,$request);
    $user->handshake=true;
    return true;
}

Once the client sends the initial handshake, the Javascript socket remains in the CONNECTING state indefinitely. This means onopen is never fired and so my socket stays in limbo. Any ideas on both how to debug, or even better confirm my handshake approach would be great.

Here is an apparent (I can not say whether it works for sure or not) solution in Python (https://github.com/kanaka/websockify/blob/master/websocket.py). Look for the do_handshake method.

Thanks!

Best Answer

So I solved my particular issue with the handshake, and it was quite noobish. I needed two sets of "\r\n" to close out the handshake. So to fix the handshake issue I described above (the Javascript WebSocket not going to the OPEN state) I needed to make the following change to my server-side PHP (note the \r\n\r\n at the end, doh):

function dohandshake($user,$buffer){
    // getheaders and calcKey are confirmed working, can provide source if desired
    list($resource,$host,$origin,$key,$version) = $this->getheaders($buffer);
    $request = "HTTP/1.1 101 Switching Protocols\r\n" .
        "Upgrade: WebSocket\r\n" .
        "Connection: Upgrade\r\n" .
        "Sec-WebSocket-Accept: " . $this->calcKey($key) . "\r\n\r\n";
    socket_write($user->socket,$request);
    $user->handshake=true;
    return true;
}

Also for future PHP-WebSocket enthusiasts I just use regular expressions to parse the header in getheaders and this is calcKey:

function calcKey($key){
     $CRAZY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
     $sha = sha1($key.$CRAZY,true);
     return base64_encode($sha);
}

Hope this helps someone else! Now to work on the message framing...

Related Topic