]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: h3: Send the h3 settings with others streams (requests)
authorFrédéric Lécaille <flecaille@haproxy.com>
Thu, 8 Sep 2022 15:53:36 +0000 (17:53 +0200)
committerFrédéric Lécaille <flecaille@haproxy.com>
Thu, 8 Sep 2022 16:04:58 +0000 (18:04 +0200)
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.

include/haproxy/mux_quic-t.h
src/h3.c
src/mux_quic.c

index aa29c00b754c1874e2520e97fb70c25a53437718..abf00bfc30d5248a24993a6af615fc91e713a95b 100644 (file)
@@ -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;
index e42089d21320723af7b3a8e0718b5ad5a7b1f01f..6c6764851420d70407d9c5e8890359cc06c69b80 100644 (file)
--- 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;
index a8ebe2be4309ab5dcb3e2c60eb3bc9fff1c50257..bf91750c5eefe6c6b8568abfe1e75035313383a1 100644 (file)
@@ -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.
         */