BUG/MINOR: mux-h1: Save shutdown mode if the shutdown is delayed
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 27 Oct 2021 13:36:38 +0000 (15:36 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 3 Nov 2021 10:57:33 +0000 (11:57 +0100)
The connection shutdown may be delayed if there are pending outgoing
data. The action is performed once data are fully sent. In this case the
mode (dirty/clean) was lost and a clean shutdown was always performed. Now,
the mode is saved to be sure to perform the connection shutdown using the
right mode. To do so, H1C_F_ST_SILENT_SHUT flag is introduced.

This patch should be backported as far as 2.0.

(cherry picked from commit a85c522d42f866d57cd79335a945402b81cb3948)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit db451fb7d790d2675bfeda435b47a560e515b437)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>

src/mux_h1.c

index fee2c0f..0948313 100644 (file)
 #define H1C_F_IN_ALLOC       0x00000010 /* mux is blocked on lack of input buffer */
 #define H1C_F_IN_FULL        0x00000020 /* mux is blocked on input buffer full */
 #define H1C_F_IN_BUSY        0x00000040 /* mux is blocked on input waiting the other side */
-/* 0x00000040 - 0x00000800 unused */
+/* 0x00000080 - 0x000002000 unused */
+
+#define H1C_F_ST_SILENT_SHUT 0x00004000 /* silent (or dirty) shutdown must be performed */
+/* 0x000008000 unused */
 
 /* Flags indicating the connection state */
 #define H1C_F_CS_ERROR       0x00001000 /* connection must be closed ASAP because an error occurred */
@@ -252,7 +255,7 @@ static int h1_recv(struct h1c *h1c);
 static int h1_send(struct h1c *h1c);
 static int h1_process(struct h1c *h1c);
 static struct task *h1_io_cb(struct task *t, void *ctx, unsigned short state);
-static void h1_shutw_conn(struct connection *conn, enum cs_shw_mode mode);
+static void h1_shutw_conn(struct connection *conn);
 static struct task *h1_timeout_task(struct task *t, void *context, unsigned short state);
 static void h1_wake_stream_for_recv(struct h1s *h1s);
 static void h1_wake_stream_for_send(struct h1s *h1s);
@@ -2255,7 +2258,7 @@ static int h1_send(struct h1c *h1c)
                h1_release_buf(h1c, &h1c->obuf);
                if (h1c->flags & H1C_F_CS_SHUTW_NOW) {
                        TRACE_STATE("process pending shutdown for writes", H1_EV_H1C_SEND, h1c->conn);
-                       h1_shutw_conn(conn, CS_SHW_NORMAL);
+                       h1_shutw_conn(conn);
                }
        }
        else if (!(h1c->wait_event.events & SUB_RETRY_SEND)) {
@@ -2699,25 +2702,27 @@ static void h1_shutw(struct conn_stream *cs, enum cs_shw_mode mode)
 
   do_shutw:
        h1c->flags |= H1C_F_CS_SHUTW_NOW;
+       if (mode != CS_SHW_NORMAL)
+               h1c->flags |= H1C_F_ST_SILENT_SHUT;
        if ((cs->flags & CS_FL_SHW) || b_data(&h1c->obuf))
                goto end;
-       h1_shutw_conn(cs->conn, mode);
+       h1_shutw_conn(cs->conn);
   end:
        TRACE_LEAVE(H1_EV_STRM_SHUT, h1c->conn, h1s);
 }
 
-static void h1_shutw_conn(struct connection *conn, enum cs_shw_mode mode)
+static void h1_shutw_conn(struct connection *conn)
 {
        struct h1c *h1c = conn->ctx;
 
        if (conn->flags & CO_FL_SOCK_WR_SH)
                return;
 
-       TRACE_ENTER(H1_EV_STRM_SHUT, conn, h1c->h1s);
+       TRACE_ENTER(H1_EV_H1C_END, conn);
        conn_xprt_shutw(conn);
-       conn_sock_shutw(conn, (mode == CS_SHW_NORMAL));
+       conn_sock_shutw(conn, (h1c && !(h1c->flags & H1C_F_ST_SILENT_SHUT)));
        h1c->flags = (h1c->flags & ~H1C_F_CS_SHUTW_NOW) | H1C_F_CS_SHUTDOWN;
-       TRACE_LEAVE(H1_EV_STRM_SHUT, conn, h1c->h1s);
+       TRACE_LEAVE(H1_EV_STRM_SHUT, conn);
 }
 
 /* Called from the upper layer, to unsubscribe <es> from events <event_type>