From: Yeonggi Kim <[email protected]>

Since 5da704b55 ("MEDIUM: log: Update the log applet to use its own
buffers"), syslog_io_handler() leaves early with applet_need_more_data()
when its input buffer is empty:

        inbuf = applet_get_inbuf(appctx);
        if (inbuf == NULL || !applet_input_data(appctx)) {
                goto missing_data;
        }

This skips applet_getchar(), which is where the handler notices the
client's shutdown: on an empty buffer it returns -1 once SE_FL_SHW is
set, and the session is closed through cli_abort. Before that commit,
co_getchar() was reached the same way on an empty buffer. Now, when the
shutdown is received alone, after the previous messages were consumed,
the TCP syslog session stays open. A log-forward section does not
inherit "timeout client" from the defaults section, so unless one is set
in the section itself, nothing ever closes the session.

Reproducer:

    global
        stats socket /tmp/haproxy.sock level admin

    log-forward relay
        bind 127.0.0.1:1514
        log 127.0.0.1:1515 local0

Three clients which each send one message to 127.0.0.1:1514 and close
the connection once it was forwarded leave three sessions in "show sess"
(none with this patch). A soft-stop then waits for "hard-stop-after",
and forever without it. This also happens when a "ring" forwards to a
log-forward section of the same process: on soft-stop the ring's
forwarder closes its connection, the session on the log-forward side
stays, so after a reload the old process is only stopped by
"hard-stop-after".

Only a missing input buffer (not allocated yet) must still make the
handler leave early. An empty one now goes through applet_getchar(),
which returns 0 (wait for more data, as before) or -1 once SE_FL_SHW is
set. The dns and peers applets already work this way: they only test
applet_get_inbuf() for NULL and rely on the getters to report the
shutdown. As before 5da704b55, a closed session is accounted in
cli_aborts, as already done when the client closes in the middle of a
message.

This must be backported as far as 3.3.
---
 src/log.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/log.c b/src/log.c
index 3d5dff7..7e2ee16 100644
--- a/src/log.c
+++ b/src/log.c
@@ -6247,10 +6247,13 @@ static void syslog_io_handler(struct appctx *appctx)
                goto out;
        }
 
+       /* Only leave early when no input buffer is available. An empty buffer
+        * must still reach applet_getchar() below, because it is what reports
+        * the client's shutdown.
+        */
        inbuf = applet_get_inbuf(appctx);
-       if (inbuf == NULL || !applet_input_data(appctx)) {
+       if (inbuf == NULL)
                goto missing_data;
-       }
 
        max_accept = l->bind_conf->maxaccept ? l->bind_conf->maxaccept : 1;
        while (1) {
-- 
2.52.0



Reply via email to