Fishnet 4 === From jlnd@cs.washington.edu Mon Mar 8 10:51:12 2004 Date: Thu, 26 Feb 2004 21:53:55 -0800 (PST) From: Janet Davis To: cse461@cs.washington.edu Subject: [Cse461] Transport protocol interoperability You all had an opportunity to discuss interoperability for the Fishnet protocol in quiz section this morning. Here are the issues that Evan and Harsha summarized for me, and my suggestions for interoperable implementations. If you think of any more we missed, or if you strenously object to any of my suggestions, please email the list. Is an initial sequence number (ISN) of 0 OK? * It looks like nothing forbids a sequence number of 0. However, you should consider using a random ISN. What is the maximum sequence number? Do I need to worry about wraparound? * The sequence number is transmitted as a signed 32-bit integer, so the maximum sequence number is 2^16-1. Rather than handling wraparound, you might pick a relatively small ISN so that wraparound is unlikely. (It's not the most robust solution, but it's simple.) Should the ACK be the last byte received or the last byte + 1? * The choice is entirely arbitrary, but everyone must agree. The assignment says to use the next byte expected (i.e., last byte received + 1) for the acknowledgment number. Let's stick with that. If seq != expected when receiving, what do you do? * The protocol requires you to send an acknowlegment on every packet you receive. Send an ACK even if the packet that was received does not advance the acknowledgment number. If I'm not expecting the packet I receive in the state the connection is in (e.g., I get a data packet without receiving SYN, or I receive a duplicate SYN), what should I do? * If you are confused, you can always send FIN to close the connection. Should we retry SYNs? * This affects interoperability depending on what the receiver does if it gets a duplicate SYN. Let's say the receiver may respond with FIN if it gets a duplicate SYN; this allows a simpler receiver implementation. How should connection teardown work? * The assignment was very vague on this, but we do need to agree. Let's put the burden on the sender: The sender must wait until all data has been acknowledged before sending FIN. We will not require FIN to be acknowledged. (In what regard would requiring an acknowledgment of the FIN packet be a better solution?) What does it mean when the receiver sends FIN? * The receiver sends FIN only when it doesn't want to receive any more data. The sender should stop sending data immediately upon receiving a FIN, regardless of unacknowledged data. Do send and receive buffer sizes need to be the same? * Not necessarily. The advertised window helps us here. How long do we wait before inferring that the node on the other side is not going to send FIN and hence, close the connection? * This timeout should be much larger than the retransmission timeout. I have heard several people using 1 minute, which seems reasonable to me. (Incidentally, this is the maximum segment lifetime used on the Internet.) === On Tue, 2 Mar 2004, Kenneth Michelson wrote: > My fishfone takes forever to transfer a soundbite over the airwaves. It > has to transfer like 300 packets before it can form a complete sound > (these things are like 15-20K). Should we raise the packet size or just > deal with the slowness? Ken ended up answering his own question -- using 8-bit, monophonic sound at a sampling rate of 8000 Hz sounds just fine on the tinny iPAQ speakers, and results in much smaller samples. A modified soundtest.rb is attached. === On Sun, 7 Mar 2004, Andrew Ebaugh wrote: > I assume the client request should terminate with a ? The project > write-up doesn't specify this, but my server portion is so far waiting for > it in the request. Yes, the request should end with . That was a typo. > Also, is a "\n" string in Ruby equivalent to what is spelled out at ? stands for Carriage Return, Line Feed, which is "\r\n". === On Sun, 7 Mar 2004, Cameron Tom wrote: > The assignment says: > "The file "index", if it exists, contains a list of file names that the > server is willing to share" > > What is the format of this index file? Going from the previous syntax, > can I assume: > file1 > file2 > ... > fileN > ? Basically, yes. The one catch is that Unix uses only (or "\n") as its line separator, rather than , so you should also understand the following: file1 file2 ... fileN === On Sun, 7 Mar 2004, Andrew Ebaugh wrote: > Also, if nodes are to be distributing new files as they are downloaded, > shouldn't the index file maintained by either the client or the server > component? Yes, when the client component downloads a new file, it should add the file name to the index file. > Related: anyone have suggestions on getting/working with a directory listing > in Ruby? Try the Dir class. =========================================================================== Fishnet 3 --------- Given the flood of late homework, and the fact that we haven't yet passed back Fishnet 2, Fishnet 3 will now be due *Monday February 23*. You may hand it in on Friday as originally scheduled if you prefer. === * Retransmission timeouts. You do not have to implement the TCP adaptive timeout algorithm. You may use a timeout of 500 ms. * Ports. The source port can be anything, as long as you do not duplicate connection identifiers as described under connection setup/teardown. For this assignment, please listen on all destination ports. (In the next assignment, we will specify "well-known ports" for a few different applications.) * Sliding window size. It is up to you to choose a sliding window send/receive buffer size. This is the topic of discussion question (b). === > Can we assume that there is one connection per port or is there only one > connection per combination of src and dest ports? There is one connection per [src-addr, src-port, dest-addr, dest-port]. You should be able to accept more than one connection from different src addresses or ports to the same dest port. === > How do I get my single-character codes to print right away? As follows: def printc(c) print c; $stdout.flush end === > Can I use tcpdump-style output? It's a lot more informative for debugging. Here is code to support tcpdump-style output for debugging. Please use the output described in the assignment for your turnin. module Fishnet PRINT_DATA = true ## transport class # we extend it with a "tcpdump" method that summarizes a packet, for # debugging # it looks like this: # "123:11 seq:616 ACK[win:59485]" class Transport FlagTypes = { SYN=>"SYN", ACK=>"ACK", FIN=>"FIN", DATA=>nil } def tcpdump str = "#{@srcPort}:#{@destPort} seq:#{seqNo}" case @type when SYN str << " SYN" when ACK str << " ACK[win:#{@window}]" when FIN str << " FIN" when DATA str << " DATA[#{@payload.length}]" str << ": " + @payload.inspect if @payload.length > 0 and PRINT_DATA end str end end end === The source port and destination port in the transport header of your packets should always correspond to the source and destination of the packet, regardless of the direction of the "connection" that these transport packets are providing. That is to say, if I have a connection open from host A port a, to host B port b, all packets should either be: src: A srcport: a dst: B dstport: b or src: B srcport: b dst: A dstport: a === > What are the contents suppposed to be in the transport packet in field > "payload"? We are treating it like a string but when we call transport.pack > we get the following error: > > ./packet.rb:197:in `pack': no implicit conversion from string (TypeError) I ran into this same issue myself. I bet the problem is that some of the other members of Transport are strings when they ought to be integers. (You can always print them out and see.) === There seems to be some confusion about how to use the initial sequence number (probably caused by the tcpdump output on the last homework). The sender picks a random initial sequence number k, and sends SYN with seqNum=k. The receiver replies with ACK and seqNum=k+1. Now the connection is established, and from this point sequenceNumbers are in terms of bytes, starting from k+1. Another way of looking at this is to say the sender picks a sequence number and tells it to the reciever, and the reciever now says "I'm ready for byte number k+1", so that's the first byte the sender sends. === > "For the transfer pattern you should use a configurable number of fixed > sized packets, 512 bytes by default..." > > Isn't the max packet size set to 128 bytes in packet.rb? Yes, good point, it is. Note also that packet.rb includes the constant Transport::MaxPayload, which you should use (rather than 512 bytes) to determine the payload size. === A sample solution for you to try sending data to is running as nodes 0 and 1 on zuniga:8888. (You are also welcome to connect to this trawler and try sending data to each other!) === > How should the client buffer be implemented so that the application will > be able to get data from it in Fishnet 4? Are there any restrictions to > data structures, or should we abstract the buffer to a function the app > can call to get any data the buffer has? Hi Jake and Cameron, I've gotten a few questions similar to this. You will find the next assignment easier if you provide a sockets-like interface; that is, your data structures let you * create a new connection * listen for new connections on a port * write to a sending connection (a client) * read from a receiving connection (a server) * close a connection If you prefer, rather than implementing the transfer command for testing, you may implement commands to create a connection, write, read, and close. It's OK if these are not completely general (e.g., if the read command reads from the first server connection). You may also use a test pattern other than the one suggested in the assignment if you prefer. === The applications you build in the next assignment will not extend the Node class, but rather plug into node and transport classes. You will have a couple of choices: - You may use a sockets-like, synchronous interface. The code in fishnet/lib/amphibian.rb can provide this with the help of your transport code. - Or, you may write event-driven applications (in the style of fishnet), which are notified by the transport service when connections and packets arrive. === I just learned that there has been a lot of confusion about whether the Fishnet 3 assignment requires the receiver to buffer packets that are received out of order. The protocol as described does NOT require you to do this. (And we won't require it either.) You may instead discard packets that are not the next packet expected. This will hurt performance when packets arrive late, but with our sliding window protocol it has little effect when packets are actually lost. And it is much simpler to implement. If you want to implement out-of-order packet buffering, I recommend implementing the "discard" solution first, just to get something working. === On Sun, 22 Feb 2004, Matthew Burkhart wrote: > We were trying run our test cases for the turnin and we cannot get the > simulator or emulator to produce any packet loss! > We looked in the code and found that that schedulePkt(src, size, now) > method in topology.rb (which causes packet loss) is not used at all in > the emulator/trawler. Ok so the emulator can't do packet loss...? > > So we then tried the simulator it didnt work immediately, so we checked > out the code and found two issues: > lossRate = $1.to_f if opts =~ /lossRate:\s*([0-9\.]+(:?[eE]\d*)?)/ > so our topo file should use "lossRate: 0.05" instead of "loss: 0.05"? > Furthermore, the $POSTMATCH use in parseEdgeOptions($POSTMATCH) is nil > ONLY when we run simulator, but parses correctly in the trawler. > What is going on here?? What are we missing? Have you all been able to > get packet loss to work? Looks like we screwed up. Thanks for debugging; this should help Evan straighten it out. > Should we just hard code the default loss rate in simulator to 0.05? That sounds like a fine idea. === Sorry to everyone who's suffered from this. We won't deduct points for subtle bugs in your retransmission algorithm if the overall design is correct. To enable packet loss in the simulator, make the following change at line 89 of commands.rb: # lossRate = $1.to_f if opts =~ /lossRate:\s*([0-9\.]+(:?[eE]\d*)?)/ lossRate = 0.05