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 aa29c00..abf00bf 100644
--- a/include/haproxy/mux_quic-t.h
+++ b/include/haproxy/mux_quic-t.h
@@ -29,6 +29,7 @@
 #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 e42089d..6c67648 100644
--- a/src/h3.c
+++ b/src/h3.c
@@ -819,11 +819,8 @@
 	}
 
 	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 a8ebe2b..bf91750 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -897,9 +897,6 @@
 
 	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 @@
 	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.
 	 */