Curious Perversions in Software Engineering
Posted: Sun, 14 May 2006 | permalink | No comments
I've been ill with flu the last few days, so I've been doing very little other than sitting huddled in my recliner, with a large, warm blanket over me, and my hot water bottle (AKA the laptop) to work on. As a result, I've been doing a fair amount of random coding, and I've come away with a larger-than-average amount of... weird shit. It maybe the flu, the strong drugs I've been taking to keep the symptoms under control, or maybe just the phase of the moon, but I haven't coded up this much madness in quite a while. Let me take you through them.
I've been writing some software which has to talk to an XML-RPC server. Not so weird. However, because the system lacks any inherent security, the (strongly) preferred method of communicating with this server is via a Unix socket. That's right, I'm doing XML-RPC over HTTP over... a Unix socket.
That, you may think, is weird. Well, it is, but it isn't the curious perversion in and of itself -- for a start, I didn't write that monster, and I'm only blowing my own trumpet in this article.
No, the perversity is in how I wrote *my* software to deal with it. See, I'm using Ruby for this software, and the standard Ruby XML-RPC client uses the built-in Net::HTTP library that comes with Ruby (which is a killer little HTTP library, BTW). Because the authors of Net::HTTP were lacking in imagination (or crack pipes) they didn't think to include the native ability to talk to Unix sockets. I mean, really -- isn't that the most important feature in a HTTP library?
I think we all know the answer to that.
Anyway, despite the lack of forward planning (and crack pipes) on the part of the Net::HTTP authors, I needed to get it to talk to a Unix socket. I could have done the long-winded thing and spend a pile of time putting in handling of pipe:// (crack or otherwise) URLs, but then I would have also had to add support for it to the XML-RPC client library (which did URL validation before passing it on -- good for it). And really, I don't think I could have handled the guffaws of laughter when I attempted to submit the patch upstream.
Instead, I put Ruby to it's perfectly-suited use. I simply created the XML-RPC client object (which created the Net::HTTP object internally), then inserted my gloved finger and replaced the default TCP socket object in the Net::HTTP object with a specially crafted Unix socket object pointing to the correct place.
"Dear god almighty!" I hear the practitioners of good software engineering practice exclaim. "Doesn't Ruby have protection against such atrocities?" Why, yes, it does. All of the objects I had to play with are private instance variables of their parents, and I can't get access to them normally. However, classes in Ruby are never closed, so I just reopened them and added accessor methods (which, in Ruby, is as simple as attr_accessor :http) so I could do my nasty little thing.
I'm quite happy to take the heat for doing what I did. It breaks encapsulation, and makes everything that little bit more complex. But, on the other hand, it let me get the job done -- the language gives you full protection until you say "may I?" and then it gets out of your way. Personally, I reckon that's a nice tradeoff between C-style full control (where even the best programmers blow their foot off on a regular basis) and B&D languages where you'll never shoot yourself in the foot, but instead you'll gnaw your leg off in frustration.
I'm doing a bunch of interesting things with the Xen hypervisor for work. Of course, you need to have a way to test all this stuff, and despite a number of hints, work still hasn't gotten me that fully-kitted out dual-core Opteron that I want to test (and transcode all my video <grin>) on that I always wanted. So, instead I've installed Linux in a qemu image, and then put Xen on that.
Surprisingly, it's worked really well -- I've got Xen running quite happily in the virtual machine, and I can create and run Xen domUs (the guest VMs) in the usual fashion.
Now all I need to do is install UML in a Xen domU, and then run some vservers inside that UML, and I'll have the full collection...
Post a comment
All comments are held for moderation; markdown formatting accepted.