MINOR: quic: refactor DCID lookup

A new function named qc_retrieve_conn_from_cid() now contains all the
code to retrieve a connection from a DCID. It handle all type of packets
and centralize the locking on the ODCID/DCID trees.

This simplify the qc_lstnr_pkt_rcv() function.
diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h
index a572aac..4651f01 100644
--- a/include/haproxy/xprt_quic-t.h
+++ b/include/haproxy/xprt_quic-t.h
@@ -631,8 +631,8 @@
 	size_t enc_params_len;
 
 	/*
-	 * Original Destination Connection ID  (coming with first client Initial packets).
-	 * Used only by servers.
+	 * Original DCID used by clients on first Initial packets.
+	 * <odcid> is concatenated with the socket src address.
 	 */
 	struct ebmb_node odcid_node;
 	struct quic_cid odcid;
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index ecc2a2f..8e0234f 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -3881,6 +3881,61 @@
 	return 0;
 }
 
+/* Retrieve a quic_conn instance from the <pkt> DCID field. If the packet is of
+ * type INITIAL, the ODCID tree is first used. In this case, <saddr> is
+ * concatenated to the <pkt> DCID field.
+ *
+ * Returns the instance or NULL if not found.
+ */
+static struct quic_conn *qc_retrieve_conn_from_cid(struct quic_rx_packet *pkt,
+                                                   struct listener *l,
+                                                   struct sockaddr_storage *saddr)
+{
+	struct quic_conn *qc = NULL;
+	struct ebmb_node *node;
+	struct quic_connection_id *id;
+
+	HA_RWLOCK_RDLOCK(QUIC_LOCK, &l->rx.cids_lock);
+
+	/* Look first into ODCIDs tree for INITIAL/0-RTT packets. */
+	if (pkt->type == QUIC_PACKET_TYPE_INITIAL ||
+	    pkt->type == QUIC_PACKET_TYPE_0RTT) {
+		/* DCIDs of first packets coming from multiple clients may have
+		 * the same values. Let's distinguish them by concatenating the
+		 * socket addresses.
+		 */
+		quic_cid_saddr_cat(&pkt->dcid, saddr);
+		node = ebmb_lookup(&l->rx.odcids, pkt->dcid.data,
+		                   pkt->dcid.len + pkt->dcid.addrlen);
+		if (node) {
+			qc = ebmb_entry(node, struct quic_conn, odcid_node);
+			goto end;
+		}
+	}
+
+	/* Look into DCIDs tree for non-INITIAL/0-RTT packets. This may be used
+	 * also for INITIAL/0-RTT non-first packets with the final DCID in
+	 * used.
+	 */
+	node = ebmb_lookup(&l->rx.cids, pkt->dcid.data, pkt->dcid.len);
+	if (!node)
+		goto end;
+
+	id = ebmb_entry(node, struct quic_connection_id, node);
+	qc = id->qc;
+
+	/* If found in DCIDs tree, remove the quic_conn from the ODCIDs tree.
+	 * If already done, this is a noop.
+	 */
+	if (HA_ATOMIC_BTR(&qc->flags, QUIC_FL_CONN_ODCID_NODE_TO_DELETE_BIT))
+		ebmb_delete(&qc->odcid_node);
+
+ end:
+	HA_RWLOCK_RDUNLOCK(QUIC_LOCK, &l->rx.cids_lock);
+
+	return qc;
+}
+
 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,
