diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index 6b2c10e8c..62ae59bbd 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -68,6 +68,7 @@ struct qcc { struct { struct quic_fctl fc; /* stream flow control applied on sending */ uint64_t buf_in_flight; /* sum of currently allocated Tx buffer sizes */ + struct list frms; /* list of STREAM frames ready for sent */ } tx; uint64_t largest_bidi_r; /* largest remote bidi stream ID opened. */ diff --git a/src/mux_quic.c b/src/mux_quic.c index 9085859f0..217c4c9aa 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -36,6 +36,15 @@ DECLARE_POOL(pool_head_qcs, "qcs", sizeof(struct qcs)); static void qmux_ctrl_send(struct qc_stream_desc *, uint64_t data, uint64_t offset); static void qmux_ctrl_room(struct qc_stream_desc *, uint64_t room); +/* Free STREAM frames in Tx list. */ +static void qcc_tx_frms_free(struct qcc *qcc) +{ + while (!LIST_ISEMPTY(&qcc->tx.frms)) { + struct quic_frame *frm = LIST_ELEM(qcc->tx.frms.n, struct quic_frame *, list); + qc_frm_free(qcc->conn->handle.qc, &frm); + } +} + static void qcs_free_ncbuf(struct qcs *qcs, struct ncbuf *ncbuf) { struct buffer buf; @@ -2247,7 +2256,7 @@ static int qcs_send(struct qcs *qcs, struct list *frms, uint64_t window_conn) */ static int qcc_io_send(struct qcc *qcc) { - struct list frms = LIST_HEAD_INIT(frms); + struct list *frms = &qcc->tx.frms; /* Temporary list for QCS on error. */ struct list qcs_failed = LIST_HEAD_INIT(qcs_failed); struct qcs *qcs, *qcs_tmp, *first_qcs = NULL; @@ -2341,7 +2350,7 @@ static int qcc_io_send(struct qcc *qcc) if (!qfctl_rblocked(&qcc->tx.fc) && !qfctl_rblocked(&qcs->tx.fc) && window_conn > total) { - if ((ret = qcs_send(qcs, &frms, window_conn - total)) < 0) { + if ((ret = qcs_send(qcs, frms, window_conn - total)) < 0) { /* Temporarily remove QCS from send-list. */ LIST_DEL_INIT(&qcs->el_send); LIST_APPEND(&qcs_failed, &qcs->el_send); @@ -2365,7 +2374,7 @@ static int qcc_io_send(struct qcc *qcc) /* Retry sending until no frame to send, data rejected or connection * flow-control limit reached. */ - while (qcc_send_frames(qcc, &frms) == 0 && !qfctl_rblocked(&qcc->tx.fc)) { + while (qcc_send_frames(qcc, frms) == 0 && !qfctl_rblocked(&qcc->tx.fc)) { window_conn = qfctl_rcap(&qcc->tx.fc); resent = 0; @@ -2383,7 +2392,7 @@ static int qcc_io_send(struct qcc *qcc) BUG_ON(resent > window_conn); if (!qfctl_rblocked(&qcs->tx.fc) && window_conn > resent) { - if ((ret = qcs_send(qcs, &frms, window_conn - resent)) < 0) { + if ((ret = qcs_send(qcs, frms, window_conn - resent)) < 0) { LIST_DEL_INIT(&qcs->el_send); LIST_APPEND(&qcs_failed, &qcs->el_send); continue; @@ -2397,12 +2406,7 @@ static int qcc_io_send(struct qcc *qcc) sent_done: /* Deallocate frames that the transport layer has rejected. */ - if (!LIST_ISEMPTY(&frms)) { - struct quic_frame *frm, *frm2; - - list_for_each_entry_safe(frm, frm2, &frms, list) - qc_frm_free(qcc->conn->handle.qc, &frm); - } + qcc_tx_frms_free(qcc); /* Re-insert on-error QCS at the end of the send-list. */ if (!LIST_ISEMPTY(&qcs_failed)) { @@ -2722,6 +2726,8 @@ static void qcc_release(struct qcc *qcc) qc_frm_free(qcc->conn->handle.qc, &frm); } + qcc_tx_frms_free(qcc); + if (qcc->app_ops && qcc->app_ops->release) qcc->app_ops->release(qcc->ctx); TRACE_PROTO("application layer released", QMUX_EV_QCC_END, conn); @@ -2835,6 +2841,7 @@ static void _qcc_init(struct qcc *qcc) qcc->app_ops = NULL; qcc->streams_by_id = EB_ROOT_UNIQUE; LIST_INIT(&qcc->lfctl.frms); + LIST_INIT(&qcc->tx.frms); } static int qmux_init(struct connection *conn, struct proxy *prx,