Schmolester: a Simple Peer-to-Peer Program in Guile Scheme

0. Menu

1. Introduction

I wrote a simple peer-to-peer (P2P) program in Guile dialect of Scheme. It works for me with GNU Guile-1.6.6 on Slackware 9.1 on i386. The program is not intended for serious use, but, instead is meant as a minimal example. In truth, it is probably a huge security hole.

I was motivated to write it based on a discussion on Slashdot about a guy named Ed Felten that had written a P2P client called TinyP2P in a few lines of Python. Of course, a Perl hacker can always out-do any Python hacker in terms of brevity, so Matthew Skala wrote P2P program called Mole-Ster in even fewer lines of Perl. Both programs are nearly unintelligible in their brevity, but, they are both mightily clever little bits of code.

My code is almost a direct port of Mole-Ster v0.0.2 into Guile, so I've called it Schmole-Ster, and it appears to be compatible with the Perl version 0.0.2.

2. Usage

To use it, cd to the directory containing the files to be shared and type schmolester password 100.100.100.100:8080 200:200:200:200:8080, replacing password with the alphanumeric password for your P2P network, 100.100.100.100:8080 with the local IP and the port on which Schmolester should run, and 200.200.200.200:8080 with the IP and port of another peer. If there are no other peers yet, just put your own IP and port again.

If you want, you can also add one or more Schmolester commands to the command line. The commands are as follows.

i/
I am here: announce to your peers that you are a peer willing to accept requests.
h/
Help me find peers: merge the peers list from your peers into your list of peers. This can be used repeatedly to recursively expand your list of peers.
g<filename>/
Get file: request that the peers send you a file named filename.

The program will run your commands from the command line first, and then it will change to server mode, awaiting commands from other peers.

Since the socket will only hold a limited number of simultaneous connections, you can only run a few commands from the command line before the information you receive from the peers clogs your socket.

3. Lessons Learned

I'm not much of a Scheme programmer. I'm really a C programmer, which is probably obvious to any Scheme guy that reads this code. So there are probably dozens of ways that I've made this code more complicated than it has to be.

At first pass, I though I'd try to port TinyP2P, but, that required an XMLRPC library and server. According to the search engines, there was an XMLRPC library for Guile at one time, but, it seems to have vanished.

XMLRPC is a simple enough protocol. I wrote my own XMLRPC parser based on Guile-lib's version of SSAX/SXML, but when it came to implementing it, I found that the pure-Guile webserver doesn't do POST. For a second, I thought I might continue by making it a CGI, or by putting it into Serveez, but, instead, I gave up.

So then I moved to Mole-Ster, which has its own message passing structure based on straight TCP. That port went fairly easily except for the following hiccoughs:

  1. The regular expressions in Perl and Guile are different enough to disallow a direct cut-and-paste. Guile regular expressions are greedier. And there is a difference in how "$" is interpreted for a binary string. Anyway, Perl seems better behaved with binary strings. I'm not sure if that is a good thing or a bad thing.
  2. Perl has these neat commands to read everyting from a file to a string, or everything from a port to a string. Guile is more modest in that respect. (Or maybe they are hiding out in some library that I don't understand.) I can understand why this was prudent back in low-memory days, but, even on my crappy machine, reading a whole mp3 or book into memory is doable. I got some of what I needed from the tireless Thien-Thi Nguyen in the form of a script called (slurp), which he also distributes as part of TTN Guile-1.4.1.x. (I never was sure of the complete list of differences between TTN's Guile and the offical GNU Guile, but, to the untrained eye, TTN's seems to be slightly more focussed on scripting.)
  3. Guile really ought to have a higher-level regular expression operator that dumps everything that matches into a list. The command match:substring is a lot of characters to type. Being a C guy, I'd really like to replace match:substring and list-ref with [], but, I guess then it wouldn't be Lisp-y.

Note that I am aware of getopt for Guile, but, I was trying to match functionality with Mole-Ster, which is why I left it out.


Last updated: Dec 30, 2004