mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-26 12:58:03 +00:00
MINOR: mux-quic: do not release qcs if there is remaining data to send
A qcs is not freed if there is remaining data in its buffer. In this case, the flag QC_SF_DETACH is positionned. The qcc io handler is responsible to remove the qcs if the QC_SF_DETACH is set and their buffers are empty.
This commit is contained in:
parent
70f8948364
commit
2873a31c81
@ -56,6 +56,7 @@ struct qcc {
|
||||
#define QC_SF_NONE 0x00000000
|
||||
#define QC_SF_FIN_STREAM 0x00000001 // FIN bit must be set for last frame of the stream
|
||||
#define QC_SF_BLK_MROOM 0x00000002 // app layer is blocked waiting for room in the qcs.tx.buf
|
||||
#define QC_SF_DETACH 0x00000004 // cs is detached but there is remaining data to send
|
||||
|
||||
struct qcs {
|
||||
struct qcc *qcc;
|
||||
|
149
src/mux_quic.c
149
src/mux_quic.c
@ -117,6 +117,62 @@ void qcs_notify_send(struct qcs *qcs)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 int qcs_push_frame(struct qcs *qcs, struct buffer *payload, int fin, uint64_t offset)
|
||||
{
|
||||
struct quic_frame *frm;
|
||||
@ -208,6 +264,31 @@ static int qc_send(struct qcc *qcc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qc_release_detached_streams(struct qcc *qcc)
|
||||
{
|
||||
struct eb64_node *node;
|
||||
int release = 0;
|
||||
|
||||
node = eb64_first(&qcc->streams_by_id);
|
||||
while (node) {
|
||||
struct qcs *qcs = container_of(node, struct qcs, by_id);
|
||||
node = eb64_next(node);
|
||||
|
||||
if (qcs->flags & QC_SF_DETACH) {
|
||||
if (!b_data(&qcs->tx.buf) && !b_data(&qcs->tx.xprt_buf)) {
|
||||
qcs_destroy(qcs);
|
||||
release = 1;
|
||||
}
|
||||
else {
|
||||
qcc->conn->xprt->subscribe(qcc->conn, qcc->conn->xprt_ctx,
|
||||
SUB_RETRY_SEND, &qcc->wait_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return release;
|
||||
}
|
||||
|
||||
static struct task *qc_io_cb(struct task *t, void *ctx, unsigned int status)
|
||||
{
|
||||
struct qcc *qcc = ctx;
|
||||
@ -216,6 +297,13 @@ static struct task *qc_io_cb(struct task *t, void *ctx, unsigned int status)
|
||||
|
||||
qc_send(qcc);
|
||||
|
||||
if (qc_release_detached_streams(qcc)) {
|
||||
if (qcc_is_dead(qcc)) {
|
||||
qc_release(qcc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -264,62 +352,6 @@ static int qc_init(struct connection *conn, struct proxy *prx,
|
||||
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)
|
||||
{
|
||||
struct qcs *qcs = cs->ctx;
|
||||
@ -328,6 +360,11 @@ static void qc_detach(struct conn_stream *cs)
|
||||
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));
|
||||
|
||||
if (b_data(&qcs->tx.buf) || b_data(&qcs->tx.xprt_buf)) {
|
||||
qcs->flags |= QC_SF_DETACH;
|
||||
return;
|
||||
}
|
||||
|
||||
qcs_destroy(qcs);
|
||||
if (qcc_is_dead(qcc)) {
|
||||
qc_release(qcc);
|
||||
|
Loading…
Reference in New Issue
Block a user