5.11 Connection Abort before
accept Returns
There is another condition similar to the
interrupted system call example in the previous section that can
cause accept to return a nonfatal error, in which case we
should just call accept again. The sequence of packets
shown in Figure 5.13 has
been seen on busy servers (typically busy Web servers).
Here, the three-way handshake completes, the
connection is established, and then the client TCP sends an RST
(reset). On the server side, the connection is queued by its TCP,
waiting for the server process to call accept when the RST
arrives. Sometime later, the server process calls
accept.
An easy way to simulate this scenario is to
start the server, have it call socket, bind, and
listen, and then go to sleep for a short period of time
before calling accept. While the server process is asleep,
start the client and have it call socket and
connect. As soon as connect returns, set the
SO_LINGER socket option to generate the RST (which we will
describe in Section 7.5 and
show an example of in Figure 16.21) and
terminate.
Unfortunately, what happens to the aborted
connection is implementation-dependent. Berkeley-derived
implementations handle the aborted connection completely within the
kernel, and the server process never sees it. Most SVR4
implementations, however, return an error to the process as the
return from accept, and the error depends on the
implementation. These SVR4 implementations return an errno
of EPROTO ("protocol error"), but POSIX specifies that the
return must be ECONNABORTED ("software caused connection
abort") instead. The reason for the POSIX change is that
EPROTO is also returned when some fatal protocol-related
events occur on the streams subsystem. Returning the same error for
the nonfatal abort of an established connection by the client makes
it impossible for the server to know whether to call
accept again or not. In the case of the
ECONNABORTED error, the server can ignore the error and
just call accept again.
The steps involved in Berkeley-derived kernels
that never pass this error to the process can be followed in TCPv2.
The RST is processed on p. 964, causing tcp_close to be
called. This function calls in_pcbdetach on p. 897, which
in turn calls sofree on p. 719. sofree (p. 473)
finds that the socket being aborted is still on the listening
socket's completed connection queue and removes the socket from the
queue and frees the socket. When the server gets around to calling
accept, it will never know that a connection that was
completed has since been removed from the queue.
We will return to these aborted connections in
Section 16.6 and
see how they can present a problem when combined with
select and a listening socket in the normal blocking
mode.
|