[6.x] problem with AIO, non-blocking sockets on freebSD and IE7 on windows.

Julian Elischer julian at elischer.org
Sat Jun 23 01:08:16 UTC 2007

If one has an event-driven process that accepts tcp connections, 
one needs to set eh non-blocking socket option and use kqueue or 
similar to schedule work.

This is ok for data transfers, however when it comes to the 
close() call there is a problem.  The problem in in 
the following code in so_close()

                if (so->so_options & SO_LINGER) {
                        if ((so->so_state & SS_ISDISCONNECTING) &&
                            (so->so_state & SS_NBIO))
                                goto drop;
                        while (so->so_state & SS_ISCONNECTED) {
                                error = tsleep(&so->so_timeo,
                                    PSOCK | PCATCH, "soclos", so->so_linger * hz);
                                if (error)

   [ continues on to destroy socket ]

because SS_NBIO is set, the socket acts as if SO_LINGER was set, with a timeout of 0.
the result of this, is the following behaviour:

The first + last packet output is below:
Source         Destination    Info    2597 > http [SYN] Seq=0 Len=0  http > 2597 [SYN, ACK] Seq=0 Ack=1 Len=0    2597 > http [ACK] Seq=1 Ack=1 Len=0    POST http://creative.gettyimages.com/source/<truncated>
HTTP/1.1    HTTP  http > 2597 [ACK] Seq=1 Ack=1261 Len=0

---------------  http > 2597 [ACK] Seq=1 Ack=13729 Len=0    HTTP  HTTP/1.0 407 Proxy Authentication Required
(text/html)  HTTP  http > 2597 [FIN, ACK] Seq=1858 Ack=13729 Len=0    2597 > http [ACK] Seq=13731 Ack=1859 Len=0  http > 2597 [RST] Seq=1 Len=0  http > 2597 [RST] Seq=1859 Len=0

The ACK that comes from the client is wquite legal and in fact a FIN should follow.
however we react to it by sending a reset.

This makes IE7 throw a "generic IE error page". Even though it has all the information it 
Less that a good result for the user.

The answer is to NOT destroy the socket immediately, but to schedule it for self destruction
in FIN_WAIT_1_TIME seconds (or so_linger secs) or when the FIN turns up, whichever occurs first.

however so_close is in the wrong layer to decide to do this I think... socket code in general
has no timer related stuff.. TCPhas timers, so I thin it would require a new call into TCP
to tell it to put the session in question onto a (new) timer..

thoughts anyone?


More information about the freebsd-net mailing list