CS 43 Lab 6: Fast Reliable Transport

Due: Thursday, November 30, 11:59 PM


Handy references:


Lab Audio

For this lab, you'll be continuing your development of a reliable data transfer protocol over an unreliable (simulated) link, only this time, your transfer rate should improve significantly! Your submission will still be in the form of a library that mimics the type of functionality that you would expect to get from an OS's transport-layer implementation.

You may implement either a go-back-N or selective repeat style of protocol.

Requirements

  1. You must use C to implement your library code, and the underlying transport that it uses to transfer messages must be UDP. TCP would give you reliability, which would obviously defeat the purpose...

  2. Your protocol should provide as much performance as network conditions will reasonably allow. If links have free space in their queues, your protocol should attempt to take advantage of that. If it overflows the queues, it should back off. You should mimic TCP's AIMD congestion control behavior. You may assume that the window size will never need to go above WINDOW_SIZE_CAP. A good default value of WINDOW_SIZE_CAP is 2000, but your code should still work if it's lowered. I might change this value when I'm testing, so make sure that you always refer to it via the #defined macro rather than hard-coding a number! Please record the maximum window size you use over the course of a run and make that value available via a function named my_max_window that has the following prototype:
    int my_max_window(int sock);

  3. Your protocol should provide in-order delivery. That is, the receiver should receive packets in the same order that the sender sends them, even if something occurs (e.g., losses) that causes a later-sent packet to arrive before an earlier-sent one.

  4. Because you're pipelining multiple packets, you need to keep track of all the outstanding data that needs to be sent and send up to an entire window at once. This means there is no longer a 1:1 correspondence between my_send() and send(). There are two general architectures you might use to account for this difference. You may use either approach:

    • You may code my_send() to store packets in your window in addition to sending them. The number of packets its willing to store at any given time will depend on your current window size. If the user ever calls my_send when the window is full, it should wait for free window space to open up (receiving an ACK just, just like your implementation of my_send() in lab 5).

    • You may use additional threads (at most two: one for sending, one for receiving), which are responsible for doing the sending, receiving, acking, timeouts, and window sizing. In this model, when the user calls my_send(), it adds the new data to a shared location that the sending thread will deliver later, and my_recv checks to see if there is any buffered data to return up to the user. This is the more "realistic" option, but is also more challenging because it requires thread synchronization due to the shared buffers.

    In either case, when the user calls my_close(), you need to ensure that all of the outstanding data is delivered before you initiate the shutdown sequence.

  5. The example code includes a test application that sits above your library and uses it to transfer a file. You may edit the test application for your own testing, but when grading, I will use the default version, so do not rely on changes to these files for correct operation. Your library (lab6.h and lab6.c) should allow any application that's built on top of it to achieve reliable communication. When transferring files with your library, you should get byte-for-byte identical copies. Use diff, md5sum, etc. to veryify that everything is transferred properly.

  6. As a part of your implementation of reliability, you'll need to perform RTT estimation to determine how you should set timeout values. You should use an EWMA-based mechanism like TCP does. The library function my_rtt() should always return your library's current estimate of the RTT. Normally you wouldn't export such information up to the application/user, but I'll use this to check your RTT calculation.

  7. Your implementation should cleanly shut down connections on both ends, even if packets get lost. You do NOT need to implement the TCP behavior that allows each side to shutdown independently, but in my_close(), you may want to wait for some time, to make sure the last ACK didn't get lost (leaving one end hanging).

Environment

For this lab, we'll be using the same mininet emulation software that we used in lab 5, with slightly different parameters. Refer to the lab 5 environment section for details about creating a VM. To test pipelining, you'll need buffer sizes that are larger than two packets. When you run mininet, test with a variety of max_queue_size parameter values. You should see the performance increase as the queue size increases, up to a certain point of diminishing returns. A larger queue means you're able to support more packets in flight at once.

Grading Rubric

This assignment is worth five points.

Tips

If you have any questions about the lab requirements or specification, please post on Piazza.

Submitting

Please remove any debugging output prior to submitting.

Please do not submit output file(s) that you used in testing.

To submit your code, simply commit your changes locally using git add and git commit. Then run git push while in your lab directory.