MINOR: quic: initialize ssl_sock_ctx alongside the quic_conn

Extract the allocation of ssl_sock_ctx from qc_conn_init to a dedicated
function qc_conn_alloc_ssl_ctx. This function is called just after
allocating a new quic_conn, without waiting for the initialization of
the connection. It allocates the ssl_sock_ctx and the quic_conn tasklet.

This change is now possible because the SSL callbacks are dealing with a
quic_conn instance.

This change is required to be able to delay the connection allocation
and handle handshake packets without it.
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index 71d3b47..4ece434 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -4250,6 +4250,110 @@
 	return 0;
 }
 
+/* Try to allocate the <*ssl> SSL session object for <qc> QUIC connection
+ * with <ssl_ctx> as SSL context inherited settings. Also set the transport
+ * parameters of this session.
+ * This is the responsibility of the caller to check the validity of all the
+ * pointers passed as parameter to this function.
+ * Return 0 if succeeded, -1 if not. If failed, sets the ->err_code member of <qc->conn> to
+ * CO_ER_SSL_NO_MEM.
+ */
+static int qc_ssl_sess_init(struct quic_conn *qc, SSL_CTX *ssl_ctx, SSL **ssl,
+                            unsigned char *params, size_t params_len)
+{
+	int retry;
+
+	retry = 1;
+ retry:
+	*ssl = SSL_new(ssl_ctx);
+	if (!*ssl) {
+		if (!retry--)
+			goto err;
+
+		pool_gc(NULL);
+		goto retry;
+	}
+
+	if (!SSL_set_quic_method(*ssl, &ha_quic_method) ||
+	    !SSL_set_ex_data(*ssl, ssl_qc_app_data_index, qc) ||
+	    !SSL_set_quic_transport_params(*ssl, qc->enc_params, qc->enc_params_len)) {
+			goto err;
+
+		SSL_free(*ssl);
+		*ssl = NULL;
+		if (!retry--)
+			goto err;
+
+		pool_gc(NULL);
+		goto retry;
+	}
+
+	return 0;
+
+ err:
+	qc->conn->err_code = CO_ER_SSL_NO_MEM;
+	return -1;
+}
+
+/* Allocate the ssl_sock_ctx from connection <qc>. This creates the tasklet
+ * used to process <qc> received packets. The allocated context is stored in
+ * <qc.xprt_ctx>.
+ *
+ * Returns 0 on success else non-zero.
+ */
+int qc_conn_alloc_ssl_ctx(struct quic_conn *qc)
+{
+	struct bind_conf *bc = qc->li->bind_conf;
+	struct ssl_sock_ctx *ctx = NULL;
+
+	ctx = pool_zalloc(pool_head_quic_conn_ctx);
+	if (!ctx)
+		goto err;
+
+	ctx->wait_event.tasklet = tasklet_new();
+	if (!ctx->wait_event.tasklet)
+		goto err;
+
+	ctx->wait_event.tasklet->process = quic_conn_io_cb;
+	ctx->wait_event.tasklet->context = ctx;
+	ctx->wait_event.events = 0;
+	ctx->subs = NULL;
+	ctx->xprt_ctx = NULL;
+	ctx->qc = qc;
+
+	/* Set tasklet tid based on the SCID selected by us for this
+	 * connection. The upper layer will also be binded on the same thread.
+	 */
+	qc->tid = ctx->wait_event.tasklet->tid = quic_get_cid_tid(&qc->scid);
+
+	if (qc_is_listener(qc)) {
+		if (qc_ssl_sess_init(qc, bc->initial_ctx, &ctx->ssl,
+		                     qc->enc_params, qc->enc_params_len) == -1) {
+		        goto err;
+		}
+
+		/* Enabling 0-RTT */
+		if (bc->ssl_conf.early_data)
+			SSL_set_quic_early_data_enabled(ctx->ssl, 1);
+
+		SSL_set_accept_state(ctx->ssl);
+	}
+
+	ctx->xprt = xprt_get(XPRT_QUIC);
+
+	/* Store the allocated context in <qc>. */
+	HA_ATOMIC_STORE(&qc->xprt_ctx, ctx);
+
+	return 0;
+
+ err:
+	if (ctx && ctx->wait_event.tasklet)
+		tasklet_free(ctx->wait_event.tasklet);
+	pool_free(pool_head_quic_conn_ctx, ctx);
+
+	return 1;
+}
+
 static ssize_t qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
                                 struct quic_rx_packet *pkt,
                                 struct quic_dgram_ctx *dgram_ctx,
