Q1. If I receive a segment with a sequence number less than the current ACK sequence number, can I just discard it?
A1. No. You have to look at both the start and end of the segment. For example, if the ACK sequence number is 1000 (1000 is the next byte you expect), and a segment comes in with a sequence number of 800 and a length of 300 (i.e. ends at 1099), then you have to keep the data from 1000 to 1099. A similar case exists at the end of the receive window.
Q2. The receiver window has closed so I can't send any more data until I get an ACK. What should I do with the extra data that I can't send?
A2. You should only read as much data from the application as you're planning on sending. Let the rest of it sit there until you're ready to send it (i.e. an ACK opens up the receive window again).
Note that the transmitter has to keep track of the sender window, based on the 3072-byte receiver window, the current ACK sequence number and the outstanding amount of un-acknowledged data, in order to know how much to send.
Q3. What am I allowed to modify in transport.c? What should I leave alone?
A3. You can change anything you like in transport.c, except for code inside "#ifdef FIXED_INITNUM." (Grading depends on this staying the same!) You can add any other functions or data types that you wish.
Q5. The specification says that I have to handle case X in the receiver, but my transmitter will never do that. Do I have to handle it?
A5. Yes. There is nothing stopping us from testing your receiver against another student's transmitter, or against our own transport layer which specifically does X as a test case for your code.
Q6. I'm confused about how connection termination works.
A6. When the application requests that a mysocket is closed (via myclose()), your transport layer will receive a 'close requested event' from stcp_wait_for_event(); this is your cue to send a FIN segment once all pending data has been successfully transmitted. When you receive a FIN from the peer, and all expected data from the peer has been passed up to the application, you indicate that subsequent myread()s should return zero by calling stcp_fin_received().
Q7. Do I have to consider the case where a packet is truncated? (i.e. the data length implied by the STCP header says I have more data than is actually in the packet?)
A7. No. You can assume the length in the STCP header is correct.
Q8. Why this weird threaded model? It makes everything harder to debug. Why not just have the application directly call the transport layer?
A8. Several reasons. For one, it actually makes things easier in the long run. If there was just one process/thread, how would the transport layer get control of the CPU when a timeout occurs or when a packet comes in? The only way to do this would be with signals. The signal model can work, but is much harder to debug with regards to things like race conditions. You have to explicitly deal with reentrancy issues and critical sections.
The event-driven model we have allows the transport layer to sleep until an interesting event happens. In some respects, this is a simpler model than you'd face in implementing a real TCP stack.
The second reason is that it abstracts the socket layer away from the transport layer. The layer you are writing is much more like a protocol stack that would actually fit into the operating system: you have a defined interface above you and below you, and you don't really need to know or care what the user processes above you are doing.
Q9. What is the meaning of 'absolute time' in stcp_wait_for_event()?
A9. It is the system time at which the function should return, if there is no pending event of interest. It is not a time interval relative to the current time, i.e. it has the same origin as functions like gettimeofday(2).
Q10. What functions and data types can I use from the stub code in my solution?
A10. Anything declared in stcp_api.h or transport.h is fair game. You should not use any other methods or data types defined by the mysock implementation. For example, you must use stcp_network_send() and stcp_network_recv() to send and receive packets from the network.
Q11. Do I need to deal with the case that sequence number wrapps around (goes over 2^32 and starts from 0 again)?
A11. No. This does add some complexity into the assignment. You're not required to deal with it. We're not going to test your programs to transfer 4 gigabytes of data :-) But keep in mind this happens in real TCP.
Q12. Why does the following not work?
while ((got = stcp_network_recv(&char, 1)) >= 0) {...}
A12. We are using UDP for the network layer on the 2 sides to communicate. UDP is a datagram service. As opposed to a stream service, data is viewed as datagrams in UDP. Each I/O operation (read/write/send/recv) on a UDP socket corresponds to a datagram and each datagram is transported as a packet.
For example, if you do send(sd, buf, 10, 0); The 10 bytes of data are viewed as a datagram and packaged as a single packet, which is then transported to the other end. On the other hand, whenever you read from a UDP socket, you'll get 'exactly one datagram (packet)'. The read/recv call will not try fill out the buffer for you. But what happens if your buffer is too small to accommondate the datagram? As you might guess, the datagram is truncated and you get only the first few bytes. The rest part of the datagram is discarded!
Our network_recv is just a wrapper for recv. So you get only the 1st byte of each received packet by doing the above.
Q13. Can I send multiple packets at a time like the following?
stcp_network_send(pkt1, 100, pkt2, 200, pkt3, 100, NULL);
A13. No. As described in the previous question, the 3 STCP packets will be packaged as one UDP packet and sent. And you'll receive all 3 STCP packets (on the other end) in ONE stcp_network_recv. Because the receiver is not required to process several packets at a time, the 2nd and 3rd packets might be dropped. So don't do this, or your program will fail to communicate with others' (eg. our testing receiver).
Q14. What is the meaning of __attribute__ ((packed))?
A14. In modern computer architectures, the internal representation of a struct with a bunch of fields might contain some bytes of inner padding to align the fields with the word boundaries (this is done for performance reasons). However when you try to send this data, you do not want to send unnecessary padding, because the receiving machine might have a different internal representation.
So, what you want the compiler to do is to eliminate any padding, and to pack all fields back to back, so that the internal and the network representation are the same (except perhaps for byte ordering). This is the role of the PACK directives.
Q15. If there's bugs in my milestone HW5.A submission, but the bugs are fixed in milestone HW5.B, will points be taken off?
A15. Yes, we will grade the functionality of each milestone with the code that you submitted for it. However, we encourage you to fix your bugs, as they might come later to haunt you when testing other functions.
Q16. Do I have to set the source and destination ports in the TCP header?
A16. Nope. Although this would be handled by 'real' TCP, because of the way we simulate the underlying unreliable network layer, the specifics of how ports are assigned depends on the underlying network layer in the mysock implementation. Consequently, the mysock layer takes care of assigning ports and setting these values accordingly. You do not have to handle demultiplexing of connections.
Q17. Do I have to check for packet corruption with a checksum?
A17. No, but you will probably still want to do other error checking in the header.
Q18. How can I accurately measure elapsed time?
A18. You can use the function gettimeofday(). You cannot use any function from the real-time library (-lrt).
Q19. When is a packet considered "retransmitted" when deciding whether to abort a connection?
A19. Any transmission counts as such, regardless of what caused it. This includes packets retransmitted as part of Go-back N.