goto out;
/* allocate transport layer stream descriptor */
- stream = qc_stream_desc_new(qcc->conn->qc, id, qcs);
+ stream = qc_stream_desc_new(id, qcs);
if (!stream) {
pool_free(pool_head_qcs, qcs);
qcs = NULL;
qcs->cs = NULL;
qcs->flags = QC_SF_NONE;
- qcs->by_id.key = id;
- eb64_insert(&qcc->streams_by_id, &qcs->by_id);
+ qcs->id = id;
+ /* store transport layer stream descriptor in qcc tree */
+ eb64_insert(&qcc->streams_by_id, &stream->by_id);
qcc->strms[type].nb_streams++;
/* If stream is local, use peer remote-limit, or else the opposite. */
b_free(&qcs->rx.buf);
b_free(&qcs->tx.buf);
- BUG_ON(!qcs->qcc->strms[qcs_id_type(qcs->by_id.key)].nb_streams);
- --qcs->qcc->strms[qcs_id_type(qcs->by_id.key)].nb_streams;
+ BUG_ON(!qcs->qcc->strms[qcs_id_type(qcs->id)].nb_streams);
+ --qcs->qcc->strms[qcs_id_type(qcs->id)].nb_streams;
- qc_stream_desc_release(qcs->stream);
-
- eb64_delete(&qcs->by_id);
+ /* stream desc must be removed from MUX tree before release it */
+ eb64_delete(&qcs->stream->by_id);
+ qc_stream_desc_release(qcs->stream, qcs->qcc->conn->qc);
pool_free(pool_head_qcs, qcs);
}
*/
struct qcs *qcc_get_qcs(struct qcc *qcc, uint64_t id)
{
+ struct qc_stream_desc *stream;
unsigned int strm_type;
int64_t sub_id;
struct eb64_node *strm_node;
/* unknown stream id */
goto out;
}
- qcs = eb64_entry(strm_node, struct qcs, by_id);
+ stream = eb64_entry(strm_node, struct qc_stream_desc, by_id);
+ qcs = stream->ctx;
}
else {
/* Remote streams. */
}
else {
strm_node = eb64_lookup(strms, id);
- if (strm_node)
- qcs = eb64_entry(strm_node, struct qcs, by_id);
+ if (strm_node) {
+ stream = eb64_entry(strm_node, struct qc_stream_desc, by_id);
+ qcs = stream->ctx;
+ }
}
}
*/
int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
{
+ struct qc_stream_desc *stream;
struct qcs *qcs;
struct eb64_node *node;
node = eb64_lookup(&qcc->streams_by_id, id);
if (node) {
- qcs = eb64_entry(&node->node, struct qcs, by_id);
+ stream = eb64_entry(node, struct qc_stream_desc, by_id);
+ qcs = stream->ctx;
if (max > qcs->tx.msd) {
qcs->tx.msd = max;
static void qcs_destroy(struct qcs *qcs)
{
struct connection *conn = qcs->qcc->conn;
- const uint64_t id = qcs->by_id.key;
+ const uint64_t id = qcs->id;
TRACE_ENTER(QMUX_EV_QCS_END, conn, qcs);
/* liberate remaining qcs instances */
node = eb64_first(&qcc->streams_by_id);
while (node) {
- struct qcs *qcs = eb64_entry(node, struct qcs, by_id);
+ struct qc_stream_desc *stream = eb64_entry(node, struct qc_stream_desc, by_id);
node = eb64_next(node);
- qcs_free(qcs);
+ qcs_free(stream->ctx);
}
pool_free(pool_head_qcc, qcc);
frm->type = QUIC_FT_STREAM_8;
frm->stream.stream = qcs->stream;
- frm->stream.id = qcs->by_id.key;
+ frm->stream.id = qcs->id;
frm->stream.buf = out;
frm->stream.data = (unsigned char *)b_peek(out, head);
*/
node = eb64_first(&qcc->streams_by_id);
while (node) {
- struct qcs *qcs = container_of(node, struct qcs, by_id);
+ struct qc_stream_desc *stream = eb64_entry(node, struct qc_stream_desc, by_id);
+ struct qcs *qcs = stream->ctx;
struct buffer *buf = &qcs->tx.buf;
struct buffer *out = &qcs->stream->buf;
* mechanism for sending. This should be unified in the future,
* in this case the next check will be removed.
*/
- if (quic_stream_is_uni(qcs->by_id.key)) {
+ if (quic_stream_is_uni(qcs->id)) {
node = eb64_next(node);
continue;
}
node = eb64_first(&qcc->streams_by_id);
while (node) {
- struct qcs *qcs = container_of(node, struct qcs, by_id);
+ struct qc_stream_desc *stream = eb64_entry(node, struct qc_stream_desc, by_id);
+ struct qcs *qcs = stream->ctx;
node = eb64_next(node);
if (qcs->flags & QC_SF_DETACH) {
chunk_appendf(&trace_buf, " : qcc=%p(F)", qcc);
if (qcs)
- chunk_appendf(&trace_buf, " qcs=%p(%llu)", qcs, qcs->by_id.key);
+ chunk_appendf(&trace_buf, " qcs=%p(%lu)", qcs, qcs->id);
if (mask & QMUX_EV_QCC_NQCS) {
const uint64_t *id = a3;
/* do not use strm_frm->stream as the qc_stream_desc instance
* might be freed at this stage. Use the id to do a proper
- * lookup.
+ * lookup. First search in the MUX then in the released stream
+ * list.
*
* TODO if lookup operation impact on the perf is noticeable,
* implement a refcount on qc_stream_desc instances.
*/
- node = eb64_lookup(&qc->streams_by_id, strm_frm->id);
- stream = eb64_entry(node, struct qc_stream_desc, by_id);
+ if (qc->mux_state == QC_MUX_READY)
+ stream = qcc_get_stream(qc->qcc, strm_frm->id);
+ if (!stream) {
+ node = eb64_lookup(&qc->streams_by_id, strm_frm->id);
+ stream = eb64_entry(node, struct qc_stream_desc, by_id);
+ }
if (!stream) {
TRACE_PROTO("acked stream for released stream", QUIC_EV_CONN_ACKSTRM, qc, strm_frm);
frm = eb64_entry(&frm_node->node,
struct quic_rx_strm_frm, offset_node);
- ret = qcc_recv(qc->qcc, qcs->by_id.key, frm->len,
+ ret = qcc_recv(qc->qcc, qcs->id, frm->len,
frm->offset_node.key, frm->fin,
(char *)frm->data, &qcs);
return 0;
}
-/* Allocate a new stream descriptor with id <id>. The stream will be stored
- * inside the <qc> connection.
+/* 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(struct quic_conn *qc, uint64_t id, void *ctx)
+struct qc_stream_desc *qc_stream_desc_new(uint64_t id, void *ctx)
{
struct qc_stream_desc *stream;
return NULL;
stream->by_id.key = id;
- eb64_insert(&qc->streams_by_id, &stream->by_id);
+ stream->by_id.node.leaf_p = NULL;
stream->buf = BUF_NULL;
stream->acked_frms = EB_ROOT;
}
/* Mark the stream descriptor <stream> as released by the upper layer. It will
- * be freed as soon as all its buffered data are acknowledged.
+ * 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)
+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);
}
/* Function to automatically activate QUIC traces on stdout.