2

One of the reasons for TIME_WAIT is to prevent old packets/duplicates, coming in late, to screw up subsequent connections on the same (src ip, src port, dst ip, dst port) quadruplet.

That makes sense, but I don't understand why it is only done for the side closing the connection.

Let's assume both connections have sent and received FINs and ACKs - aren't they in the same boat regarding old duplicates coming in? So why doesn't the other side protect itself with a TIME_WAIT state as well?

1
  • Did any answer help you? If so, you should accept the answer so that the question doesn't keep popping up forever, looking for an answer. Alternatively, you can post and accept your own answer.
    – Ron Maupin
    Dec 17 '20 at 22:33
5
+50

I don't understand why it is only done for the side closing the connection.

Remember that that when the first side sends a FIN, it is done sending, but it will still receive and process as long as the other side is willing to send, and sends ACKs for any segments received until the other side is done. It goes into the FIN-WAIT-1 state until it receives the ACK of its FIN, and the FIN-WAIT-2 state after it receives that ACK of its FIN. It cannot force the other side to close (except with RST), and it will receive and process until the connection is closed.

When the second side is done sending, it will send a FIN causing the the first side to send an ACK, then go into TIME-WAIT (2MSL) to make sure the second side received its ACK. After the second side receives the ACK, it also waits 2MSL. After those timeouts, each side closes the connection. This is actually symmetric as both side wait 2MSL before closing the connection.

Once the connection is closed, and any receipt of segments, by either side, after that requires a RST in reply. The timeout on the second side is to make sure that there are no out-of-order segments arriving that would cause a RST.

It is explained in RFC 793, Transmission Control Protocol, which is the definition of TCP. The originator of the first FIN goes into TIME-WAIT because "TIME-WAIT - represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request." After the last ACK of the last FIN, the sender of the last FIN must wait "Timeout=2MSL."

The states are explained on pages 21 and 22, and the Connection State diagram is on page 23.

1
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Ron Maupin
    Jan 21 '21 at 15:56
1

Preventing lost and delayed packets affecting future connections is only a secondary purpose of TIME_WAIT1. TCP is hardened against such packets by virtue of the receive window and, in modern implementations, timestamps.

Instead, TIME_WAIT's primary purpose is to handle the case in which the final ACK is lost. In such a case the final FIN will be re-received and the final ACK will need to be re-transmitted. This is necessary because there is no ACKing an ACK, or the two endpoints would be ACKing each other forever. Instead, one side sends the final ACK and waits for some time in TIME_WAIT so as to be fairly certain that the other endpoint received said ACK and did not re-transmit its FIN.

However, the fact that the endpoint that passively closes does not enter a state equivalent to TIME_WAIT I view as a design flaw in TCP. Have a look at the TCP state diagram in this page, and consider the case where the second last ACK is lost:

enter image description here

Diagram Key: Green: State | Blue: API calls | Red: errors, events and notes | Purple line: connection state save-points

The problem is that the two Endpoints get out of sync if the second-last ACK is lost: Endpoint A believes a simultaneous close is happening and awaits a final ACK, whereas Endpoint B believes that the connection is fully closed both ways (Diagram 1).

This eventually cleans itself up if the connection is left as-is (Diagram 2), but nothing stops Endpoint B from trying to re-open the connection (Diagram 3) which results in connection reset errors (Diagrams 4 and 5).

A better design would have been to merge the CLOSING and LAST_ACK states so that both ends go through TIME_WAIT, at the cost of slightly more memory usage at the passively closing end.


1No direct mention of TIME_WAIT's secondary purpose of preventing segments from an old incarnation of the connection from interfering with a new incarnation is made in RFC 739, and can be only vaguely inferred from the sections on quiet time and section 4.2.2.13 of RFC 1122. I notice that RFC 6528 Section 2 from 2012 states:

It is interesting to note that, as a matter of fact, protection against stale segments from a previous incarnation of the connection is enforced by preventing the creation of a new incarnation of a previous connection before 2*MSL have passed since a segment corresponding to the old incarnation was last seen (where "MSL" is the "Maximum Segment Lifetime" [RFC0793]). This is accomplished by the TIME-WAIT state and TCP's "quiet time" concept

However I find this to be incorrect as a connection that is reset does not enter the TIME_WAIT state and instead enters the CLOSED or LISTEN states. So old segments could still be in flight at a time when the connection could be re-opened. This could perhaps be remedied by having reset connections go into a TIME_WAIT-like state. The confusion over this dual-purpose may be the root cause of these inconsistencies.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.