@@ -3888,9 +3943,6 @@
 {
 	unsigned char *beg;
 	struct quic_conn *qc;
-	struct eb_root *cids;
-	unsigned char dcid_lookup_len;
-	struct ebmb_node *node;
 	struct listener *l;
 	struct ssl_sock_ctx *conn_ctx;
 	int long_header = 0;
@@ -3948,41 +4000,29 @@
 		/* For Initial packets, and for servers (QUIC clients connections),
 		 * there is no Initial connection IDs storage.
 		 */
-		if (pkt->type == QUIC_PACKET_TYPE_INITIAL ||
-		    pkt->type == QUIC_PACKET_TYPE_0RTT) {
+		if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
 			uint64_t token_len;
-			/* DCIDs of first packets coming from clients may have the same values.
-			 * Let's distinguish them concatenating the socket addresses to the DCIDs.
-			 */
-			quic_cid_saddr_cat(&pkt->dcid, saddr);
-			cids = &l->rx.odcids;
-			dcid_lookup_len = pkt->dcid.len + pkt->dcid.addrlen;
 
-			if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
-				if (!quic_dec_int(&token_len, (const unsigned char **)buf, end) ||
-					end - *buf < token_len) {
-					TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
-					goto err;
-				}
-
-				/* XXX TO DO XXX 0 value means "the token is not present".
-				 * A server which sends an Initial packet must not set the token.
-				 * So, a client which receives an Initial packet with a token
-				 * MUST discard the packet or generate a connection error with
-				 * PROTOCOL_VIOLATION as type.
-				 * The token must be provided in a Retry packet or NEW_TOKEN frame.
-				 */
-				pkt->token_len = token_len;
+			if (!quic_dec_int(&token_len, (const unsigned char **)buf, end) ||
+				end - *buf < token_len) {
+				TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
+				goto err;
 			}
+
+			/* XXX TO DO XXX 0 value means "the token is not present".
+			 * A server which sends an Initial packet must not set the token.
+			 * So, a client which receives an Initial packet with a token
+			 * MUST discard the packet or generate a connection error with
+			 * PROTOCOL_VIOLATION as type.
+			 * The token must be provided in a Retry packet or NEW_TOKEN frame.
+			 */
+			pkt->token_len = token_len;
 		}
-		else {
+		else if (pkt->type != QUIC_PACKET_TYPE_0RTT) {
 			if (pkt->dcid.len != QUIC_HAP_CID_LEN) {
 				TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
 				goto err;
 			}
-
-			cids = &l->rx.cids;
-			dcid_lookup_len = pkt->dcid.len;
 		}
 
 		/* Only packets packets with long headers and not RETRY or VERSION as type
@@ -3999,22 +4039,9 @@
 
 			pkt->len = len;
 		}
-
-
-		HA_RWLOCK_RDLOCK(OTHER_LOCK, &l->rx.cids_lock);
-		node = ebmb_lookup(cids, pkt->dcid.data, dcid_lookup_len);
-		if (!node && pkt->type == QUIC_PACKET_TYPE_INITIAL &&
-		    pkt->dcid.len == QUIC_HAP_CID_LEN && cids == &l->rx.odcids) {
-			/* Switch to the definitive tree ->cids containing the final CIDs. */
-			node = ebmb_lookup(&l->rx.cids, pkt->dcid.data, pkt->dcid.len);
-			if (node) {
-				/* If found, signal this with NULL as special value for <cids>. */
-				cids = NULL;
-			}
-		}
-		HA_RWLOCK_RDUNLOCK(OTHER_LOCK, &l->rx.cids_lock);
 
-		if (!node) {
+		qc = qc_retrieve_conn_from_cid(pkt, l, saddr);
+		if (!qc) {
 			int ipv4;
 			struct quic_cid *odcid;
 			struct ebmb_node *n = NULL;
@@ -4085,56 +4112,24 @@
 				/* Try to accept a new connection. */
 				listener_accept(l);
 			}
-
-			/* This is the DCID node sent in this packet by the client. */
-			node = &qc->odcid_node;
 		}
 		else {
-			if ((pkt->type == QUIC_PACKET_TYPE_INITIAL ||
-			     pkt->type == QUIC_PACKET_TYPE_0RTT) && cids == &l->rx.odcids) {
-				qc = ebmb_entry(node, struct quic_conn, odcid_node);
-			}
-			else {
-				struct quic_connection_id *cid = ebmb_entry(node, struct quic_connection_id, node);
-				qc = cid->qc;
-				if (HA_ATOMIC_BTR(&qc->flags, QUIC_FL_CONN_ODCID_NODE_TO_DELETE_BIT)) {
-					/* Delete the ODCID from its tree */
-					HA_RWLOCK_WRLOCK(QUIC_LOCK, &l->rx.cids_lock);
-					ebmb_delete(&qc->odcid_node);
-					HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &l->rx.cids_lock);
-				}
-			}
 			pkt->qc = qc;
 			if (HA_ATOMIC_LOAD(&qc->conn))
 				conn_ctx = HA_ATOMIC_LOAD(&qc->conn->xprt_ctx);
 		}
 	}
 	else {
-		struct quic_connection_id *cid;
-
 		if (end - *buf < QUIC_HAP_CID_LEN) {
 			TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
 			goto err;
 		}
 
-		cids = &l->rx.cids;
-
-		HA_RWLOCK_RDLOCK(QUIC_LOCK, &l->rx.cids_lock);
-		node = ebmb_lookup(cids, *buf, QUIC_HAP_CID_LEN);
-		if (!node) {
-			HA_RWLOCK_RDUNLOCK(QUIC_LOCK, &l->rx.cids_lock);
-			TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
-			goto err;
-		}
-
-		cid = ebmb_entry(node, struct quic_connection_id, node);
-		qc = cid->qc;
-		HA_RWLOCK_RDUNLOCK(QUIC_LOCK, &l->rx.cids_lock);
-
 		memcpy(pkt->dcid.data, *buf, QUIC_HAP_CID_LEN);
 		pkt->dcid.len = QUIC_HAP_CID_LEN;
 		*buf += QUIC_HAP_CID_LEN;
 
+		qc = qc_retrieve_conn_from_cid(pkt, l, saddr);
 		if (HA_ATOMIC_LOAD(&qc->conn))
 			conn_ctx = HA_ATOMIC_LOAD(&qc->conn->xprt_ctx);