diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index 43a7cccb8..4ce088e61 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -30,7 +30,6 @@ enum qcs_type { #define QC_CF_CC_EMIT 0x00000001 /* A CONNECTION_CLOSE is set by the MUX */ #define QC_CF_BLK_MFCTL 0x00000002 /* sending blocked due to connection flow-control */ #define QC_CF_CONN_FULL 0x00000004 /* no stream buffers available on connection */ -#define QC_CF_APP_FINAL 0x00000008 /* The application layer was finalized */ struct qcc { struct connection *conn; diff --git a/src/h3.c b/src/h3.c index f7bd8a12c..9a1d97d40 100644 --- a/src/h3.c +++ b/src/h3.c @@ -1636,6 +1636,10 @@ static void h3_detach(struct qcs *qcs) TRACE_LEAVE(H3_EV_H3S_END, qcs->qcc->conn, qcs); } +/* Initialize H3 control stream and prepare SETTINGS emission. + * + * Returns 0 on success else non-zero. + */ static int h3_finalize(void *ctx) { struct h3c *h3c = ctx; @@ -1643,12 +1647,12 @@ static int h3_finalize(void *ctx) qcs = qcc_init_stream_local(h3c->qcc, 0); if (!qcs) - return 0; + return 1; h3_control_send(qcs, h3c); h3c->ctrl_strm = qcs; - return 1; + return 0; } /* Generate a GOAWAY frame for connection on the control stream. diff --git a/src/mux_quic.c b/src/mux_quic.c index 31d5a3ab0..b7b843e35 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -883,6 +883,21 @@ int qcc_install_app_ops(struct qcc *qcc, const struct qcc_app_ops *app_ops) TRACE_PROTO("application layer initialized", QMUX_EV_QCC_NEW, qcc->conn); + /* RFC 9114 7.2.4.2. Initialization + * + * Endpoints MUST NOT require any data to be + * received from the peer prior to sending the SETTINGS frame; + * settings MUST be sent as soon as the transport is ready to + * send data. + */ + if (qcc->app_ops->finalize) { + if (qcc->app_ops->finalize(qcc->ctx)) { + TRACE_ERROR("app ops finalize error", QMUX_EV_QCC_NEW, qcc->conn); + goto err; + } + tasklet_wakeup(qcc->wait_event.tasklet); + } + TRACE_LEAVE(QMUX_EV_QCC_NEW, qcc->conn); return 0; @@ -1741,15 +1756,6 @@ static int qc_send(struct qcc *qcc) if (qcc->flags & QC_CF_BLK_MFCTL) goto err; - if (!(qcc->flags & QC_CF_APP_FINAL) && !eb_is_empty(&qcc->streams_by_id) && - qcc->app_ops->finalize) { - /* Finalize the application layer before sending any stream. - * For h3 this consists in preparing the control stream data (SETTINGS h3). - */ - qcc->app_ops->finalize(qcc->ctx); - qcc->flags |= QC_CF_APP_FINAL; - } - /* Send STREAM/STOP_SENDING/RESET_STREAM data for registered streams. */ list_for_each_entry_safe(qcs, qcs_tmp, &qcc->send_list, el_send) { /* Stream must not be present in send_list if it has nothing to send. */