TCP TIME_WAIT State
Ctrl-C is typed on the client-side to terminate the application (nc program), the TCP connection state on the client side moves from ESTABLISHED to FIN_WAIT_1, and the client sends the server the FIN message. On receiving the FIN|ACK response from the server, the client-side state moves to TIME_WAIT. (The transmissions of FIN and FIN|ACK happen within a very short duration e.g. less than a second, and thus the intermediate state FIN_WAIT_1 is not visible in the lower panel of Figure 10. Similarly, the server-side rapidly transitions from ESTABLISHED to CLOSE_WAIT to LAST_ACK, after which the server-side TCP connection is CLOSED. Once again, these intermediate states are not captured in the lower panel of Figure 9.) The client-side remains in the TIME_WAIT state for a duration corresponding to the TCP maximum segment life (MSL) timeout, which is typically 2 minutes as recommended by RFC 793 . See Exercise 1 for further details.
RFC 793  defines TIME-WAIT as a state that “represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request”. The primary reason for this state is to prevent delayed delivery of a TCP segment3 from an earlier (closed) connection being misinterpreted as a part of a subsequent new (open) connection. This scenario, although unlikely, can occur under rare circumstances when the new connection makes use of the same port number and IP addresses as the earlier connection (i.e., the same socket tuple identification), and has TCP sequence numbers in the same range as used in the earlier connection. A schematic representing this possibility is shown in Figure 11. Here, machine M2 initiates the connection closure and goes into the TIME_WAIT state. If a new connection starts with the same <src IP, src port, dst IP, dst port> tuple, this connection should be rejected until data from the earlier connection that exists in the network can be delivered to M2. The life of data packets in a network is determined by the Time To Live (TTL) field in the IP header., which corresponds to number of hops (i.e., routers in the network) through which this packet can pass through before it gets dropped. Since the time taken by a packet from one router to the next router in the path from source to destination corresponds to transmission delay plus propagation delay , TTL roughly corresponds to the maximum duration for which a packet can exist in the network either before it reaches its destination or dropped (when TTL becomes zero4 ). Thus, the TCP connection for the end point that initiates active close must wait for this much time, known as 2MSL time (twice the Maximum Segment Lifetime). When a machine sees a new connection being established with the same socket tuple corresponding to a connection in a TIME_WAIT state, it simply rejects the connection with an error “Address already in use”. This is shown in Figure 12. Here, the client C_m (lower panel) using port number 6666 initiates a TCP connection to the server S_m (upper panel) listening on port 5555. The connection is established and after exchange of the data string hello, the client closes the connection and enters the TIME_WAIT state. Thus, when the client machine initiates a new connection using same socket tuple (using source port 6666 and destination port 5555), the TCP implementation on the client gives the error “bind failed: Address already in use”. Since the client remains in the TIME_WAIT state for 2MSL time (2 minutes) this error will persist until the 2MSL timeout expires.
Figure 11: Use of TIME_WAIT state
Thus, when client initiates another TCP connection using the same source port number which results in tuple value identical to previous connection in TIME_WAIT state, TCP implementation rejects this connection request and returns an error (“Address already in use”).
Figure 12: Use of TCP TIME_WAIT State`
Further, as a safeguarding measure (possibly an overzealous step), if any program on this machine tries to use the port number 6666 during this 2MSL period, it also gets the error “Address already in use”. Two such examples, which result in this error, are shown in lower panel of Figure 12. The first example corresponds to using the source port 6666 to connect to a server application on port 7777 (irrespective of whether this server application is running or not), and the second example corresponds to starting a server application listening on port 6666 on the client machine C_m itself. From a correctness perspective, both these cases should have been allowed. Only the TCP connection corresponding precisely to the earlier tuple <10.211.55.2, 5555, 10.211.55.10, 6666> should have been rejected. This implementation does impose a restriction on the number of TCP connections that can be set up on the machine.
The TIME_WAIT state also serves another purpose. Imagine that the TIME_WAIT state did not exist. Thus, when a connection is in the FIN_WAIT_2 state, and it receives the FIN message from the other end
(Figure 1), it sends the ACK message as a response and directly transitions to the CLOSED state. From the perspective of the TCP connection causing active close, the connection is completely closed. However, what if this ACK response is lost? In this case, the other end (following the path of passive close) will remain in the LAST_ACK state. After the timeout (to receive ACK of FIN) expires, it will send the FIN message again. When this message is received by other end (which has completed doing active close), it will not find any connection state and will respond with a TCP Reset error message implying no such connection exists. The connection following the transition path of passive close therefore gets an error message, even though the connection was closed properly – an unwanted situation.
The TIME_WAIT state may lead to scalability issues, and resources need to be planned accordingly. For instance, consider a high-performance web/application server that processes a high number of requests per second from web users. To serve these requests, suppose this server initiates TCP communication with other application servers, database servers, etc. for which it needs to open new connections. Further, this server closes these connections immediately after it gets the required data from these other servers. Since this web/app server is initiating active close, each such connection will transit to TIME_WAIT and remain in this state for 2MSL time before closing and releasing its full resources. The typical ephemeral port range (by default, a client uses source port number within this range when it initiates a connection) on a machine has around 300005 ports. Considering value of 2MSL timeout as 120 second and a server that sets up 250 TCP connections per second, it will very soon have 30000 connections in the TCP_WAIT state. Thus, it will not be able to initiate a new TCP connection as no local port number is available for setting up a new connection. One short-term approach is to reduce the value of 2MSL timeout, but that does not solve the problem since it may lead to the problem of TCP data segments from earlier connections appearing as genuine data segments of newly established later connections, which was the original problem addressed by the TIME_WAIT state. A better alternative could be to assign multiple IP addresses to the web server, and it should randomly pick an IP address and ephemeral port to initiate the connection.
We have explored the basic working of TCP state transition for a normal connection setup and specific network error conditions causing packet loss during TCP Connection Setup (Phase 1). We observed the connection state (SYN_SENT for acting open and SYN_RECV for passive open) at the client and server ends. The insight we have gained into these states will help in diagnosing situations where TCP connections do not work on expected lines, and will thus help us resolve issues accurately, and in a timely fashion.
There are several additional details that have not been covered in this article. Even during the connection setup phase, the transition path from SYN_SENT to SYN_RECV (shown by black color transitions in Figure 1) has not been discussed. This transition corresponds to simultaneous open, which is unlikely to occur – it is practically infeasible to create such a scenario in lab experiments. In the next article, we will discuss the events and state transitions in data transfer phase (Phase 2) and the teardown phase (Phase 3) and related issues. We will explore network behaviour and conditions that will enable us to witness individual states of transition for both active close and passive close, and the related challenges
3In general, data packets at TCP transport layer are called segments.
4Each router when forwards a packet decreases TTL by 1 and drops the packet when the value becomes 0. The max value of TTL can be 255 as it is an 8-bit field.
5This value is specified by system configuration parameter
net.ipv4.ip_local_port_range and its default value is 32768-60999.