FAQ Categories
The call to minisocket_server_create() blocks permanently until a connection is established. There is no timeout associated with this wait, so if no clients attempt to make a connection to the server, the function will block indefinitely.
Every minisocket maintains two counters: a sequence number and an acknowledgement number. The sequence number maintains a count of the number of new non-ACK packets that have been transmitted by the local socket. The acknowledgement number reflects the last valid sequence number from the remote, which for a window of size 1, would also happen to be the last sequence number seen. Take note that this definition has changed: the acknowledgement number is no longer the next expected sequence number, but rather the last seen sequence number.
Every non-ACK packet transmitted by the local socket will be issued a consecutive sequence number. Retransmissions are simply resends of old packets and are therefore not issued new sequence numbers. Empty ACK packets should use the last issued sequence number. Because of this scheme, a lost ACK packet can sometimes be made up for by a new packet from the local end (see diagrams below). This is actually closer to how TCP works.
The acknowledgement number on a local minisocket always reflects the last valid sequence number seen from the remote. The layman's way of describing this is: "if my acknowledgement number is X, then I have seen all remote packets up to and including X." A properly implemented minisocket network stack will never generate a packet that skips sequence numbers, and because the window size for this project has been set to 1, it is impossible for a sender to transmit a later packet before the earlier packet has been acknowledged. Thus, acknowledgement numbers will also be received in sequential order, without skips.
The (sequence number, acknowledgement number) tuple should start at (1,0) for both the client and server. The seq of the first packet leaving the local minisocket must be 1, whereas the ack number is 0 because the local minisocket has not yet seen packet 1 from the remote's system. Thus, the SYN packet from the client (which is the client's first packet) should have seq=1 ack=0. The SYNACK packet from the server should have seq=1 ack=1, because it is the first packet generated from the server and the server has seen the first packet from the client. The ACK packet from the client then has seq=1 ack=1, since an ACK is not awarded a new sequence number, and the client has seen the first packet from the server. This progression of sequence numbers and acknowledgement numbers then continues incrementally from the handshake.
Handshaking involves a predictable exchange of messages. The client sends a SYN message with seq=1 ack=0 and retransmits up to 7 times of the same SYN message with the same seq=1 ack=0 until an ACK message is received from the server. The server, upon receiving this SYN message, will reply with a SYNACK message that has seq=1 ack=1. It will keep retransmitting the SYNACK message of seq=1 ack=1 until the client responds with an ACK of seq=1 ack=1, or until the server has exhausted all its 7 retries (whereupon it will return back to the listening state). If the any of the client's seq=1 ack=1 ACK packet is received, the server enters the connected state.
Note that there is a possibility for the client and server to enter an inconsistent state: it could be the case that the client received the server's SYNACK, but the network somehow dropped all the ACKs from the client and the server has not received any ACKs despite retransmitting its SYNACK 7 times. In this case, the client would progress to the connected state, whereas the server reverts to the listening state. If such a thing were to happen, the client would discover that the server was no longer connected when it eventually sends a data message (the server would not respond and the client would eventually time out and close the connection). However, if the client begins the session by calling receive(), then it would hang in that state forever since the server would never deliver data to the client. This is normal and you do not need to worry about it.
Acknowledgement packets should never be cached. They should be regenerated each time an acknowledgement packet has to be sent. Therefore, ACK responses always reflect the latest (seq, ack) state of the socket.
The retransmission scheme only applies to non-ACK packets, which includes SYN, SYNACK, FIN and data messages. For these packets, a retransmission is necessary when no other packet from the remote acknowledges the receipt of a sent packet before the retransmission deadline. An acknowledgement does not always have to be in the form of an empty ACK packet. Since every packet from the remote contains a sequence number and acknowledgement number, these values can in fact be used to deduce if the remote has received a locally-sent packet.
What this means for the design of your network handler is that every incoming packet's acknowledgement number should be checked against the local sequence number, regardless of the packet type. If the acknowledgement number matches the local sequence number, we know that the remote has indeed received the last message that was sent from the local end, and thus the retransmission alarm for that packet can now be disabled. This clears the window and allows the sender to proceed with transmitting the next (non-ACK) packet.
On the other hand, if no packet sent by the remote acknowledges receipt of the locally-sent packet, then the timer will eventually expire on the retransmission alarm and that packet will be resent. A properly designed minisocket stack should not need to 'force' a retranmission; in particular, the receipt of any message from the remote should not trigger a resend of non-ACK packets.
Duplicate non-ACK packets should all be acknowledged with the current state of the minisocket. Duplicate ACK packets can simply be dropped.
Your implementation should create sockets for clients on port numbers 2^15 through 2^16 - 1. If no ports in this range are available, the call should fail. Likewise, It should also only be possible to create sockets for servers on ports 0 through 2^15 - 1. Attempts to create a server on any other port should fail.