From: Amaury Denoyelle Date: Wed, 8 Feb 2023 14:55:24 +0000 (+0100) Subject: MINOR: mux-quic: implement client-fin timeout X-Git-Tag: v2.8-dev5~162 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb7d320d2529fc2579b032f77d3a97611b2baaf2;p=thirdparty%2Fhaproxy.git MINOR: mux-quic: implement client-fin timeout Implement client-fin timeout for MUX quic. This timeout is used once an applicative layer shutdown has been called. In HTTP/3, this corresponds to the emission of a GOAWAY. This should be backported up to 2.7. --- diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index 2c66f85f58..7b4dc91e71 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -105,6 +105,7 @@ struct qcc { struct task *task; struct list opening_list; /* list of not already attached streams (http-request timeout) */ int timeout; + int shut_timeout; int idle_start; /* base time for http-keep-alive timeout */ const struct qcc_app_ops *app_ops; diff --git a/src/mux_quic.c b/src/mux_quic.c index 93e68d5b95..4b3af328b7 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -262,22 +262,22 @@ static void qcc_refresh_timeout(struct qcc *qcc) * it with global close_spread delay applied. */ - /* TODO implement client/server-fin timeout for graceful shutdown */ - /* Frontend timeout management + * - shutdown done -> timeout client-fin * - detached streams with data left to send -> default timeout * - stream waiting on incomplete request or no stream yet activated -> timeout http-request * - idle after stream processing -> timeout http-keep-alive */ if (!conn_is_back(qcc->conn)) { - if (qcc->nb_hreq) { + if (qcc->nb_hreq && !(qcc->flags & QC_CF_APP_SHUT)) { TRACE_DEVEL("one or more requests still in progress", QMUX_EV_QCC_WAKE, qcc->conn); qcc->task->expire = tick_add_ifset(now_ms, qcc->timeout); task_queue(qcc->task); goto leave; } - if (!LIST_ISEMPTY(&qcc->opening_list) || unlikely(!qcc->largest_bidi_r)) { + if ((!LIST_ISEMPTY(&qcc->opening_list) || unlikely(!qcc->largest_bidi_r)) && + !(qcc->flags & QC_CF_APP_SHUT)) { int timeout = px->timeout.httpreq; struct qcs *qcs = NULL; int base_time; @@ -293,12 +293,18 @@ static void qcc_refresh_timeout(struct qcc *qcc) qcc->task->expire = tick_add_ifset(base_time, timeout); } else { - /* Use http-request timeout if keep-alive timeout not set */ - int timeout = tick_isset(px->timeout.httpka) ? - px->timeout.httpka : px->timeout.httpreq; - - TRACE_DEVEL("at least one request achieved but none currently in progress", QMUX_EV_QCC_WAKE, qcc->conn); - qcc->task->expire = tick_add_ifset(qcc->idle_start, timeout); + if (qcc->flags & QC_CF_APP_SHUT) { + TRACE_DEVEL("connection in closing", QMUX_EV_QCC_WAKE, qcc->conn); + qcc->task->expire = tick_add_ifset(now_ms, + qcc->shut_timeout); + } + else { + /* Use http-request timeout if keep-alive timeout not set */ + int timeout = tick_isset(px->timeout.httpka) ? + px->timeout.httpka : px->timeout.httpreq; + TRACE_DEVEL("at least one request achieved but none currently in progress", QMUX_EV_QCC_WAKE, qcc->conn); + qcc->task->expire = tick_add_ifset(qcc->idle_start, timeout); + } } } @@ -2201,8 +2207,17 @@ static int qc_init(struct connection *conn, struct proxy *prx, qcc->proxy = prx; /* haproxy timeouts */ qcc->task = NULL; - qcc->timeout = conn_is_back(qcc->conn) ? prx->timeout.server : - prx->timeout.client; + if (conn_is_back(qcc->conn)) { + qcc->timeout = prx->timeout.server; + qcc->shut_timeout = tick_isset(prx->timeout.serverfin) ? + prx->timeout.serverfin : prx->timeout.server; + } + else { + qcc->timeout = prx->timeout.client; + qcc->shut_timeout = tick_isset(prx->timeout.clientfin) ? + prx->timeout.clientfin : prx->timeout.client; + } + if (tick_isset(qcc->timeout)) { qcc->task = task_new_here(); if (!qcc->task) {