From 00d668549e46b34d29ea3daa1f6dd42b5251a365 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 23 Jul 2025 09:41:46 +0200 Subject: [PATCH] MINOR: mux-quic: do not reuse connection if app already shut QUIC connection graceful closure is performed in two steps. First, the application layer is closed. In the context of HTTP/3, this is done with a GOAWAY frame emission, which forbids opening of new streams. Then the whole connection is terminated via CONNECTION_CLOSE which is the final emitted frame. This commit ensures that when app layer is shut for a backend connection, this connection is removed from either idle or avail server tree. The objective is to prevent stream layer to try to reuse a connection if no new stream can be attached on it. New BUG_ON checks are inserted in qmux_strm_attach() and h3_attach() to ensure that this assertion is always true. --- src/h3.c | 3 +++ src/mux_quic.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/h3.c b/src/h3.c index e9444c76f..d88d9bcd2 100644 --- a/src/h3.c +++ b/src/h3.c @@ -3005,6 +3005,9 @@ static int h3_attach(struct qcs *qcs, void *conn_ctx) */ if (h3c->flags & H3_CF_GOAWAY_SENT && qcs->id >= h3c->id_goaway && quic_stream_is_bidi(qcs->id)) { + /* Local stack should not attached stream on a closed connection. */ + BUG_ON(quic_stream_is_local(qcs->qcc, qcs->id)); + TRACE_STATE("close stream outside of goaway range", H3_EV_H3S_NEW, qcs->qcc->conn, qcs); qcc_abort_stream_read(qcs); qcc_reset_stream(qcs, H3_ERR_REQUEST_REJECTED); diff --git a/src/mux_quic.c b/src/mux_quic.c index cad164442..87d981154 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -3195,6 +3195,10 @@ static void qcc_shutdown(struct qcc *qcc) if (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) qcc->conn->handle.qc->err = qcc->err; + /* A connection is not reusable if app layer is closed. */ + if (qcc->flags & QC_CF_IS_BACK) + conn_delete_from_tree(qcc->conn); + out: qcc->app_st = QCC_APP_ST_SHUT; TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn); @@ -3719,6 +3723,9 @@ static int qmux_strm_attach(struct connection *conn, struct sedesc *sd, struct s */ BUG_ON(!qcc_fctl_avail_streams(qcc, 1)); + /* Connnection should not be reused if already on error/closed. */ + BUG_ON(qcc->flags & QC_CF_ERRL || qcc->app_st >= QCC_APP_ST_SHUT); + qcs = qcc_init_stream_local(qcc, 1); if (!qcs) { TRACE_DEVEL("leaving on error", QMUX_EV_QCS_NEW, qcc->conn); @@ -3771,7 +3778,8 @@ static void qmux_strm_detach(struct sedesc *sd) qcs_destroy(qcs); /* Backend connection can be reused unless it is already on error/closed. */ - if (qcc->flags & QC_CF_IS_BACK && !qcc_is_dead(qcc)) { + if ((qcc->flags & QC_CF_IS_BACK) && !qcc_is_dead(qcc) && + qcc->app_st == QCC_APP_ST_INIT) { if (!(conn->flags & CO_FL_PRIVATE)) { if (!qcc->nb_sc) { TRACE_DEVEL("prepare for idle connection reuse", QMUX_EV_STRM_END, conn); -- 2.47.2