From: Christopher Faulet Date: Tue, 8 Jan 2019 10:12:04 +0000 (+0100) Subject: MEDIUM: mux-h1: Clarify how shutr/shutw are handled X-Git-Tag: v2.0-dev1~247 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=666a0c4d82674980598e649f6c2ea9d576778e3e;p=thirdparty%2Fhaproxy.git MEDIUM: mux-h1: Clarify how shutr/shutw are handled Now, h1_shutr() only do a shutdown read and try to set the flag H1C_F_CS_SHUTDOWN if shutdown write was already performed. On its side, h1_shutw(), if all conditions are met, do the same for the shutdown write. The real connection close is done when the mux h1 is released, in h1_release(). The flag H1C_F_CS_SHUTW was renamed to H1C_F_CS_SHUTDOWN to be less ambiguous. This patch may be backported to 1.9. --- diff --git a/src/mux_h1.c b/src/mux_h1.c index 60369da905..d4d3eb8de8 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -44,7 +44,7 @@ #define H1C_F_CS_ERROR 0x00001000 /* connection must be closed ASAP because an error occurred */ #define H1C_F_CS_SHUTW_NOW 0x00002000 /* connection must be shut down for writes ASAP */ -#define H1C_F_CS_SHUTW 0x00004000 /* connection is already shut down */ +#define H1C_F_CS_SHUTDOWN 0x00004000 /* connection is shut down for read and writes */ #define H1C_F_CS_WAIT_CONN 0x00008000 /* waiting for the connection establishment */ #define H1C_F_WAIT_NEXT_REQ 0x00010000 /* waiting for the next request to start, use keep-alive timeout */ @@ -113,7 +113,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); +static void h1_shutw_conn(struct connection *conn, enum cs_shw_mode mode); static struct task *h1_timeout_task(struct task *t, void *context, unsigned short state); /*****************************************************/ @@ -139,7 +139,7 @@ static struct task *h1_timeout_task(struct task *t, void *context, unsigned shor */ static inline int h1_recv_allowed(const struct h1c *h1c) { - if (b_data(&h1c->ibuf) == 0 && (h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTW))) + if (b_data(&h1c->ibuf) == 0 && (h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN))) return 0; if (h1c->conn->flags & CO_FL_ERROR || conn_xprt_read0_pending(h1c->conn)) @@ -1814,7 +1814,7 @@ static int h1_send(struct h1c *h1c) h1_release_buf(h1c, &h1c->obuf); h1_sync_messages(h1c); if (h1c->flags & H1C_F_CS_SHUTW_NOW) - h1_shutw_conn(conn); + h1_shutw_conn(conn, CS_SHW_NORMAL); } else if (!(h1c->wait_event.events & SUB_RETRY_SEND)) conn->xprt->subscribe(conn, SUB_RETRY_SEND, &h1c->wait_event); @@ -1847,7 +1847,7 @@ static int h1_process(struct h1c * h1c) conn->flags & CO_FL_ERROR || conn_xprt_read0_pending(conn)) goto release; - if (!conn_is_back(conn) && !(h1c->flags & (H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTW))) { + if (!conn_is_back(conn) && !(h1c->flags & (H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTDOWN))) { if (!h1s_create(h1c, NULL, NULL)) goto release; } @@ -1875,7 +1875,7 @@ static int h1_process(struct h1c * h1c) if (h1c->task) { h1c->task->expire = TICK_ETERNITY; if (b_data(&h1c->obuf)) { - h1c->task->expire = tick_add(now_ms, ((h1c->flags & (H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTW)) + h1c->task->expire = tick_add(now_ms, ((h1c->flags & (H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTDOWN)) ? h1c->shut_timeout : h1c->timeout)); task_queue(h1c->task); @@ -2080,7 +2080,7 @@ static void h1_detach(struct conn_stream *cs) } /* We don't want to close right now unless the connection is in error */ - if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTW)) || + if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN)) || (h1c->conn->flags & CO_FL_ERROR) || !h1c->conn->owner) h1_release(h1c->conn); else { @@ -2088,7 +2088,7 @@ static void h1_detach(struct conn_stream *cs) if (h1c->task) { h1c->task->expire = TICK_ETERNITY; if (b_data(&h1c->obuf)) { - h1c->task->expire = tick_add(now_ms, ((h1c->flags & (H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTW)) + h1c->task->expire = tick_add(now_ms, ((h1c->flags & (H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTDOWN)) ? h1c->shut_timeout : h1c->timeout)); task_queue(h1c->task); @@ -2114,10 +2114,8 @@ static void h1_shutr(struct conn_stream *cs, enum cs_shr_mode mode) return; if (conn_xprt_ready(cs->conn) && cs->conn->xprt->shutr) cs->conn->xprt->shutr(cs->conn, (mode == CS_SHR_DRAIN)); - if (cs->conn->flags & CO_FL_SOCK_WR_SH) { - h1c->flags = (h1c->flags & ~H1C_F_CS_SHUTW_NOW) | H1C_F_CS_SHUTW; - conn_full_close(cs->conn); - } + if ((cs->conn->flags & (CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH)) == (CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH)) + h1s->h1c->flags = (h1s->h1c->flags & ~H1C_F_CS_SHUTW_NOW) | H1C_F_CS_SHUTDOWN; } static void h1_shutw(struct conn_stream *cs, enum cs_shw_mode mode) @@ -2139,21 +2137,17 @@ static void h1_shutw(struct conn_stream *cs, enum cs_shw_mode mode) if ((cs->flags & CS_FL_SHW) || b_data(&h1c->obuf)) return; - h1_shutw_conn(cs->conn); + h1_shutw_conn(cs->conn, mode); } -static void h1_shutw_conn(struct connection *conn) +static void h1_shutw_conn(struct connection *conn, enum cs_shw_mode mode) { struct h1c *h1c = conn->ctx; - if (conn_xprt_ready(conn) && conn->xprt->shutw) - conn->xprt->shutw(conn, 1); - if (!(conn->flags & CO_FL_SOCK_RD_SH)) - conn_sock_shutw(conn, 1); - else { - h1c->flags = (h1c->flags & ~H1C_F_CS_SHUTW_NOW) | H1C_F_CS_SHUTW; - conn_full_close(conn); - } + conn_xprt_shutw(conn); + conn_sock_shutw(conn, (mode == CS_SHW_NORMAL)); + if ((conn->flags & (CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH)) == (CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH)) + h1c->flags = (h1c->flags & ~H1C_F_CS_SHUTW_NOW) | H1C_F_CS_SHUTDOWN; } /* Called from the upper layer, to unsubscribe to events */