diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index 51bb4d61a..95cf47a01 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -99,6 +99,7 @@ struct stream_interface { /* struct members below are the "remote" part, as seen from the buffer side */ unsigned int err_type; /* first error detected, one of SI_ET_* */ int conn_retries; /* number of connect retries left */ + unsigned int hcto; /* half-closed timeout (0 = unset) */ }; /* operations available on a stream-interface */ diff --git a/src/proto_http.c b/src/proto_http.c index 0cafdb493..56480da65 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -9033,6 +9033,7 @@ void http_reset_txn(struct stream *s) s->res.rex = TICK_ETERNITY; s->res.wex = TICK_ETERNITY; s->res.analyse_exp = TICK_ETERNITY; + s->si[1].hcto = TICK_ETERNITY; } void free_http_res_rules(struct list *r) diff --git a/src/proxy.c b/src/proxy.c index c76d55d52..19eddcac0 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -1152,6 +1152,9 @@ int stream_set_backend(struct stream *s, struct proxy *be) if (be->options2 & PR_O2_INDEPSTR) s->si[1].flags |= SI_FL_INDEP_STR; + if (tick_isset(be->timeout.serverfin)) + s->si[1].hcto = be->timeout.serverfin; + /* We want to enable the backend-specific analysers except those which * were already run as part of the frontend/listener. Note that it would * be more reliable to store the list of analysers that have been run, diff --git a/src/stream.c b/src/stream.c index 94f7e5aea..78cc7ff5c 100644 --- a/src/stream.c +++ b/src/stream.c @@ -168,6 +168,7 @@ struct stream *stream_new(struct session *sess, struct task *t, enum obj_type *o /* this part should be common with other protocols */ si_reset(&s->si[0]); si_set_state(&s->si[0], SI_ST_EST); + s->si[0].hcto = sess->fe->timeout.clientfin; /* attach the incoming connection to the stream interface now. */ if (conn) @@ -182,6 +183,7 @@ struct stream *stream_new(struct session *sess, struct task *t, enum obj_type *o * callbacks will be initialized before attempting to connect. */ si_reset(&s->si[1]); + s->si[1].hcto = TICK_ETERNITY; if (likely(sess->fe->options2 & PR_O2_INDEPSTR)) s->si[1].flags |= SI_FL_INDEP_STR; @@ -2056,10 +2058,6 @@ struct task *process_stream(struct task *t) if (req->flags & CF_READ_ERROR) si_b->flags |= SI_FL_NOLINGER; si_shutw(si_b); - if (tick_isset(s->be->timeout.serverfin)) { - res->rto = s->be->timeout.serverfin; - res->rex = tick_add(now_ms, res->rto); - } } /* shutdown(write) done on server side, we must stop the client too */ @@ -2239,10 +2237,6 @@ struct task *process_stream(struct task *t) if (unlikely((res->flags & (CF_SHUTW|CF_SHUTW_NOW)) == CF_SHUTW_NOW && channel_is_empty(res))) { si_shutw(si_f); - if (tick_isset(sess->fe->timeout.clientfin)) { - req->rto = sess->fe->timeout.clientfin; - req->rex = tick_add(now_ms, req->rto); - } } /* shutdown(write) done on the client side, we must stop the server too */ diff --git a/src/stream_interface.c b/src/stream_interface.c index ee34e4bf5..4a0038842 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -205,6 +205,11 @@ static void stream_int_shutw(struct stream_interface *si) oc->wex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_DATA; + if (tick_isset(si->hcto)) { + ic->rto = si->hcto; + ic->rex = tick_add(now_ms, ic->rto); + } + switch (si->state) { case SI_ST_EST: /* we have to shut before closing, otherwise some short messages @@ -826,6 +831,11 @@ static void stream_int_shutw_conn(struct stream_interface *si) oc->wex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_DATA; + if (tick_isset(si->hcto)) { + ic->rto = si->hcto; + ic->rex = tick_add(now_ms, ic->rto); + } + switch (si->state) { case SI_ST_EST: /* we have to shut before closing, otherwise some short messages @@ -1441,6 +1451,11 @@ static void stream_int_shutw_applet(struct stream_interface *si) oc->wex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_DATA; + if (tick_isset(si->hcto)) { + ic->rto = si->hcto; + ic->rex = tick_add(now_ms, ic->rto); + } + /* on shutw we always wake the applet up */ appctx_wakeup(si_appctx(si));