It's important to remember that once a TCP connection is established, it
is bidirectional, but that each direction can be shut down
independently.

If peers C and S are communicating using TCP, then C can shut down
its stream to S without affecting S's stream to C by sending a packet
with the FIN bit set. On Unix, C can make that happen by calling
shutdown(fd,1). When S receives the FIN packet, it knows that C is done
sending, but S can continue sending data to C. On Unix, if S calls read
on the TCP socket, it will get EOF (read will return 0) after read
returns any remaining buffered data.

When C sends the FIN, it is not telling S that it wants S to stop
sending data. It's perfectly valid for C to send an HTTP request
immediately followed by a FIN, and then wait for S to send the HTTP
response.

Now, suppose C sends the HTTP request and then wants to tell S to abort
the request. It doesn't matter whether C has sent the FIN or not: even
if C has not sent the FIN (meaning that C can send more data to S), HTTP
does not provide any way for C to ask S to abort.

At the TCP level, if C sends the FIN, it doesn't mean that S should stop
processing and sending. It just tells S that C is done sending. To tell
S to abort, the best C can do is send a packet with the RST flag set. On
Unix, C can do that by setting SO_LINGER on with a linger time of zero
and then closing the socket.

If S is on a Unix system, then when its TCP stack receives the RST, the
TCP stack won't immediately notify the process.  The process must try to
write to the TCP socket; it will then receive a SIGPIPE.  If SIGPIPE is
blocked or ignored, or if the SIGPIPE handler returns, then the write
system call will return EPIPE.

I think I've read that on some Unix systems, if you call write with 0
bytes, it will return EPIPE (or raise SIGPIPE) if a RST has been sent. I
think I've read that on Linux this does not work.  I haven't tested it.

So how can we use all of this knowledge to allow an AOLserver handler to
detect when the client has cancelled (sent an RST)? Simple: try to send
a byte periodically; if ns_write returns 0, then the client has gone
away. There's no other portable, reliable way to do it.

Note that if you send the response with ns_return, you can't use
ns_write.  And if you use ns_write to send the HTTP header, then
AOLserver will not allow HTTP keepalive.

Reply via email to