From 7f1265a238a1a7b1133bc8a2aaea80245c1a289f Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 29 May 2019 17:36:37 +0200 Subject: [PATCH] BUG/MEDIUM: mux-h2: fix the conditions to end the h2_send() loop The test for the mux alloc failure in h2_send() right after an attempt at h2_process_mux() used to make sense as it tried to detect that this latter failed to produce data. But now that we have a list of buffers, it is a perfectly valid situation where there can still be data in the buffer(s). So now when we see this flag we only declare it's the last run on the loop. In addition we need to make sure we break out of the loop on snd_buf failure, or we'll loop indefinitely, for example when the buf is full and we can't send. No backport is needed. --- src/mux_h2.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/mux_h2.c b/src/mux_h2.c index 557a158ca..c5a10dfce 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -2825,7 +2825,7 @@ static int h2_send(struct h2c *h2c) done = h2_process_mux(h2c); if (h2c->flags & H2_CF_MUX_MALLOC) - break; + done = 1; // we won't go further without extra buffers if (conn->flags & CO_FL_ERROR) break; @@ -2836,12 +2836,16 @@ static int h2_send(struct h2c *h2c) for (buf = br_head(h2c->mbuf); b_size(buf); buf = br_del_head(h2c->mbuf)) { if (b_data(buf)) { int ret = conn->xprt->snd_buf(conn, conn->xprt_ctx, buf, b_data(buf), flags); - if (!ret) + if (!ret) { + done = 1; break; + } sent = 1; b_del(buf, ret); - if (b_data(buf)) + if (b_data(buf)) { + done = 1; break; + } } b_free(buf); released++; @@ -2888,8 +2892,9 @@ static int h2_send(struct h2c *h2c) if (!br_data(h2c->mbuf)) return sent; schedule: - if (!(h2c->wait_event.events & SUB_RETRY_SEND)) + if (!(conn->flags & CO_FL_ERROR) && !(h2c->wait_event.events & SUB_RETRY_SEND)) conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_SEND, &h2c->wait_event); + return sent; }