From: Frédéric Lécaille Date: Thu, 8 Sep 2022 15:53:36 +0000 (+0200) Subject: MINOR: h3: Send the h3 settings with others streams (requests) X-Git-Tag: v2.7-dev6~59 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3dd79d378c86b3ebf60e029f518add5f1ed54815;p=thirdparty%2Fhaproxy.git MINOR: h3: Send the h3 settings with others streams (requests) This is the ->finalize application callback which prepares the unidirectional STREAM frames for h3 settings and wakeup the mux I/O handler to send them. As haproxy is at the same time always waiting for the client request, this makes haproxy call sendto() to send only about 20 bytes of stream data. Furthermore in case of heavy loss, this give less chances to short h3 requests to succeed. Drawback: as at this time the mux sends its streams by their IDs ascending order the stream 0 is always embedded before the unidirectional stream 3 for h3 settings. Nevertheless, as these settings may be lost and received after other h3 request streams, this is permitted by the RFC. Perhaps there is a better way to do. This will have to be checked with Amaury. Must be backported to 2.6. --- diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index aa29c00b75..abf00bfc30 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -29,6 +29,7 @@ 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 e42089d213..6c67648514 100644 --- a/src/h3.c +++ b/src/h3.c @@ -819,11 +819,8 @@ static int h3_control_send(struct qcs *qcs, void *ctx) } ret = b_force_xfer(res, &pos, b_data(&pos)); - if (ret > 0) { + if (ret > 0) h3c->flags |= H3_CF_SETTINGS_SENT; - if (!(qcs->qcc->wait_event.events & SUB_RETRY_SEND)) - tasklet_wakeup(qcs->qcc->wait_event.tasklet); - } TRACE_LEAVE(H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs); return ret; diff --git a/src/mux_quic.c b/src/mux_quic.c index a8ebe2be43..bf91750c5e 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -897,9 +897,6 @@ 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); - if (qcc->app_ops->finalize) - qcc->app_ops->finalize(qcc->ctx); - TRACE_LEAVE(QMUX_EV_QCC_NEW, qcc->conn); return 0; @@ -1609,6 +1606,15 @@ static int qc_send(struct qcc *qcc) if (qcc->flags & QC_CF_BLK_MFCTL) return 0; + 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; + } + /* loop through all streams, construct STREAM frames if data available. * TODO optimize the loop to favor streams which are not too heavy. */