REORG: quic: use a dedicated module for qc_stream_desc

Regroup all type definitions and functions related to qc_stream_desc in
the source file src/quic_stream.c.

qc_stream_desc complexity will be increased with the development of Tx
multi-buffers. Having a dedicated module is useful to mix it with
pure transport/quic-conn code.
diff --git a/Makefile b/Makefile
index fd1caa2..7c7d26a 100644
--- a/Makefile
+++ b/Makefile
@@ -636,7 +636,8 @@
 OPTIONS_OBJS += src/quic_sock.o src/proto_quic.o src/xprt_quic.o src/quic_tls.o \
                 src/quic_frame.o src/quic_cc.o src/quic_cc_newreno.o src/mux_quic.o \
                 src/cbuf.o src/qpack-dec.o src/qpack-tbl.o src/h3.o src/qpack-enc.o \
-                src/hq_interop.o src/cfgparse-quic.o src/quic_loss.o
+                src/hq_interop.o src/cfgparse-quic.o src/quic_loss.o \
+                src/quic_stream.o
 endif
 
 ifneq ($(USE_LUA),)
diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h
index 6fa9522..f9b8b2f 100644
--- a/include/haproxy/mux_quic-t.h
+++ b/include/haproxy/mux_quic-t.h
@@ -10,6 +10,7 @@
 
 #include <haproxy/buf-t.h>
 #include <haproxy/connection-t.h>
+#include <haproxy/quic_stream-t.h>
 #include <haproxy/xprt_quic-t.h>
 #include <haproxy/conn_stream-t.h>
 
diff --git a/include/haproxy/quic_stream-t.h b/include/haproxy/quic_stream-t.h
new file mode 100644
index 0000000..6a451ac
--- /dev/null
+++ b/include/haproxy/quic_stream-t.h
@@ -0,0 +1,32 @@
+#ifndef _HAPROXY_QUIC_STREAM_T_H_
+#define _HAPROXY_QUIC_STREAM_T_H_
+
+#ifdef USE_QUIC
+
+#include <import/ebtree-t.h>
+
+#include <haproxy/buf-t.h>
+
+/* QUIC STREAM descriptor.
+ *
+ * This structure is the low-level counterpart of the QUIC STREAM at the MUX
+ * layer. It provides a node for tree-storage and buffering for Tx.
+ *
+ * Once the MUX has finished to transfer data on a STREAM, it must release its
+ * QUIC STREAM descriptor. The descriptor will be kept by the quic_conn until
+ * all acknowledgement has been received.
+ */
+struct qc_stream_desc {
+	struct eb64_node by_id; /* id of the stream used for <streams_by_id> tree */
+
+	struct buffer buf; /* buffer for STREAM data on Tx, emptied on acknowledge */
+	uint64_t ack_offset; /* last acknowledged offset */
+	struct eb_root acked_frms; /* ACK frames tree for non-contiguous ACK ranges */
+
+	int release; /* set to 1 when the MUX has finished to use this stream */
+
+	void *ctx; /* MUX specific context */
+};
+
+#endif /* USE_QUIC */
+#endif /* _HAPROXY_QUIC_STREAM_T_H_ */
diff --git a/include/haproxy/quic_stream.h b/include/haproxy/quic_stream.h
new file mode 100644
index 0000000..c524d10
--- /dev/null
+++ b/include/haproxy/quic_stream.h
@@ -0,0 +1,16 @@
+#ifndef _HAPROXY_QUIC_STREAM_H_
+#define _HAPROXY_QUIC_STREAM_H_
+
+#ifdef USE_QUIC
+
+#include <haproxy/quic_stream-t.h>
+
+struct quic_conn;
+
+struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx);
+void qc_stream_desc_release(struct qc_stream_desc *stream,
+                            struct quic_conn *qc);
+int qc_stream_desc_free(struct qc_stream_desc *stream);
+
+#endif /* USE_QUIC */
+#endif /* _HAPROXY_QUIC_STREAM_H_ */
diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h
index e2999a5..2478332 100644
--- a/include/haproxy/xprt_quic-t.h
+++ b/include/haproxy/xprt_quic-t.h
@@ -767,26 +767,5 @@
 	const struct qcc_app_ops *app_ops;
 };
 
-/* QUIC STREAM descriptor.
- *
- * This structure is the low-level counterpart of the QUIC STREAM at the MUX
- * layer. It provides a node for tree-storage and buffering for Tx.
- *
- * Once the MUX has finished to transfer data on a STREAM, it must release its
- * QUIC STREAM descriptor. The descriptor will be kept by the quic_conn until
- * all acknowledgement has been received.
- */
-struct qc_stream_desc {
-	struct eb64_node by_id; /* id of the stream used for <streams_by_id> tree */
-
-	struct buffer buf; /* buffer for STREAM data on Tx, emptied on acknowledge */
-	uint64_t ack_offset; /* last acknowledged offset */
-	struct eb_root acked_frms; /* ACK frames tree for non-contiguous ACK ranges */
-
-	int release; /* set to 1 when the MUX has finished to use this stream */
-
-	void *ctx; /* MUX specific context */
-};
-
 #endif /* USE_QUIC */
 #endif /* _HAPROXY_XPRT_QUIC_T_H */
