|
|
|
@ -908,9 +908,26 @@ static handler_t connection_handle_fdevent(server *srv, void *context, int reven
|
|
|
|
|
if (con->state == CON_STATE_CLOSE) {
|
|
|
|
|
con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
|
|
|
|
|
} else if (revents & FDEVENT_HUP) {
|
|
|
|
|
if (fdevent_is_tcp_half_closed(con->fd)) {
|
|
|
|
|
connection_set_state(srv, con, CON_STATE_ERROR);
|
|
|
|
|
} else if (revents & FDEVENT_RDHUP) {
|
|
|
|
|
if (sock_addr_get_family(&con->dst_addr) == AF_UNIX) {
|
|
|
|
|
/* future: will getpeername() on AF_UNIX properly check if still connected? */
|
|
|
|
|
fdevent_event_clr(srv->ev, &con->fde_ndx, con->fd, FDEVENT_RDHUP);
|
|
|
|
|
con->keep_alive = 0;
|
|
|
|
|
} else if (fdevent_is_tcp_half_closed(con->fd)) {
|
|
|
|
|
/* Success of fdevent_is_tcp_half_closed() after FDEVENT_RDHUP indicates TCP FIN received,
|
|
|
|
|
* but does not distinguish between client shutdown(fd, SHUT_WR) and client close(fd).
|
|
|
|
|
* Remove FDEVENT_RDHUP so that we do not spin on the ready event.
|
|
|
|
|
* However, a later TCP RST will not be detected until next write to socket.
|
|
|
|
|
* future: might getpeername() to check for TCP RST on half-closed sockets
|
|
|
|
|
* (without FDEVENT_RDHUP interest) when checking for write timeouts
|
|
|
|
|
* once a second in server.c, though getpeername() on Windows might not indicate this */
|
|
|
|
|
fdevent_event_clr(srv->ev, &con->fde_ndx, con->fd, FDEVENT_RDHUP);
|
|
|
|
|
con->keep_alive = 0;
|
|
|
|
|
} else {
|
|
|
|
|
/* Failure of fdevent_is_tcp_half_closed() indicates TCP RST
|
|
|
|
|
* (or unable to tell (unsupported OS), though should not
|
|
|
|
|
* be setting FDEVENT_RDHUP in that case) */
|
|
|
|
|
connection_set_state(srv, con, CON_STATE_ERROR);
|
|
|
|
|
}
|
|
|
|
|
} else if (revents & FDEVENT_ERR) { /* error, connection reset */
|
|
|
|
@ -1370,8 +1387,7 @@ int connection_state_machine(server *srv, connection *con) {
|
|
|
|
|
r = 0;
|
|
|
|
|
switch(con->state) {
|
|
|
|
|
case CON_STATE_READ:
|
|
|
|
|
case CON_STATE_CLOSE:
|
|
|
|
|
r = FDEVENT_IN;
|
|
|
|
|
r = FDEVENT_IN | FDEVENT_RDHUP;
|
|
|
|
|
break;
|
|
|
|
|
case CON_STATE_WRITE:
|
|
|
|
|
/* request write-fdevent only if we really need it
|
|
|
|
@ -1386,9 +1402,12 @@ int connection_state_machine(server *srv, connection *con) {
|
|
|
|
|
/* fall through */
|
|
|
|
|
case CON_STATE_READ_POST:
|
|
|
|
|
if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN) {
|
|
|
|
|
r |= FDEVENT_IN;
|
|
|
|
|
r |= FDEVENT_IN | FDEVENT_RDHUP;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CON_STATE_CLOSE:
|
|
|
|
|
r = FDEVENT_IN;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -1402,6 +1421,9 @@ int connection_state_machine(server *srv, connection *con) {
|
|
|
|
|
con->is_writable = 0;
|
|
|
|
|
r |= FDEVENT_OUT;
|
|
|
|
|
}
|
|
|
|
|
if (events & FDEVENT_RDHUP) {
|
|
|
|
|
r |= FDEVENT_RDHUP;
|
|
|
|
|
}
|
|
|
|
|
if (r != events) {
|
|
|
|
|
/* update timestamps when enabling interest in events */
|
|
|
|
|
if ((r & FDEVENT_IN) && !(events & FDEVENT_IN)) {
|
|
|
|
|