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