From: Willy Tarreau Date: Wed, 29 May 2019 15:36:37 +0000 (+0200) Subject: BUG/MEDIUM: mux-h2: fix the conditions to end the h2_send() loop X-Git-Tag: v2.0-dev5~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7f1265a238a1a7b1133bc8a2aaea80245c1a289f;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/src/mux_h2.c b/src/mux_h2.c index 557a158cab..c5a10dfce1 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; }