I have an example of using the background module. I think it is compatible with the 4.5.1 patch. The main difference is that my version of the C code is a module with additional core API added to nsd. The Tcl code should work the same.
Here is the link (the init.tcl shows how to use the thread package): http://junom.com/gitweb/gitweb.perl?p=aolserver.git;a=tree;f=aolserver/nsbgwrite;hb=HEAD I'll look at the patch. It seems useful even for more than the current issue. Also, it might be possible to use the new registered filter point: prequeue to completely avoid using a conn thread. tom jackson On Mon, Nov 1, 2010 at 3:51 PM, Jeff Rogers <[email protected]> wrote: > It looks like my previous answer was, at best, partially right. It looks > lke [ns_conn channel] does in fact give you a read/write channel. The > effect of the missing content-length header is to discard any data that was > read past the headers. Attached is a patch (readahead.patch) to change > that behavior. The patch does 2 things: one, if the request includes > 'upgrade' in the connection header, it doesn't read past the header (and > doesn't throw away what it has read). Two, when [ns_conn channel] is > called, it will insert into the channel buffer any data that was already > read (and not processed) on the socket. Combined, it means that on an > upgrade connection you can get the entire body, even if there was no > content-length header sent. > > Also attached is a tcl file (index.tcl) that looks for an upgrade header, > and when it gets one it forks a background tcl thread that echoes everything > read back to the sender. Every new request will get a new thread. It also > probably needs some tweaking to get a second request to work at all (since > it's using shared channels to give the socket to the background thread). > > Importantly, this design of thread-per-connection is not scalable - your > server will fall down and start crying once you start up a few dozen > threads. (perhaps more; a really rough guess is that each tcl thread > consumes 2M of memory before doing anything). What you really want to do is > to transfer each new websocket to a single existing background thread, but > I'm not sure how to send stuff into another thread's event loop using the > aolserver thread tools. The standard tcl thread package is more powerful > (with thread::send and thread::wait) but I don't know if those play nice > inside AOLserver. > > -J > > > > wiwo wrote: >> >> Hi! >> >> I just tried the following: >> >> I've been telneting to our server and was feeding it this request: >> >> GET /test/ns_chan HTTP/1.1 >> Host: www.dcon.at >> Connection: Upgrade >> Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 >> Sec-WebSocket-Protocol: sample >> Content-Length: 8 >> Upgrade: WebSocket >> Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5 >> Origin: http://example.com >> >> ^n:ds[4U >> >> Notice the "Content-Length" header. As Jeff told me, I've now been >> able to output the 8 byte "body" of the request. >> >> Then I was creating an ns_chan with: >> >> set ch [ns_conn channel] >> ns_chan create $ch $chan_name >> >> and getting it back with: >> set ch [ns_chan get $chan_name] >> >> The I tried to write my WebSocket server handshake with: >> >> puts $ch " >> HTTP/1.1 101 WebSocket Protocol Handshake >> Upgrade: WebSocket >> Connection: Upgrade >> Sec-WebSocket-Origin: http://[util::host] >> Sec-WebSocket-Location: ws://[util::host]/[ns_conn url] >> Sec-WebSocket-Protocol: sample >> >> $ret >> " >> >> which showed up in the telnet client. >> >> Then I tried to read again >> >> set str [read $x 10] >> ns_log notice $str >> >> and typed 10 characters in the telnet client which showed up in the >> log. >> >> So far so good! I could now write my own proposal for changing the >> WebSocket Client and make Google and Apple change their >> implementations of the protocol. Unfortunately my relationship with >> Steve and Larry cooled down the last few months, so this could take a >> while :-) >> >> Or I could get my hands dirty and mess around with the code in >> driver.c. >> >> As far as I can see, the crucial code is in >> static ReadErr SockReadLine(Driver *drvPtr, Ns_Sock *sock, Conn >> *connPtr) >> somewhere at line 1878 where the content length is read. I could >> simply check for the "Upgrade: WebSocket" header and set the length to >> the magic number of 8. >> >> Of course I have no idea when I'm talking about AOLserver C code, but >> maybe someone with a clue can give me his/her thoughts here. >> >> wiwo >> >> >>> I'm pretty sure it's not possible to implement websockets in AOLserver >>> without some C-level work, and if you could you wouldn't want to. >>> >>> You can't, because the driver reads the entire request, including >>> content, before handing it off to the connection thread. And it only >>> reads past the headers if there is a 'Content-length' header. (You can >>> hook into the content-reading with a read filter, but that won't help >>> because with no content-length it won't ever try to read it). >>> >>> You wouldn't want to, because you would attach a conn thread to a single >>> persistent websocket, which would severely limit how many you could >>> handle. Doing it as a background tcl thread would be little better, >>> because you'd still need a thread per connection. Handling all >>> websockets with a single background thread using tcl event handling >>> would work, if you could get read/write handles to the sockets (which >>> currently you can't - I think the background delivery patch only creates >>> a writable channel). >>> >>> So what else can you do? >>> >>> For starters, you could check the current state of naviserver - I'm not >>> up to date on what has changed there lately, but a r/w version of >>> 'ns_conn channel' might have been implemented. >>> >>> Otherwise, you need to get your hands dirty in the C code and implement >>> 'Upgrade' handling. If you do take this approach, I'd suggest >>> implementing just enough logic to transfer control elsewhere - that is, >>> in the driver, don't try to handle websockets, rather set it up to >>> recognize the upgrade protocol ("Connection: upgrade" and "Upgrade: >>> something" headers) and call a registered procedure and forget about the >>> connection (leaving it to the registered proc to actually do anything >>> with it). >>> >>> -J >>> >>> -- >>> AOLserver -http://www.aolserver.com/ >>> >>> To Remove yourself from this list, simply send an email to >>> <[email protected]> with the >>> body of "SIGNOFF AOLSERVER" in the email message. You can leave the >>> Subject: field of your email blank. >> >> >> -- >> AOLserver - http://www.aolserver.com/ >> >> To Remove yourself from this list, simply send an email to >> <[email protected]> with the >> body of "SIGNOFF AOLSERVER" in the email message. You can leave the >> Subject: field of your email blank. > > > > -- > AOLserver - http://www.aolserver.com/ > > To Remove yourself from this list, simply send an email to > <[email protected]> with the > body of "SIGNOFF AOLSERVER" in the email message. You can leave the Subject: > field of your email blank. > -- AOLserver - http://www.aolserver.com/ To Remove yourself from this list, simply send an email to <[email protected]> with the body of "SIGNOFF AOLSERVER" in the email message. You can leave the Subject: field of your email blank.
