[core] option to propagate TCP FIN to backend host

(experimental support for mod_sockproxy)

"tcp-fin-propagate" = "enable" for each host in *.server backend defs
personal/stbuehler/fix-fdevent
Glenn Strauss 2018-08-09 00:40:37 -04:00
parent bbf01a3a6c
commit 7c8cc6f7c5
4 changed files with 44 additions and 7 deletions

View File

@ -918,6 +918,7 @@ static handler_t connection_handle_fdevent(server *srv, void *context, int reven
int events = fdevent_event_get_interest(srv->ev, con->fd);
events &= ~(FDEVENT_IN|FDEVENT_RDHUP);
con->conf.stream_request_body &= ~(FDEVENT_STREAM_REQUEST_BUFMIN|FDEVENT_STREAM_REQUEST_POLLIN);
con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLRDHUP;
con->is_readable = 1; /*(can read 0 for end-of-stream)*/
con->keep_alive = 0;
if (con->request.content_length < -1) { /*(transparent proxy mode; no more data to read)*/
@ -934,6 +935,7 @@ static handler_t connection_handle_fdevent(server *srv, void *context, int reven
* 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 */
con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_TCP_FIN;
fdevent_event_set(srv->ev, &con->fde_ndx, con->fd, events);
} else {
/* Failure of fdevent_is_tcp_half_closed() indicates TCP RST

View File

@ -20,9 +20,12 @@ typedef handler_t (*fdevent_handler)(struct server *srv, void *ctx, int revents)
#define FDEVENT_NVAL BV(5)
#define FDEVENT_RDHUP BV(13)
#define FDEVENT_STREAM_REQUEST BV(0)
#define FDEVENT_STREAM_REQUEST_BUFMIN BV(1)
#define FDEVENT_STREAM_REQUEST_POLLIN BV(15)
#define FDEVENT_STREAM_REQUEST BV(0)
#define FDEVENT_STREAM_REQUEST_BUFMIN BV(1)
#define FDEVENT_STREAM_REQUEST_POLLRDHUP BV(12)
#define FDEVENT_STREAM_REQUEST_TCP_FIN BV(13)
#define FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR BV(14)
#define FDEVENT_STREAM_REQUEST_POLLIN BV(15)
#define FDEVENT_STREAM_RESPONSE BV(0)
#define FDEVENT_STREAM_RESPONSE_BUFMIN BV(1)

View File

@ -1269,6 +1269,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size
{ "listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
{ "x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
{ "x-sendfile-docroot",NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
{ "tcp-fin-propagate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@ -1324,6 +1325,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size
fcv[19].destination = &(host->listen_backlog);
fcv[20].destination = &(host->xsendfile_allow);
fcv[21].destination = host->xsendfile_docroot;
fcv[22].destination = &(host->tcp_fin_propagate);
if (0 != config_insert_values_internal(srv, da_host->value, fcv, T_CONFIG_SCOPE_CONNECTION)) {
goto error;
@ -1715,6 +1717,23 @@ handler_t gw_connection_reset(server *srv, connection *con, void *p_d) {
}
static void gw_conditional_tcp_fin(server *srv, gw_handler_ctx *hctx) {
connection *con = hctx->remote_conn;
/*assert(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN);*/
if (!chunkqueue_is_empty(hctx->wb)) return;
if (!hctx->host->tcp_fin_propagate) return;
if (hctx->gw_mode == GW_AUTHORIZER) return;
if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR)
return;
/* propagate shutdown SHUT_WR to backend if TCP half-close on con->fd */
con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR;
con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
con->is_readable = 0;
shutdown(hctx->fd, SHUT_WR);
fdevent_event_clr(srv->ev, &hctx->fde_ndx, hctx->fd, FDEVENT_OUT);
}
static handler_t gw_write_request(server *srv, gw_handler_ctx *hctx) {
switch(hctx->state) {
case GW_STATE_INIT:
@ -1880,6 +1899,10 @@ static handler_t gw_write_request(server *srv, gw_handler_ctx *hctx) {
}
}
if (hctx->remote_conn->conf.stream_request_body
& FDEVENT_STREAM_REQUEST_TCP_FIN)
gw_conditional_tcp_fin(srv, hctx);
return HANDLER_WAIT_FOR_EVENT;
case GW_STATE_READ:
/* waiting for a response */
@ -2001,10 +2024,18 @@ handler_t gw_handle_subrequest(server *srv, connection *con, void *p_d) {
}
}
return ((0 == hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
&& hctx->state != GW_STATE_CONNECT_DELAYED)
? gw_send_request(srv, hctx)
: HANDLER_WAIT_FOR_EVENT;
{
handler_t rc =((0==hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
&& hctx->state != GW_STATE_CONNECT_DELAYED)
? gw_send_request(srv, hctx)
: HANDLER_WAIT_FOR_EVENT;
if (HANDLER_WAIT_FOR_EVENT != rc) return rc;
}
if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN)
gw_conditional_tcp_fin(srv, hctx);
return HANDLER_WAIT_FOR_EVENT;
}

View File

@ -203,6 +203,7 @@ typedef struct {
buffer *strip_request_uri;
unsigned short tcp_fin_propagate;
unsigned short kill_signal; /* we need a setting for this as libfcgi
applications prefer SIGUSR1 while the
rest of the world would use SIGTERM