From 1efaca8a57a9c077ff88f3334492693c68569cbe Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 11 Jun 2025 15:38:59 +0200 Subject: [PATCH] MINOR: mux-quic: instantiate first stream on backend side Adjust qmux_init() to handle frontend and backend sides differently. Most notably, on backend side, the first bidirectional stream is created preemptively. This step is necessary as MUX layer will be woken up just after handshake completion. --- src/mux_quic.c | 55 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/src/mux_quic.c b/src/mux_quic.c index 046627e24..b3fcd6517 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -134,6 +134,7 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type) qcs->stream = NULL; qcs->qcc = qcc; + qcs->sd = NULL; qcs->flags = QC_SF_NONE; qcs->st = QC_SS_IDLE; qcs->ctx = NULL; @@ -3405,6 +3406,7 @@ static int qmux_init(struct connection *conn, struct proxy *prx, { struct qcc *qcc; struct quic_transport_params *lparams, *rparams; + void *conn_ctx = conn->ctx; TRACE_ENTER(QMUX_EV_QCC_NEW); @@ -3530,27 +3532,48 @@ static int qmux_init(struct connection *conn, struct proxy *prx, if (qcc->app_ops == &h3_ops && !conn_is_back(conn)) proxy_inc_fe_cum_sess_ver_ctr(sess->listener, prx, 3); - /* Register conn for idle front closing. This is done once everything is allocated. */ - if (!conn_is_back(conn)) + if (!conn_is_back(conn)) { + /* Register conn for idle front closing. */ LIST_APPEND(&mux_stopping_data[tid].list, &conn->stopping_list); - /* init read cycle */ - tasklet_wakeup(qcc->wait_event.tasklet); + /* init read cycle */ + tasklet_wakeup(qcc->wait_event.tasklet); - /* MUX is initialized before QUIC handshake completion if early data - * received. Flag connection to delay stream processing if - * wait-for-handshake is active. - */ - if (conn->handle.qc->state < QUIC_HS_ST_COMPLETE) { - if (!(conn->flags & CO_FL_EARLY_SSL_HS)) { - TRACE_STATE("flag connection with early data", QMUX_EV_QCC_WAKE, conn); - conn->flags |= CO_FL_EARLY_SSL_HS; - /* subscribe for handshake completion */ - conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_RECV, - &qcc->wait_event); - qcc->flags |= QC_CF_WAIT_HS; + /* MUX is initialized before QUIC handshake completion if early data + * received. Flag connection to delay stream processing if + * wait-for-handshake is active. + */ + if (conn->handle.qc->state < QUIC_HS_ST_COMPLETE) { + if (!(conn->flags & CO_FL_EARLY_SSL_HS)) { + TRACE_STATE("flag connection with early data", QMUX_EV_QCC_WAKE, conn); + conn->flags |= CO_FL_EARLY_SSL_HS; + /* subscribe for handshake completion */ + conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_RECV, + &qcc->wait_event); + qcc->flags |= QC_CF_WAIT_HS; + } } } + else { + /* Initiate backend side transfer by creating the first + * bidirectional stream. MUX will then be woken up on QUIC + * handshake completion so that stream layer can start the + * transfer itself. + */ + struct qcs *qcs; + struct stconn *sc = conn_ctx; + + qcs = qcc_init_stream_local(qcc, 1); + if (!qcs) { + TRACE_PROTO("Cannot allocate a new locally initiated streeam", + QMUX_EV_QCC_NEW|QMUX_EV_QCC_ERR, conn); + goto err; + } + + sc_attach_mux(sc, qcs, conn); + qcs->sd = sc->sedesc; + qcc->nb_sc++; + } TRACE_LEAVE(QMUX_EV_QCC_NEW, conn); return 0;