diff --git a/include/haproxy/quic_stream.h b/include/haproxy/quic_stream.h index 57f8c455f..44897287b 100644 --- a/include/haproxy/quic_stream.h +++ b/include/haproxy/quic_stream.h @@ -10,7 +10,7 @@ struct quic_conn; struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type, void *ctx, struct quic_conn *qc); -void qc_stream_desc_release(struct qc_stream_desc *stream); +void qc_stream_desc_release(struct qc_stream_desc *stream, uint64_t final_size); int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len); void qc_stream_desc_free(struct qc_stream_desc *stream, int closing); diff --git a/src/mux_quic.c b/src/mux_quic.c index a6af629a8..55c395a09 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -68,7 +68,7 @@ static void qcs_free(struct qcs *qcs) qcc->app_ops->detach(qcs); /* Release qc_stream_desc buffer from quic-conn layer. */ - qc_stream_desc_release(qcs->stream); + qc_stream_desc_release(qcs->stream, qcs->tx.sent_offset); /* Free Rx/Tx buffers. */ qcs_free_ncbuf(qcs, &qcs->rx.ncbuf); diff --git a/src/quic_stream.c b/src/quic_stream.c index 727636b06..42452c2c0 100644 --- a/src/quic_stream.c +++ b/src/quic_stream.c @@ -85,8 +85,13 @@ struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type type, void /* Mark the stream descriptor as released. It will be freed as soon as * all its buffered data are acknowledged. Does nothing if is already * NULL. + * + * corresponds to the last offset sent for this stream. If there + * is unsent data present, they will be remove first to guarantee that buffer + * is freed after receiving all acknowledges. */ -void qc_stream_desc_release(struct qc_stream_desc *stream) +void qc_stream_desc_release(struct qc_stream_desc *stream, + uint64_t final_size) { if (!stream) return; @@ -97,14 +102,31 @@ void qc_stream_desc_release(struct qc_stream_desc *stream) stream->release = 1; stream->ctx = NULL; + if (stream->buf) { + struct qc_stream_buf *stream_buf = stream->buf; + struct buffer *buf = &stream_buf->buf; + const uint64_t tail_offset = + MAX(stream->buf_offset, stream->ack_offset) + b_data(buf); + + /* final_size cannot be greater than all currently stored data. */ + BUG_ON(final_size > tail_offset); + + /* Remove unsent data from current buffer. */ + if (final_size < tail_offset) { + b_sub(buf, tail_offset - final_size); + /* Remove buffer is all ACK already received. */ + if (!b_data(buf)) + qc_stream_buf_free(stream, &stream_buf); + } + + /* A released stream does not use . */ + stream->buf = NULL; + } + if (LIST_ISEMPTY(&stream->buf_list)) { /* if no buffer left we can free the stream. */ qc_stream_desc_free(stream, 0); } - else { - /* A released stream does not use . */ - stream->buf = NULL; - } } /* Acknowledge data at of length for . It is handled diff --git a/src/quic_tls.c b/src/quic_tls.c index 7e18a3926..581d615ce 100644 --- a/src/quic_tls.c +++ b/src/quic_tls.c @@ -125,7 +125,7 @@ void quic_cstream_free(struct quic_cstream *cs) quic_free_ncbuf(&cs->rx.ncbuf); - qc_stream_desc_release(cs->desc); + qc_stream_desc_release(cs->desc, 0); pool_free(pool_head_quic_cstream, cs); }