A while back I discovered JWChat – a browser-based IM client that uses only HTTP to communicate with a server – in other words very friendly to restricted environments where you are behind a firewall and you can't install software.
JWChat uses a standard binding of XMPP (aka Jabber) over HTTP – in other words it speaks HTTP to a Jabber server. Now the good thing about many Jabber servers is that they can talk to MSN, Yahoo and AIM as well as other Jabber servers. This standard is defined in XEP-0124 and is implemented directly by some Jabber servers. Unfortunately not by the Jabber server that my ISP (dreamhost ) allows me to run. But wait! I can run a rails server on dreamhost, so it was just a simple matter of writing a gateway in Ruby that implemented XEP-0124. Of course, nothing in software development is ever simple (don't believe anyone who tries to tell you otherwise).
So, apart from the task of implementing XEP-0124 in Ruby, I also have to cope with the fact that my ISP uses Apache/FastCGI to provide Rails access. The problem here is that I need to open a single persistent connection to a Jabber server for each user session, whereas FastCGI spawns multiple processes to handle individual incoming HTTP requests.
Enter DRb. DRb is Distributed Ruby. With this I can create a single Ruby server process to which all of those FastCGI processes talk. At least I could if Dreamhost allowed me to run daemon processes. But they don't. They periodically go around and kill them. Besides, who wants to have the hassle of running a daemon process? So I made it so that the first FastCGI process that needs the gateway server becomes the gateway server. To prevent race conditions, where several processes try to become the gateway at the same time, I have to obtain a lock global to all the processes. A file lock was the most obvious way to do it, so that's what I did.
Now I have a neat little system whereby the gateway process comes into being just in time. Unfortunately Apache seems to have some pretty arcane rules about when it decides to kill FastCGI processes off. So, to prevent my gateway process from being terminated I had to fork off a daemon process from the FastCGI process. Ruby 1.8 doesn't do this. Fortunately some enterprising people have worked out how to do it and allowed people to use their code. So now I have a neat little system where an XEP-0124 gateway daemon gets run as needed.
Ruby on Windows can't fork, so on Windows I fall back to just not daemonizing the gateway process. This works fine for SCGI. It would even work fine for FastCGI if you have access to the httpd.conf file and can spawn off a few static FastCGI processes.
Anyhow, my little XEP-0124 in Ruby works. There's quite a few things that need to be implemented to make it fully XEP-0124 compliant (such as SASL support, support for more than two simultaneous connections per session, packet ordering etc.) but it works between JWChat and my host's Jabber server. Its hosted over at RubyForge , and if you want to give it a try there are some instructions here. If you want to develop it further, add a comment to this post and I'll add you to the RubyForge project.
I discovered an issue with how Dreamhost shared servers are configured. It seems they only allow two dispatch.fcgi processes to be run. Each process only serves one HTTP request at a time which means that the binding mechanism defined in XEP-0124 doesn't really work since if there is more than one active Jabber session, both processes are hung up on those sessions. I had to modify the Ruby module a little to make it correctly fall back to polling. To do this you need the new version and then set REQUESTS to 0 in xmpphttpbind.rb.
BTW I also implemented support for servers that use SSL, such as GTalk.