Your assignment is to do the following, by modifying and extending the wclient outline file:
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
You can test your program by contacting the server, ulam.cs.luc.edu, and requesting files. If you contact on port 4515/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 4516/4716 you get a response from the same port. No matter what file you ask for, the file you get is always the same. The server on ports 4517/4717 offers experimental support for sliding windows. By asking port 4715 for the following names, you get the indicated behavior:
vanilla Normal transfer
At this point, the only special filenames that work on the "sameport" ports (4516/4517/4716/4717) are vanilla, lose2 (losedata2), dup2 (dupdata2) and spray.
In order to get the basic vanilla transfer working, there are two things you need to do, as outlined above:
If you run the existing wclient.java (with wumppkt.java), and you have network access that doesn't block the necessary ports, your output should look something like this:
Looking
up address of ulam.cs.luc.edu... got it!
req size = 12, filename=vanilla
rec'd packet: len=520; proto=1; opcode=2; src=(10.0.0.1/60000); time=4
DATA packet blocknum =
1
An Assessment of the Programming Language Pascal
by Niklaus Wirth, developer of Pascal
1. What is reliable software?
Reliable is the attribute for a person, an organization, or a mechanism
that you can trust, that you can depend on, that is worthy of your
confidence. For example, a reliable clock is one that indicates
accurate time even during an earthquake, a reliable railway system is
one where trains run punctually even during a snowstorm, a reliable
bridge is a bridge that doesn't crack even under heahard timeout
hard timeout
hard timeout
hard timeout
hard timeout
...
What's going on here is that the server sent you Data[1], but your ACK didn't go to the right place, so it never sent you Data[2].
If you don't get Data[1], that is, you got nothing but error and status messages, try uncommenting the SAMEPORT line, because most likely a NAT router is blocking the Data[1] from a new port. If you do this, you will get both Data[1] and Data[2], because your ACK[1] now is going to the correct port (4715). But you won't get past Data[2], because you are not yet ever sending ACK[2]. You will probably get multiple Data[2] packets, because you will resend ACK[1] multiple times and each one will trigger a new Data[2].
The first step is to fix the ACK port, by appropriate placement of something like
ackDG.setPort(thePort);
(In general, you probably only want to set something like latchport, on receipt of the first Data[1], as part of the process of latching on to the initial port. However, at this point it won't matter if you set it on every packet.) 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 line
ack = wp.new ACK(wumppkt.BUMPPROTO, expected_block);
The line above creates an ack with the current expected_block, and you want to update expected_block for the next block. Alternatively, you can place a line
expected_block = data.blocknum();
before the ack creation, because this sets expected_block to the block number of the block that just arrived.
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!).
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. For undergrads only: implement sliding windows. A simple implementation is outlined in the Sliding Windows chapter of my book.
2. Implement HUMP. This should work through all NAT firewalls, and yet still have a new child port created for each connection. HUMP is not particularly hard: after you send the REQ, the first packet you get (which will come from the original server port) will be the handoff, which tells you the handoff port. You then respond with ACK[0] to the handoff port on the server, which then responds with Data[1].
If the handoff packet is lost, the HUMP connection fails. I originally thought this was a problem, but it seems to be a minor one compared to the impact of NAT.
Once you get basic WUMP working, HUMP involves
3. 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.