From: Amaury Denoyelle Date: Wed, 18 Jun 2025 07:59:50 +0000 (+0200) Subject: MEDIUM: mux-quic: implement attach for new streams on backend side X-Git-Tag: v3.3-dev2~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4527a2912bf8d33d3f1e26f3dd3cffffce474abd;p=thirdparty%2Fhaproxy.git MEDIUM: mux-quic: implement attach for new streams on backend side Implement attach and avail_streams mux-ops callbacks, which are used on backend side for connection reuse. Attach operation is used to initiate new streams on the connection outside of the first one. It simply relies on qcc_init_stream_local() to instantiate a new QCS instance, which is immediately linked to its stream data layer. Outside of attach, it is also necessary to implement avail_streams so that the stream layer will try to initiate connection reuse. This method reports the number of bidirectional streams which can still be opened for the QUIC connection. It depends directly to the flow-control value advertised by the peer. Thus, this ensures that attach won't cause any flow control violation. --- diff --git a/src/mux_quic.c b/src/mux_quic.c index 3a19fddfd..17fe8d6be 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -3122,6 +3122,20 @@ static int qcc_io_recv(struct qcc *qcc) return 0; } +/* Calculate the number of bidirectional streams which can still be opened for + * connection. This depends on flow-control set by the peer. + * + * Returns the value which is a positive integer or 0 if no new stream + * currently available. + */ +static int qmux_avail_streams(struct connection *conn) +{ + struct server *srv = __objt_server(conn->target); + struct qcc *qcc = conn->ctx; + + BUG_ON(srv->max_reuse >= 0); /* TODO ensure max-reuse is enforced. */ + return qcc_fctl_avail_streams(qcc, 1); +} /* Release all streams which have their transfer operation achieved. */ static void qcc_purge_streams(struct qcc *qcc) @@ -3687,6 +3701,37 @@ static void qmux_destroy(void *ctx) TRACE_LEAVE(QMUX_EV_QCC_END); } +static int qmux_strm_attach(struct connection *conn, struct sedesc *sd, struct session *sess) +{ + struct qcs *qcs; + struct qcc *qcc = conn->ctx; + + TRACE_ENTER(QMUX_EV_QCS_NEW, conn); + + /* Flow control limit on bidi streams should already have + * been checked by a prior qmux_avail_streams() invokation. + */ + BUG_ON(!qcc_fctl_avail_streams(qcc, 1)); + + qcs = qcc_init_stream_local(qcc, 1); + if (!qcs) { + TRACE_DEVEL("leaving on error", QMUX_EV_QCS_NEW, qcc->conn); + return -1; + } + + if (sc_attach_mux(sd->sc, qcs, conn)) { + TRACE_DEVEL("leaving on error", QMUX_EV_QCS_NEW, qcc->conn); + qcs_free(qcs); + return -1; + } + + qcs->sd = sd->sc->sedesc; + qcc->nb_sc++; + + TRACE_LEAVE(QMUX_EV_QCS_NEW, conn); + return 0; +} + static void qmux_strm_detach(struct sedesc *sd) { struct qcs *qcs = sd->se; @@ -4209,6 +4254,8 @@ static const struct mux_ops qmux_ops = { .subscribe = qmux_strm_subscribe, .unsubscribe = qmux_strm_unsubscribe, .wake = qmux_wake, + .avail_streams = qmux_avail_streams, + .attach = qmux_strm_attach, .shut = qmux_strm_shut, .ctl = qmux_ctl, .sctl = qmux_sctl,