On 19/11/13 20:18, Ted Ross wrote:
Frase,

This looks really interesting. Can you provide any details about the WebSockets encapsulation (i.e. how WS messages and frames are used)?

Thanks,

-Ted

Hi Ted, thanks for the response. I'm not really sure what you are getting at with your question, so I'll fire a few points off in the hope that one is close to the mark.

I guess the real reason I'm not sure what you are meaning is that it's actually pretty transparent. As far as I'm aware WebSockets are transporting application layer data around in pretty much exactly the same way that TCP sockets do. All of the AMQP framing is done entirely in the compiled proton library exactly as it would be for a TCP socket transport - data winds up on a buffer and that buffer is sent out over the WebSocket or socket.

Under the hood emscripten is using binary WebSockets - there's code (in a method called createPeer() that gets called from connect()) that looks like this:

// the node ws library API is slightly different than the browser's var opts = ENVIRONMENT_IS_NODE ? {headers: {'websocket-protocol': ['binary']}} : ['binary'];
            // If node we use the ws library.
var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
            ws = new WebSocket(url, opts);
            ws.binaryType = 'arraybuffer';

This uses the Browser's WebSocket implementation (in my case FF20 at the moment) or in the case of Node.js as illustrated above is uses the "ws" WebSocket library, which has become a bit of a de-facto standard.

So I guess to answer your question as expressed above the low level WebSocket message and frame stuff would likely be as specified in http://tools.ietf.org/html/rfc6455, but it's all taken care of by the Browser or "ws" implementations. ws is Open Source and lives here https://github.com/einaros/ws so if you are interested in the implementation details, though as I say I've treated it as rather transparent.

I'd expect that if (or *sigh* when) I decide to be kind and support "legacy" browsers I'll end up doing a polyfill that mirrors the actual WebSocket API (albeit backed by a library that does long polling or whatever) - though even to allow support for Browsers that don't support binary WebSockets I'll need to contribute a patch to emscripten to base64 encode (yuk but needs must - why won't old browsers die :-))

If you are interested in the AMQP framing then as I say I don't believe that there should be any difference at all between what goes to a TCP socket and what goes to the WebSocket. If you're feeling geeky here's the transfer debug for sending the Hello World! message:

As an aside for "comedy value" on Saturday I was looking at transport.c for about two hours banging my head on my desk thinking "but it's saying #define AMQP_HEADER ("AMQP\x00\x01\x00\x00") why am I seeing 3,1,0,0 and not 0,1,0,0" before I eventually twigged that the 3 relates to SASL (read the spec Luke, read the spec :-)) - I laughed in preference to crying :-)

node send.js
Can't create control pipe: Function not implemented
ignoring setsockopt command
connect: ws://0.0.0.0:5672
websocket adding peer: 0.0.0.0:5672
websocket handle open
websocket send (41 bytes): 65,77,81,80,3,1,0,0,0,0,0,33,2,1,0,0,0,83,65,208,0,0,0,17,0,0,0,2,163,9,65,78,79,78,89,77,79,85,83,160,0 websocket read (148 bytes): 65,77,81,80,3,1,0,0,0,0,0,43,2,1,0,0,0,83,64,208,0,0,0,27,0,0,0,1,240,0,0,0,18,0,0,0,1,179,0,0,0,9,65,78,79,78,89,77,79,85,83,0,0,0,22,2,1,0,0,0,83,68,208,0,0,0,6,0,0,0,1,80,0,65,77,81,80,0,1,0,0,0,0,0,67,2,0,0,0,0,83,16,208,0,0,0,51,0,0,0,10,161,36,50,50,98,57,57,55,55,48,45,54,101,55,54,45,52,54,52,101,45,102,53,56,48,45,54,98,52,102,100,56,102,100,102,98,53,101,64,64,64,64,64,64,64,64,64 websocket send (202 bytes): 65,77,81,80,0,1,0,0,0,0,0,75,2,0,0,0,0,83,16,208,0,0,0,59,0,0,0,10,161,36,48,102,48,101,48,102,97,101,45,50,97,53,102,45,52,102,55,100,45,97,50,101,56,45,49,100,98,56,97,101,101,98,56,49,55,50,161,7,48,46,48,46,48,46,48,64,64,64,64,64,64,64,64,0,0,0,30,2,0,0,0,0,83,17,208,0,0,0,14,0,0,0,4,64,82,0,112,127,255,255,255,82,1,0,0,0,89,2,0,0,0,0,83,18,208,0,0,0,73,0,0,0,10,161,10,115,101,110,100,101,114,45,120,120,120,82,0,66,80,2,80,0,0,83,40,208,0,0,0,17,0,0,0,11,64,82,0,64,82,0,66,64,64,64,64,64,64,0,83,41,208,0,0,0,13,0,0,0,7,64,82,0,64,82,0,66,64,64,64,64,82,0 websocket read (119 bytes): 0,0,0,32,2,0,0,0,0,83,17,208,0,0,0,16,0,0,0,4,96,0,0,82,0,112,127,255,255,255,82,0,0,0,0,45,2,0,0,0,0,83,18,208,0,0,0,29,0,0,0,10,161,10,115,101,110,100,101,114,45,120,120,120,82,0,65,80,2,80,0,64,64,64,64,82,0,0,0,0,42,2,0,0,0,0,83,19,208,0,0,0,26,0,0,0,9,82,0,112,127,255,255,255,82,0,82,0,82,0,82,0,112,0,0,4,0,64,66 websocket send (121 bytes): 0,0,0,121,2,0,0,0,0,83,20,208,0,0,0,22,0,0,0,6,82,0,82,0,160,8,0,0,0,0,0,0,0,0,82,0,65,66,0,83,112,208,0,0,0,11,0,0,0,5,66,80,4,64,66,82,0,0,83,115,208,0,0,0,39,0,0,0,13,64,160,0,64,64,161,1,1,64,64,64,131,0,0,0,0,0,0,0,0,131,0,0,0,0,0,0,0,0,64,82,0,161,1,115,0,83,119,161,12,72,101,108,108,111,32,87,111,114,108,100,33



