HUMP Programming Project

This program is to implement the HUMP (WUMP with Handoff) client in java (or C#). Those registered for 343 are to do this with window size 1; those registered for 443 should implement a more-or-less arbitrary window size [you can choose a fixed window size at compile time]. Here is an overview of the three WUMP protocols (BUMP, HUMP, and CHUMP).

For the Java version, the starter files are below. Changes should only be made to the wclient.java file.

The HUMP option is the best way to handle NAT firewalls, which is why we're doing it.

I have old C# versions of the above files, but I would need to update them to supporting HUMP. But let me know if this is an issue for you..

Your assignment is to do the following, by modifying and extending the wclient.java outline file:

  1. Implement the basic transfer:
  2. These two (or 2.5) steps should mean that the vanilla transfer works (if it still does not, try running the program on campus and using the LUC Wi-Fi network).
  3. Add all appropriate packet sanity checks: timeouts, host/port, size, opcode, and block number
  4. Generate output. The transferred file is to be written to System.out. A status message about every packet (listing size and block number) is to be written to System.err. Do not confuse these!
  5. Terminate after a packet of size less than 512 is received
  6. Implement an appropriate "dallying" strategy
  7. send an ERROR packet if it receives a packet from the wrong port. The appropriate ERRCODE in this case is EBADPORT.
  8. If required, implement support for window sizes > 1.

For BUMP, in which the server answers from a previously unseen port, it is helpful to view the description in terms of the state diagram. We will use the states UNLATCHED, ESTABLISHED and DALLY used to describe TFTP in intronetworks.cs.luc.edu/current/html/udp.html#tftp-states.

UNLATCHED   
    Transition to ESTABLISHED on receipt of a valid Data[1] packet (correct source IP address, etc)
    Save the source port as latchport

ESTABLISHED
    At any point we are expecting block expected_block
    If we receive a valid full-sized Data[N] packet with N==expected_block, increment expected_block.
    The source port must match latchport.
    If we receive a valid Data[N] with N==expected_block and with size < 512 bytes, transition to DALLY

DALLY
    If we receive a valid Data[N] from the correct port, with N == expected_block, resend the last ACK
    Exit this state after sufficient elapsed time

For HUMP, there is no clear UNLATCHED state where you're waiting for a packet from a port that is not known. However, we might call everything before the client sends ACK[0] the UNCONNECTED state, and everything following (until the end of the file) the CONNECTED state.

An outline of the program main loop, with notes, is available here

. I recommend that you implement this in phases, as follows.
  1. Implement the steps above under "basic transfer". These are also discussed below. This will mean that the vanilla transfer completes.
  2. Add the end-of-file (size < 512) check
  3. Add sanity checks, for (in order) host/port, packet size, protocol, opcode, and block number.
  4. Handle timeouts, by retransmitting the most recently sent packet when the elapsed time exceeds a certain amount (2 seconds?). The packet resent will always be ackDG. Use the send_time variable to determine how long the elapsed time has been. Note that the response to an InterruptedIOException, a "true" timeout, will simply be to continue the loop again.
  5. Add support for an dallying and error packets. After the client has received the file, dallying means to wait something like two timeout intervals (or more) to see if the final data packet is retransmitted. If it is, it means that the final ACK was lost. The dally period gives the client an opportunity to resend the final ACK. Error packets are to be sent to any sender of an apparent data packet that comes from the wrong port.

You can test your program by contacting the server, ulam.cs.luc.edu, and requesting files. If you contact on port 4715, you get a response from a new port (the standard behavior). This doesn't go through NAT firewalls, so if you contact ulam2 on port 4716 you get a response from the same port. No matter what file you ask for, the file you get is always the same. By asking port 4715 for the following names, you get the indicated behavior:

vanilla       Normal transfer

dupdata2    DATA[2] is sent twice

losedata2    DATA[2] is lost on initial send, until you resend ACK[1]

marspacket   A packet from the wrong port (a "martian" port) arrives

badopcode   A packet arrives with an incorrect opcode

nofile        You get an error packet with a NO FILE error code.

lose         Lose everything after the first windowful (min 3). It will be retransmitted when you retransmit the previous ACK.
spray       Constant barrage of data[1]. Implies LOSE too. In this case, no timeout events will occur; you must check for elapsed time.

delay       Delays sending packet 1, prompting a duplicate REQ and thus results in multiple server instances on multiple ports.

reorder    Sends the first windowful in the wrong order.


The Basic Transfer

In order to get the basic vanilla transfer working, there are three things you absolutely need to do, as outlined above:

The first steps are to fix the ACK port, by appropriate placement (two places!) of something like

ackDG.setPort(newport);

You can put this in with the other ackDG settings. At this point, in the SERVERPORT case you should now get Data[1] and Data[2]. Because your repeated ACK[1]'s are now going to the correct port, you should get multiple Data[2]'s, because each time you send ACK[1] the server will respond with Data[2]. This behavior is quite similar, overall, to that of the SAMEPORT setting without the above fix.

(If you're using the SAMEPORT case because you're at home and you have a NAT router, that's fine, but you should still make the above fix anyway, and then come in to Loyola to verify that the SERVERPORT case works properly. Having the SERVERPORT case work is a requirement.)

The second step is to increment expected_block, so that the arrival of Data[2] results in ACK[2] rather than ACK[1]. This is done with

expected_block++;

You can put this anywhere after the "// send ACK" code block inside the main while loop.

At this point you should get the entire file (11 blocks), with timeouts at the end because you are not properly handling the end-of-transmission case (last block has < 512 bytes of data). Because repeated ACK[11]'s don't trigger any new transmissions at the server side (why?), you won't get multiple copies of the last packet.

In general, you should verify that the arriving block number matches expected_block, as part of other sanity checks, before incrementing the latter. But you can worry about that later.

The next steps are to implement the sanity checks. The most important are to check the incoming port and also the packet's block number (to see that it matches expected_block), but you should also check the packet's IP address and size and opcode (watch the order!).

Extra-Credit Options

Here are a few options for earning extra credit. In order to receive extra credit, your project must be submitted by the due date. You must also make it clear, near the top of your wclient.java file, that you are submitting an extra-credit option. (I may add to this list if I can think of others.)

1. Implement sliding windows. A simple implementation is outlined in the Sliding Windows chapter of my book.

2. Implement adaptive timeout. That is, measure the RTT of each packet, and create a running average RTTmean, and then set the timeout interval to, say, 2*RTTmean. You should probably set a minimum timeout of, say, 500 ms.

If you're interested in this option, let me know and I'll create a larger file to use for testing.