@@ -4414,6 +4518,9 @@
 			if (!qc->enc_params_len)
 				goto err;
 
+			if (qc_conn_alloc_ssl_ctx(qc))
+				goto err;
+
 			/* NOTE: the socket address has been concatenated to the destination ID
 			 * chosen by the client for Initial packets.
 			 */
@@ -5356,178 +5463,28 @@
 	return conn_unsubscribe(conn, xprt_ctx, event_type, es);
 }
 
-/* Try to allocate the <*ssl> SSL session object for <qc> QUIC connection
- * with <ssl_ctx> as SSL context inherited settings. Also set the transport
- * parameters of this session.
- * This is the responsibility of the caller to check the validity of all the
- * pointers passed as parameter to this function.
- * Return 0 if succeeded, -1 if not. If failed, sets the ->err_code member of <qc->conn> to
- * CO_ER_SSL_NO_MEM.
- */
-static int qc_ssl_sess_init(struct quic_conn *qc, SSL_CTX *ssl_ctx, SSL **ssl,
-                            unsigned char *params, size_t params_len)
-{
-	int retry;
-
-	retry = 1;
- retry:
-	*ssl = SSL_new(ssl_ctx);
-	if (!*ssl) {
-		if (!retry--)
-			goto err;
-
-		pool_gc(NULL);
-		goto retry;
-	}
-
-	if (!SSL_set_quic_method(*ssl, &ha_quic_method) ||
-	    !SSL_set_ex_data(*ssl, ssl_qc_app_data_index, qc) ||
-	    !SSL_set_quic_transport_params(*ssl, qc->enc_params, qc->enc_params_len)) {
-			goto err;
-
-		SSL_free(*ssl);
-		*ssl = NULL;
-		if (!retry--)
-			goto err;
-
-		pool_gc(NULL);
-		goto retry;
-	}
-
-	return 0;
-
- err:
-	qc->conn->err_code = CO_ER_SSL_NO_MEM;
-	return -1;
-}
-
-/* Initialize a QUIC connection (quic_conn struct) to be attached to <conn>
- * connection with <xprt_ctx> as address of the xprt context.
- * Returns 1 if succeeded, 0 if not.
+/* Store in <xprt_ctx> the context attached to <conn>.
+ * Returns always 0.
  */
 static int qc_conn_init(struct connection *conn, void **xprt_ctx)
 {
-	struct ssl_sock_ctx *ctx = NULL;
 	struct quic_conn *qc = NULL;
 
 	TRACE_ENTER(QUIC_EV_CONN_NEW, conn);
 
+	/* do not store the context if already set */
 	if (*xprt_ctx)
 		goto out;
 
-	ctx = pool_zalloc(pool_head_quic_conn_ctx);
-	if (!ctx) {
-		conn->err_code = CO_ER_SYS_MEMLIM;
-		goto err;
-	}
-
-	ctx->wait_event.tasklet = tasklet_new();
-	if (!ctx->wait_event.tasklet) {
-		conn->err_code = CO_ER_SYS_MEMLIM;
-		goto err;
-	}
-
-	ctx->wait_event.tasklet->process = quic_conn_io_cb;
-	ctx->wait_event.tasklet->context = ctx;
-	ctx->wait_event.events = 0;
-	HA_ATOMIC_STORE(&ctx->conn, conn);
-	ctx->subs = NULL;
-	ctx->xprt_ctx = NULL;
-
-	ctx->xprt = xprt_get(XPRT_QUIC);
-	if (objt_server(conn->target)) {
-		/* Server */
-		struct server *srv = __objt_server(conn->target);
-		unsigned char dcid[QUIC_HAP_CID_LEN];
-		int ssl_err, ipv4;
-
-		ssl_err = SSL_ERROR_NONE;
-		if (RAND_bytes(dcid, sizeof dcid) != 1)
-			goto err;
-
-		ipv4 = conn->dst->ss_family == AF_INET;
-		qc = qc_new_conn(QUIC_PROTOCOL_VERSION_DRAFT_28, ipv4,
-		                 dcid, sizeof dcid, 0, NULL, 0, 0, srv);
-		if (qc == NULL)
-			goto err;
-
-		ctx->qc = qc;
-
-		/* Insert our SCID, the connection ID for the QUIC client. */
-		ebmb_insert(&srv->cids, &qc->scid_node, qc->scid.len);
-
-		conn->qc = qc;
-		qc->conn = conn;
-		if (!qc_new_isecs(qc, initial_salt_v1, sizeof initial_salt_v1,
-		                  dcid, sizeof dcid, 0))
-			goto err;
-
-		qc->rx.params = srv->quic_params;
-		/* Copy the initial source connection ID. */
-		quic_cid_cpy(&qc->rx.params.initial_source_connection_id, &qc->scid);
-		qc->enc_params_len =
-			quic_transport_params_encode(qc->enc_params, qc->enc_params + sizeof qc->enc_params,
-			                             &qc->rx.params, 0);
-		if (!qc->enc_params_len)
-			goto err;
-
-		if (qc_ssl_sess_init(qc, srv->ssl_ctx.ctx, &ctx->ssl,
-		                     qc->enc_params, qc->enc_params_len) == -1)
-			goto err;
-
-		SSL_set_quic_transport_params(ctx->ssl, qc->enc_params, qc->enc_params_len);
-		SSL_set_connect_state(ctx->ssl);
-		ssl_err = SSL_do_handshake(ctx->ssl);
-		if (ssl_err != 1) {
-			int st;
-
-			st = HA_ATOMIC_LOAD(&qc->state);
-			ssl_err = SSL_get_error(ctx->ssl, ssl_err);
-			if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
-				TRACE_PROTO("SSL handshake", QUIC_EV_CONN_HDSHK, qc, &st, &ssl_err);
-			}
-			else {
-				TRACE_DEVEL("SSL handshake error", QUIC_EV_CONN_HDSHK, qc, &st, &ssl_err);
-				goto err;
-			}
-		}
-	}
-	else if (objt_listener(conn->target)) {
-		/* Listener */
-		struct bind_conf *bc = __objt_listener(conn->target)->bind_conf;
-
-		qc = ctx->conn->qc;
-		ctx->qc = qc;
-
-		qc->tid = ctx->wait_event.tasklet->tid = quic_get_cid_tid(&qc->scid);
-		if (qc_ssl_sess_init(qc, bc->initial_ctx, &ctx->ssl,
-		                     qc->enc_params, qc->enc_params_len) == -1)
-			goto err;
-
-		/* Enabling 0-RTT */
-		if (bc->ssl_conf.early_data)
-			SSL_set_quic_early_data_enabled(ctx->ssl, 1);
-
-		SSL_set_accept_state(ctx->ssl);
-	}
-
-	HA_ATOMIC_STORE(xprt_ctx, ctx);
+	HA_ATOMIC_STORE(xprt_ctx, conn->qc->xprt_ctx);
 
 	/* Leave init state and start handshake */
 	conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
 
  out:
-	HA_ATOMIC_STORE(&qc->xprt_ctx, ctx);
 	TRACE_LEAVE(QUIC_EV_CONN_NEW, qc);
 
 	return 0;
-
- err:
-	if (ctx && ctx->wait_event.tasklet)
-		tasklet_free(ctx->wait_event.tasklet);
-	pool_free(pool_head_quic_conn_ctx, ctx);
-	TRACE_DEVEL("leaving in error", QUIC_EV_CONN_NEW, conn);
-	return -1;
 }
 
 /* Start the QUIC transport layer */