diff --git a/include/haproxy/xprt_quic.h b/include/haproxy/xprt_quic.h
index 94488b0..1a2a3ce 100644
--- a/include/haproxy/xprt_quic.h
+++ b/include/haproxy/xprt_quic.h
@@ -1248,9 +1248,6 @@
                               struct quic_dgram *new_dgram, struct list *dgrams);
 int qc_send_app_pkts(struct quic_conn *qc, struct list *frms);
 
-struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx);
-void qc_stream_desc_release(struct qc_stream_desc *stream, struct quic_conn *qc);
-
 void qc_notify_close(struct quic_conn *qc);
 
 #endif /* USE_QUIC */
diff --git a/src/mux_quic.c b/src/mux_quic.c
index d51bed1..642da72 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -8,6 +8,7 @@
 #include <haproxy/dynbuf.h>
 #include <haproxy/htx.h>
 #include <haproxy/pool.h>
+#include <haproxy/quic_stream.h>
 #include <haproxy/sink.h>
 #include <haproxy/ssl_sock-t.h>
 #include <haproxy/trace.h>
diff --git a/src/quic_stream.c b/src/quic_stream.c
new file mode 100644
index 0000000..4213e50
--- /dev/null
+++ b/src/quic_stream.c
@@ -0,0 +1,99 @@
+#include <haproxy/quic_stream.h>
+
+#include <import/eb64tree.h>
+
+#include <haproxy/api.h>
+#include <haproxy/buf.h>
+#include <haproxy/list.h>
+#include <haproxy/dynbuf.h>
+#include <haproxy/pool.h>
+#include <haproxy/xprt_quic.h>
+
+DECLARE_STATIC_POOL(pool_head_quic_conn_stream, "qc_stream_desc",
+                    sizeof(struct qc_stream_desc));
+
+/* Allocate a new stream descriptor with id <id>. The caller is responsible to
+ * store the stream in the appropriate tree.
+ *
+ * Returns the newly allocated instance on success or else NULL.
+ */
+struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx)
+{
+	struct qc_stream_desc *stream;
+
+	stream = pool_alloc(pool_head_quic_conn_stream);
+	if (!stream)
+		return NULL;
+
+	stream->by_id.key = id;
+	stream->by_id.node.leaf_p = NULL;
+
+	stream->buf = BUF_NULL;
+	stream->acked_frms = EB_ROOT;
+	stream->ack_offset = 0;
+	stream->release = 0;
+	stream->ctx = ctx;
+
+	return stream;
+}
+
+/* Mark the stream descriptor <stream> as released by the upper layer. It will
+ * be freed as soon as all its buffered data are acknowledged. In the meantime,
+ * the stream is stored in the <qc> tree : thus it must have been removed from
+ * any other tree before calling this function.
+ */
+void qc_stream_desc_release(struct qc_stream_desc *stream,
+                            struct quic_conn *qc)
+{
+	BUG_ON(stream->by_id.node.leaf_p);
+
+	stream->release = 1;
+	stream->ctx = NULL;
+
+	if (!b_data(&stream->buf))
+		qc_stream_desc_free(stream);
+	else
+		eb64_insert(&qc->streams_by_id, &stream->by_id);
+}
+
+/* Free the stream descriptor <stream> buffer. This function should be used
+ * when all its data have been acknowledged. If the stream was released by the
+ * upper layer, the stream descriptor will be freed.
+ *
+ * Returns 0 if the stream was not freed else non-zero.
+ */
+int qc_stream_desc_free(struct qc_stream_desc *stream)
+{
+	b_free(&stream->buf);
+	offer_buffers(NULL, 1);
+
+	if (stream->release) {
+		/* Free frames still waiting for an ACK. Even if the stream buf
+		 * is NULL, some frames could still be not acknowledged. This
+		 * is notably the case for retransmission where multiple frames
+		 * points to the same buffer content.
+		 */
+		struct eb64_node *frm_node = eb64_first(&stream->acked_frms);
+		while (frm_node) {
+			struct quic_stream *strm;
+			struct quic_frame *frm;
+
+			strm = eb64_entry(&frm_node->node, struct quic_stream, offset);
+
+			frm_node = eb64_next(frm_node);
+			eb64_delete(&strm->offset);
+
+			frm = container_of(strm, struct quic_frame, stream);
+			LIST_DELETE(&frm->list);
+			quic_tx_packet_refdec(frm->pkt);
+			pool_free(pool_head_quic_frame, frm);
+		}
+
+		eb64_delete(&stream->by_id);
+		pool_free(pool_head_quic_conn_stream, stream);
+
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index 36b21e2..fde571d 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -45,6 +45,7 @@
 #include <haproxy/quic_frame.h>
 #include <haproxy/quic_loss.h>
 #include <haproxy/quic_sock.h>
+#include <haproxy/quic_stream.h>
 #include <haproxy/cbuf.h>
 #include <haproxy/proto_quic.h>
 #include <haproxy/quic_tls.h>
@@ -169,7 +170,6 @@
 DECLARE_STATIC_POOL(pool_head_quic_crypto_buf, "quic_crypto_buf_pool", sizeof(struct quic_crypto_buf));
 DECLARE_POOL(pool_head_quic_frame, "quic_frame_pool", sizeof(struct quic_frame));
 DECLARE_STATIC_POOL(pool_head_quic_arng, "quic_arng_pool", sizeof(struct quic_arng_node));
-DECLARE_STATIC_POOL(pool_head_quic_conn_stream, "qc_stream_desc", sizeof(struct qc_stream_desc));
 
 static struct quic_tx_packet *qc_build_pkt(unsigned char **pos, const unsigned char *buf_end,
                                            struct quic_enc_level *qel, struct list *frms,
@@ -1429,48 +1429,6 @@
 	return 1;
 }
 
-/* Free the stream descriptor <stream> buffer. This function should be used
- * when all its data have been acknowledged. If the stream was released by the
- * upper layer, the stream descriptor will be freed.
- *
- * Returns 0 if the stream was not freed else non-zero.
- */
-static int qc_stream_desc_free(struct qc_stream_desc *stream)
-{
-	b_free(&stream->buf);
-	offer_buffers(NULL, 1);
-
-	if (stream->release) {
-		/* Free frames still waiting for an ACK. Even if the stream buf
-		 * is NULL, some frames could still be not acknowledged. This
-		 * is notably the case for retransmission where multiple frames
-		 * points to the same buffer content.
-		 */
-		struct eb64_node *frm_node = eb64_first(&stream->acked_frms);
-		while (frm_node) {
-			struct quic_stream *strm;
-			struct quic_frame *frm;
-
-			strm = eb64_entry(&frm_node->node, struct quic_stream, offset);
-
-			frm_node = eb64_next(frm_node);
-			eb64_delete(&strm->offset);
-
-			frm = container_of(strm, struct quic_frame, stream);
-			LIST_DELETE(&frm->list);
-			quic_tx_packet_refdec(frm->pkt);
-			pool_free(pool_head_quic_frame, frm);
-		}
-
-		eb64_delete(&stream->by_id);
-		pool_free(pool_head_quic_conn_stream, stream);
-
-		return 1;
-	}
-
-	return 0;
-}
-
 /* Remove from <stream> the acknowledged frames.
  *
  * Returns 1 if at least one frame was removed else 0.
@@ -5956,50 +5914,6 @@
 	return 0;
 }
 
-/* Allocate a new stream descriptor with id <id>. The caller is responsible to
- * store the stream in the appropriate tree.
- *
- * Returns the newly allocated instance on success or else NULL.
- */
-struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx)
-{
-	struct qc_stream_desc *stream;
-
-	stream = pool_alloc(pool_head_quic_conn_stream);
-	if (!stream)
-		return NULL;
-
-	stream->by_id.key = id;
-	stream->by_id.node.leaf_p = NULL;
-
-	stream->buf = BUF_NULL;
-	stream->acked_frms = EB_ROOT;
-	stream->ack_offset = 0;
-	stream->release = 0;
-	stream->ctx = ctx;
-
-	return stream;
-}
-
-/* Mark the stream descriptor <stream> as released by the upper layer. It will
- * be freed as soon as all its buffered data are acknowledged. In the meantime,
- * the stream is stored in the <qc> tree : thus it must have been removed from
- * any other tree before calling this function.
- */
-void qc_stream_desc_release(struct qc_stream_desc *stream,
-                            struct quic_conn *qc)
-{
-	BUG_ON(stream->by_id.node.leaf_p);
-
-	stream->release = 1;
-	stream->ctx = NULL;
-
-	if (!b_data(&stream->buf))
-		qc_stream_desc_free(stream);
-	else
-		eb64_insert(&qc->streams_by_id, &stream->by_id);
-}
-
 /* Notify the MUX layer if alive about an imminent close of <qc>. */
 void qc_notify_close(struct quic_conn *qc)
 {