MEDIUM: mux-quic: implement release mux operation

Implement qc_release. This function is called by the upper layer on
connection close. For the moment, this only happens on client timeout.

This functions is used the free a qcs instance. If all bidirectional
streams are freed, the qcc instance and the connection are purged.
diff --git a/src/mux_quic.c b/src/mux_quic.c
index 774612b..bdf57e5 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -215,9 +215,75 @@
 	return -1;
 }
 
+/* detachs the QUIC stream from its QCC and releases it to the QCS pool. */
+static void qcs_destroy(struct qcs *qcs)
+{
+	fprintf(stderr, "%s: release stream %llu\n", __func__, qcs->by_id.key);
+
+	eb64_delete(&qcs->by_id);
+
+	b_free(&qcs->rx.buf);
+	b_free(&qcs->tx.buf);
+	b_free(&qcs->tx.xprt_buf);
+
+	--qcs->qcc->strms[qcs_id_type(qcs->by_id.key)].nb_streams;
+
+	pool_free(pool_head_qcs, qcs);
+}
+
+static inline int qcc_is_dead(const struct qcc *qcc)
+{
+	fprintf(stderr, "%s: %lu\n", __func__, qcc->strms[QCS_CLT_BIDI].nb_streams);
+
+	if (!qcc->strms[QCS_CLT_BIDI].nb_streams)
+		return 1;
+
+	return 0;
+}
+
+/* release function. This one should be called to free all resources allocated
+ * to the mux.
+ */
+static void qc_release(struct qcc *qcc)
+{
+	struct connection *conn = NULL;
+
+	if (qcc) {
+		/* The connection must be aattached to this mux to be released */
+		if (qcc->conn && qcc->conn->ctx == qcc)
+			conn = qcc->conn;
+
+		if (qcc->wait_event.tasklet)
+			tasklet_free(qcc->wait_event.tasklet);
+
+		pool_free(pool_head_qcc, qcc);
+	}
+
+	if (conn) {
+		conn->mux = NULL;
+		conn->ctx = NULL;
+
+		conn_stop_tracking(conn);
+		conn_full_close(conn);
+		if (conn->destroy_cb)
+			conn->destroy_cb(conn);
+		conn_free(conn);
+	}
+}
+
 static void qc_detach(struct conn_stream *cs)
 {
-	/* XXX TO DO XXX */
+	struct qcs *qcs = cs->ctx;
+	struct qcc *qcc = qcs->qcc;
+
+	fprintf(stderr, "%s: leaving with tx.buf.data=%lu, tx.xprt_buf.data=%lu\n",
+	        __func__, b_data(&qcs->tx.buf), b_data(&qcs->tx.xprt_buf));
+
+	qcs_destroy(qcs);
+	if (qcc_is_dead(qcc)) {
+		qc_release(qcc);
+		return;
+	}
 }
 
 /* Called from the upper layer, to receive data */