And for the receiver:

node recv.js
Can't create control pipe: Function not implemented
ignoring setsockopt command
listen: 0.0.0.0:5672
received connection from: 127.0.0.1:54644
websocket adding peer: 127.0.0.1:54644
accept
ignoring setsockopt command
websocket read (41 bytes): 65,77,81,80,3,1,0,0,0,0,0,33,2,1,0,0,0,83,65,208,0,0,0,17,0,0,0,2,163,9,65,78,79,78,89,77,79,85,83,160,0 websocket send (148 bytes): 65,77,81,80,3,1,0,0,0,0,0,43,2,1,0,0,0,83,64,208,0,0,0,27,0,0,0,1,240,0,0,0,18,0,0,0,1,179,0,0,0,9,65,78,79,78,89,77,79,85,83,0,0,0,22,2,1,0,0,0,83,68,208,0,0,0,6,0,0,0,1,80,0,65,77,81,80,0,1,0,0,0,0,0,67,2,0,0,0,0,83,16,208,0,0,0,51,0,0,0,10,161,36,50,50,98,57,57,55,55,48,45,54,101,55,54,45,52,54,52,101,45,102,53,56,48,45,54,98,52,102,100,56,102,100,102,98,53,101,64,64,64,64,64,64,64,64,64 websocket read (202 bytes): 65,77,81,80,0,1,0,0,0,0,0,75,2,0,0,0,0,83,16,208,0,0,0,59,0,0,0,10,161,36,48,102,48,101,48,102,97,101,45,50,97,53,102,45,52,102,55,100,45,97,50,101,56,45,49,100,98,56,97,101,101,98,56,49,55,50,161,7,48,46,48,46,48,46,48,64,64,64,64,64,64,64,64,0,0,0,30,2,0,0,0,0,83,17,208,0,0,0,14,0,0,0,4,64,82,0,112,127,255,255,255,82,1,0,0,0,89,2,0,0,0,0,83,18,208,0,0,0,73,0,0,0,10,161,10,115,101,110,100,101,114,45,120,120,120,82,0,66,80,2,80,0,0,83,40,208,0,0,0,17,0,0,0,11,64,82,0,64,82,0,66,64,64,64,64,64,64,0,83,41,208,0,0,0,13,0,0,0,7,64,82,0,64,82,0,66,64,64,64,64,82,0 websocket send (119 bytes): 0,0,0,32,2,0,0,0,0,83,17,208,0,0,0,16,0,0,0,4,96,0,0,82,0,112,127,255,255,255,82,0,0,0,0,45,2,0,0,0,0,83,18,208,0,0,0,29,0,0,0,10,161,10,115,101,110,100,101,114,45,120,120,120,82,0,65,80,2,80,0,64,64,64,64,82,0,0,0,0,42,2,0,0,0,0,83,19,208,0,0,0,26,0,0,0,9,82,0,112,127,255,255,255,82,0,82,0,82,0,82,0,112,0,0,4,0,64,66 websocket read (121 bytes): 0,0,0,121,2,0,0,0,0,83,20,208,0,0,0,22,0,0,0,6,82,0,82,0,160,8,0,0,0,0,0,0,0,0,82,0,65,66,0,83,112,208,0,0,0,11,0,0,0,5,66,80,4,64,66,82,0,0,83,115,208,0,0,0,39,0,0,0,13,64,160,0,64,64,161,1,1,64,64,64,131,0,0,0,0,0,0,0,0,131,0,0,0,0,0,0,0,0,64,82,0,161,1,115,0,83,119,161,12,72,101,108,108,111,32,87,111,114,108,100,33
Address: (null)
Subject: (no subject)
Content: "Hello World!"


For the case of the sender pn_send() in driver.c does a call:
    return send(sockfd, buf, len, 0);

Which in turn hits the emscripten runtime and calls send() there which eventually makes its way to the sendmsg function which ultimately does:

        // find the peer for the destination address
        var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);

............

          // send the actual data
          dest.socket.send(data);

Which retrieves the actual WebSocket instance from the pseudo file descriptor mapping and actually sends the data down it.


Hope that's covered what you were interested in?

Cheers,
Frase



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@qpid.apache.org
For additional commands, e-mail: users-h...@qpid.apache.org

Reply via email to