IMPORTANT UPDATE, re: connection string. READ NOW! Q: The Gnutella spec says the handshake string should be "GNUTELLA CONNECT/0.4/n/n" but this dopesn't seem to work. A: No, it doesn't. Frankly, this is my fault (Stefan). I developed this assignment with an earlier version of Mutella which had trouble running on ieng9 and pisa, so I updated to the latest version. What I failed to realize is that the newer version of mutella does not correctly support the 0.4 handshake. Consequently, to get the correct behavior you MUST use the GNUTELLA v0.6 handshake (documented in http://rfc-gnutella.sourceforge.net/src/rfc-0_6-draft.html). Here's what this means for you: 1) The client must send: GNUTELLA CONNECT/0.6\r\n\r\n 2) The server will send back GNUTELLA/0.6 200 OK (followed by a bunch of crap... read it all and throw it away) 3) The client THEN send back: GNUTELLA/0.6 200 OK\r\n\r\n It is this last step which does not exist in v0.4 of Gnutella, but is REQUIRED in v0.6. I'm skeptical about fixing the mutella server without breaking yet more so consider the assignment changed to require the v0.6 handshake. In general, assume the server will be using the v0.6 version of the protocol -- but you are only responsible for the functionality as defined in the assignment. My apologies for the screwup and we'll try to be lenient in grading in consideration of this. As a consolation, I'll award 45% of the possible 50% for the sending/receiving queries functionality even if you only parse a single entry in each QueryHit message ((i.e. don't kill yourself parsing extended headers, etc... these until you get everything else working). Q: I can't connect to the server. A: The server has been configured to only accept connections from UCSD subnets (132.239.z.y and 128.54.x.y). Q: Is there any reason I can't declare a struct for the Gnutella message header? A: In principal no. However, there are some tricky details because you need to precisely emulate the Gnutella "on-the-wire" protocol. the key problem is that the gnutella header is 23 bytes long and structures are not packed to byte boundaries by default (rather they are aligned to the natural boundaries of each type.. ints to 32bit boundaries, etc) If you want to use a struct here, you're going to need to learn about the "__attribute__ pack" directive or the "#pragma pack(1)" directive which can tell the compiler to pack a structure on byte boundaries. The alternative is to just use a character array. Q: Is there some sample server code I can play with to test my client. Almost all Gnutell servents are based on the Gnucleus code base. The servent we're been using, mutella (http://mutella.sourceforge.net/), is no exception. You are welcome to look at this code. You may not copy it (although this would be a bad idea for you anyway since its pretty ugly and overkill for this project). I've put a binary version of the mutella server compiled for Solaris on ieng9 in ~cs123b/cs123mutella and I've put a copy of the source at ~cs123b/mutella-0.4.3 (note that these versions have been hacked to compile on solaris and have the aforementioned UCSD hacks embedded). Note that the server will create a directory ~/.mutella the first time it is run and after exiting will create a file mutellarc there. You should edit the "ForceUltrapeerMode" entry and set it to true so you'll be able to make queries from your client to your private mutella server. FOLLOWUP: Walter has moved these to /home/solaris/ieng9/cs123b/public Q: I read that Gnutella's datatypes are little-endian. What does that mean and how does it affect me? The bytes making up integers and floating point numbers can be stored in different manners and didfferent processors use different schemes. Big-endian means that the most significant values in a sequence are stored at the lowest storage address. In a little-endian system system the oppose is true. For example (from Webopedia) consider the number 1025 stored in a 4-byte integer. Here is the binary representation: 00000000 00000000 00000100 00000001 and here are the two different address layouts Address Big-Endian Rep Little-Endian Rep 00 00000000 00000001 01 00000000 00000100 02 00000100 00000000 03 00000001 00000000 Generally Intel processors are little-endian wrt to integers while Sun's processors are big-endian. This is where the problem comes in. Guntella uses a little-endian order for its "on-the-wire" format, but the machines you are using are Sun SPARC machines (big-endian). Consequently, you need to convert your integers (types short, int or long) from little-endian format as you read them from a packet buffer and convert them to little-endian format as you create a packet to be sent. I've made a set of functions available to do this in http://www.cs.ucsd.edu/classes/sp04/cse123b/endian.c (taken from the postgres project), but you're welcome to use your own. Note that IP addresses are the one exception in Gnutellas protocol. They are stored in big-endian format (i.e. you won't need to change them on the SPARC, but its good practice to use the htonl and ntohl macros to stay portable) Q: Other resources I should read? A: Sure, the draft spec of the 0.6 version of the Gnutella protocol can be found at http://rfc-gnutella.sourceforge.net/src/rfc-0_6-draft.html. This document can be useful even though we're only implementing a portion of the 0.4 protocol subset. Why? Its better written than the original 0.4 spec and since most servers implement 0.6 it may help explain the extraneous messages that you receive.