Signs of Triviality

Opinions, mostly my own, on the importance of being and other things.
[homepage] [index] [] [@jschauma] [RSS]

No tratheroute for you!

Seinfeld's Soup NaziIt seemed like another odd instance of Blue Car Syndrome when on October 23rd, John McCarthy died. Having just a few weeks ago decided to (re (learn lisp)), his name all of a sudden was everywhere (well... for sufficiently geeky values of "everywhere", anyway) -- just when I had actually started to write my first lisp program in a long, long time.

After my previous adventures in Go-land, which went entirely (predictably) smoothly and where everything felt comfortable, I went along and set myself up for Lisp and installed CMUCL on my Mac OS X laptop. Re-acquainting myself with some of the basics, I quickly find out that on this platform tracing recursive functions may not show the recursive calls, so I move on to my preferred OS, where I happen to install CLISP.

And that's already the first weird thing: Lisp comes in a number of dialects (Common Lisp, Scheme, Clojure, ...), but even Common Lisp has a surprisingly large number of implementations. Sure, there are, of course various C compilers as well, but the difference between the implementations is not quite as significant. And then contrast this concept with the world of Python, PHP, Perl etc., where you really only have one single interpretation of the language. For Common Lisp, there are well over ten, uhm, "common" implementations!

These different implementations require you to write certain parts of your code in an oddly convoluted ifdef-kind-of way. Consider this example of processing the given command-line arguments:

(let ((args
       #+clisp ext:*args*
       #+sbcl sb-ext:*posix-argv*
       #+clozure (ccl::command-line-arguments)
       #+gcl si:*command-args*
       #+ecl (loop for i from 0 below (si:argc) collect (si:argv i))
       #+cmu extensions:*command-line-strings*
       #+allegro (sys:command-line-arguments)
       #+lispworks sys:*line-arguments-list*

Dijkstra would not like Quick And
DirtyAlright, so for the time being, I'm going to pretend that all the world's a clisp, so I can just silently assume ext:*args*. Now where did my getopt(3) equivalent go? Well, there's this, but I don't want to start my first program by pulling in and requiring external dependencies. So I start to spend a silly amount of time in writing my own very crude command-line option parsing routine.

Somewhat surprisingly, I am not getting frustrated. I repeatedly have to redo even simple statements as I am figuring out the more lispy way of doing things, and while I have a lot of "Wait, what? Why? Huh?" moments, I think it tickles slightly more dormant parts of my brain, so in the end I actually end up enjoying the experience. Oh, right, it's called learning, and that actually is fun! :-)

Now most of the Lisp tutorials out there are rather academically focused, with exercises illustrating tail recursion (factorial and fibonacci are very popular), but I'm more interested in using Lisp for something "practical", so I decided to write traceroute(8).

After wrangling the command-line options into a hash, I'm all ready to start the actual functionality of the program. For that, I need to open two sockets, so let's get ourselves one of these babies (UDP, to send my packets out on)

(setq send-socket (rawsock:socket :inet :dgram "udp"))

and one of these (to receive the ICMP TIME_EXCEEDED (and, ultimately, PORT_UNREACHABLE) messages).
(setq recv-socket (rawsock:socket :inet :raw 1))

Next up, we want to set the TTL on the outgoing packet to increasing values, starting with 1. Hmmm... how do we do that? (setf (rawsock:socket-option socket name &key :level) value) looks promising, what with it claiming to use setsockopt(2), but unfortunately it turns out you can only set socket-level options, not protocol-specific options. The same is true about (socket:socket-options socket-server &rest {option}*) as well as about usocket or (SBCL specific) sb-bsd-sockets.

Learning is FunIn other words, I can't seem to find a socket module that actually supports setting protocol-specific socket options at all. Which kind of puts a downer on the whole traceroute(8) business, since I can't set the TTL. However, again, oddly, I'm not as frustrated as you'd think. I actually enjoyed figuring out how to do things in Lisp, especially because it let me know how much more I have to learn. I'll just write something else...

[toggle code visibility]

October 28, 2011

[Migration is hard...] [index] [Parental Math]