MAJOR: quic: implement accept queue
Do not proceed to direct accept when creating a new quic_conn. Wait for
the QUIC handshake to succeeds to insert the quic_conn in the accept
queue. A tasklet is then woken up to call listener_accept to accept the
quic_conn.
The most important effect is that the connection/mux layers are not
instantiated at the same time as the quic_conn. This forces to delay
some process to be sure that the mux is allocated :
* initialization of mux transport parameters
* installation of the app-ops
Also, the mux instance is not checked now to wake up the quic_conn
tasklet. This is safe because the xprt-quic code is now ready to handle
the absence of the connection/mux layers.
Note that this commit has a deep impact as it changes significantly the
lower QUIC architecture. Most notably, it breaks the 0-RTT feature.
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index 26e085f..588d8a2 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -44,6 +44,7 @@
#include <haproxy/quic_cc.h>
#include <haproxy/quic_frame.h>
#include <haproxy/quic_loss.h>
+#include <haproxy/quic_sock.h>
#include <haproxy/cbuf.h>
#include <haproxy/quic_tls.h>
#include <haproxy/sink.h>
@@ -1048,12 +1049,6 @@
else
return 0;
- if (qcc_install_app_ops(qc->qcc, qc->app_ops))
- return 0;
-
- /* mux-quic can now be considered ready. */
- qc->mux_state = QC_MUX_READY;
-
return 1;
}
@@ -1892,10 +1887,14 @@
}
TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_HDSHK, qc, &state);
- if (qc_is_listener(ctx->qc))
+ if (qc_is_listener(ctx->qc)) {
HA_ATOMIC_STORE(&qc->state, QUIC_HS_ST_CONFIRMED);
- else
+ /* The connection is ready to be accepted. */
+ quic_accept_push_qc(qc);
+ }
+ else {
HA_ATOMIC_STORE(&qc->state, QUIC_HS_ST_COMPLETE);
+ }
} else {
ssl_err = SSL_process_quic_post_handshake(ctx->ssl);
if (ssl_err != 1) {
@@ -3662,6 +3661,9 @@
qc->path = &qc->paths[0];
quic_path_init(qc->path, ipv4, default_quic_cc_algo, qc);
+ /* required to use MTLIST_IN_LIST */
+ MT_LIST_INIT(&qc->accept_list);
+
TRACE_LEAVE(QUIC_EV_CONN_INIT, qc);
return qc;
@@ -4557,9 +4559,6 @@
if (likely(!qc_to_purge)) {
/* Enqueue this packet. */
pkt->qc = qc;
- MT_LIST_APPEND(&l->rx.pkts, &pkt->rx_list);
- /* Try to accept a new connection. */
- listener_accept(l);
}
else {
quic_conn_drop(qc_to_purge);
@@ -4663,7 +4662,7 @@
* initialized.
*/
conn_ctx = HA_ATOMIC_LOAD(&qc->xprt_ctx);
- if (conn_ctx && HA_ATOMIC_LOAD(&qc->qcc))
+ if (conn_ctx)
tasklet_wakeup(conn_ctx->wait_event.tasklet);
TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc ? qc : NULL, pkt);
@@ -5484,6 +5483,15 @@
return 0;
}
+ quic_mux_transport_params_update(qc->qcc);
+ if (qcc_install_app_ops(qc->qcc, qc->app_ops)) {
+ TRACE_PROTO("Cannot install app layer", QUIC_EV_CONN_LPKT, qc);
+ return 0;
+ }
+
+ /* mux-quic can now be considered ready. */
+ qc->mux_state = QC_MUX_READY;
+
tasklet_wakeup(qctx->wait_event.tasklet);
return 1;
}