From: Christopher Faulet Date: Mon, 3 Apr 2023 16:32:50 +0000 (+0200) Subject: MEDIUM: tree-wide: Move flags about shut from the channel to the SC X-Git-Tag: v2.8-dev7~70 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=87633c3a11237929f6314a56bce80e489fa85aaa;p=thirdparty%2Fhaproxy.git MEDIUM: tree-wide: Move flags about shut from the channel to the SC The purpose of this patch is only a one-to-one replacement, as far as possible. CF_SHUTR(_NOW) and CF_SHUTW(_NOW) flags are now carried by the stream-connecter. CF_ prefix is replaced by SC_FL_ one. Of course, it is not so simple because at many places, we were testing if a channel was shut for reads and writes in same time. To do the same, shut for reads must be tested on one side on the SC and shut for writes on the other side on the opposite SC. A special care was taken with process_stream(). flags of SCs must be saved to be able to detect changes, just like for the channels. --- diff --git a/include/haproxy/channel-t.h b/include/haproxy/channel-t.h index 32f698300c..f876d91018 100644 --- a/include/haproxy/channel-t.h +++ b/include/haproxy/channel-t.h @@ -40,12 +40,6 @@ * - read-only indicators reported by lower data levels : * CF_STREAMER, CF_STREAMER_FAST * - * - write-once status flags reported by the stream connector layer : - * CF_SHUTR, CF_SHUTW - * - * - persistent control flags managed only by application level : - * CF_SHUT*_NOW, CF_*_ENA - * * The flags have been arranged for readability, so that the read and write * bits have the same position in a byte (read being the lower byte and write * the second one). All flag names are relative to the channel. For instance, @@ -58,10 +52,7 @@ #define CF_READ_TIMEOUT 0x00000004 /* timeout while waiting for producer */ /* unused 0x00000008 */ -/* unused: 0x00000010 */ -#define CF_SHUTR 0x00000020 /* producer has already shut down */ -#define CF_SHUTR_NOW 0x00000040 /* the producer must shut down for reads ASAP */ -/* 0x00000080 unused */ +/* unused: 0x00000010 - 0x00000080 */ #define CF_WRITE_EVENT 0x00000100 /* a write event detected on consumer side */ /* unused: 0x00000200 */ @@ -69,37 +60,9 @@ /* unused 0x00000800 */ #define CF_WAKE_WRITE 0x00001000 /* wake the task up when there's write activity */ -#define CF_SHUTW 0x00002000 /* consumer has already shut down */ -#define CF_SHUTW_NOW 0x00004000 /* the consumer must shut down for writes ASAP */ +/* unused: 0x00002000 - 0x00004000 */ #define CF_AUTO_CLOSE 0x00008000 /* producer can forward shutdown to other side */ -/* When CF_SHUTR_NOW is set, it is strictly forbidden for the producer to alter - * the buffer contents. When CF_SHUTW_NOW is set, the consumer is free to perform - * a shutw() when it has consumed the last contents, otherwise the session processor - * will do it anyway. - * - * The SHUT* flags work like this : - * - * SHUTR SHUTR_NOW meaning - * 0 0 normal case, connection still open and data is being read - * 0 1 closing : the producer cannot feed data anymore but can close - * 1 0 closed: the producer has closed its input channel. - * 1 1 impossible - * - * SHUTW SHUTW_NOW meaning - * 0 0 normal case, connection still open and data is being written - * 0 1 closing: the consumer can send last data and may then close - * 1 0 closed: the consumer has closed its output channel. - * 1 1 impossible - * - * The SHUTW_NOW flag should be set by the session processor when SHUTR and AUTO_CLOSE - * are both set. And it may also be set by the producer when it detects SHUTR while - * directly forwarding data to the consumer. - * - * The SHUTR_NOW flag is mostly used to force the producer to abort when an error is - * detected on the consumer side. - */ - #define CF_STREAMER 0x00010000 /* the producer is identified as streaming data */ #define CF_STREAMER_FAST 0x00020000 /* the consumer seems to eat the stream very fast */ @@ -120,9 +83,6 @@ /* Masks which define input events for stream analysers */ #define CF_MASK_ANALYSER (CF_READ_EVENT|CF_READ_TIMEOUT|CF_WRITE_EVENT|CF_WAKE_ONCE) -/* Mask for static flags which cause analysers to be woken up when they change */ -#define CF_MASK_STATIC (CF_SHUTR|CF_SHUTW|CF_SHUTR_NOW|CF_SHUTW_NOW) - /* This function is used to report flags in debugging tools. Please reflect * below any single-bit flag addition above in the same order via the * __APPEND_FLAG macro. The new end of the buffer is returned. @@ -134,14 +94,14 @@ static forceinline char *chn_show_flags(char *buf, size_t len, const char *delim _(0); /* flags */ _(CF_READ_EVENT, _(CF_READ_TIMEOUT, - _(CF_SHUTR, _(CF_SHUTR_NOW, _(CF_WRITE_EVENT, + _(CF_WRITE_EVENT, _(CF_WRITE_TIMEOUT, - _(CF_WAKE_WRITE, _(CF_SHUTW, _(CF_SHUTW_NOW, _(CF_AUTO_CLOSE, + _(CF_WAKE_WRITE, _(CF_AUTO_CLOSE, _(CF_STREAMER, _(CF_STREAMER_FAST, _(CF_WROTE_DATA, _(CF_KERN_SPLICING, _(CF_AUTO_CONNECT, _(CF_DONT_READ, _(CF_WAKE_ONCE, _(CF_FLT_ANALYZE, - _(CF_ISRESP))))))))))))))))))); + _(CF_ISRESP))))))))))))))); /* epilogue */ _(~0U); return buf; diff --git a/include/haproxy/channel.h b/include/haproxy/channel.h index 9cacb923d5..1bf21c7a74 100644 --- a/include/haproxy/channel.h +++ b/include/haproxy/channel.h @@ -514,13 +514,13 @@ static inline int channel_may_recv(const struct channel *chn) /* Returns true if the channel's input is already closed */ static inline int channel_input_closed(struct channel *chn) { - return ((chn->flags & CF_SHUTR) != 0); + return ((chn_prod(chn)->flags & SC_FL_SHUTR) != 0); } /* Returns true if the channel's output is already closed */ static inline int channel_output_closed(struct channel *chn) { - return ((chn->flags & CF_SHUTW) != 0); + return ((chn_cons(chn)->flags & SC_FL_SHUTW) != 0); } /* Check channel timeouts, and set the corresponding flags. */ @@ -551,19 +551,20 @@ static inline void channel_htx_erase(struct channel *chn, struct htx *htx) /* marks the channel as "shutdown" ASAP for reads */ static inline void channel_shutr_now(struct channel *chn) { - chn->flags |= CF_SHUTR_NOW; + chn_prod(chn)->flags |= SC_FL_SHUTR_NOW; } /* marks the channel as "shutdown" ASAP for writes */ static inline void channel_shutw_now(struct channel *chn) { - chn->flags |= CF_SHUTW_NOW; + chn_cons(chn)->flags |= SC_FL_SHUTW_NOW; } /* marks the channel as "shutdown" ASAP in both directions */ static inline void channel_abort(struct channel *chn) { - chn->flags |= CF_SHUTR_NOW | CF_SHUTW_NOW; + chn_prod(chn)->flags |= SC_FL_SHUTR_NOW; + chn_cons(chn)->flags |= SC_FL_SHUTW_NOW; chn->flags &= ~CF_AUTO_CONNECT; } @@ -986,8 +987,8 @@ static inline int ci_putstr(struct channel *chn, const char *str) static inline int co_getchr(struct channel *chn) { /* closed or empty + imminent close = -2; empty = -1 */ - if (unlikely((chn->flags & CF_SHUTW) || channel_is_empty(chn))) { - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (unlikely((chn_cons(chn)->flags & SC_FL_SHUTW) || channel_is_empty(chn))) { + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) return -2; return -1; } diff --git a/include/haproxy/sc_strm.h b/include/haproxy/sc_strm.h index 199e8d221e..fbe0968ee4 100644 --- a/include/haproxy/sc_strm.h +++ b/include/haproxy/sc_strm.h @@ -288,7 +288,7 @@ static inline int sc_is_recv_allowed(const struct stconn *sc) { struct channel *ic = sc_ic(sc); - if (ic->flags & CF_SHUTR) + if (chn_prod(ic)->flags & SC_FL_SHUTR) return 0; if (sc_ep_test(sc, SE_FL_APPLET_NEED_CONN)) @@ -367,7 +367,7 @@ static inline int sc_is_send_allowed(const struct stconn *sc) { struct channel *oc = sc_oc(sc); - if (oc->flags & CF_SHUTW) + if (chn_cons(oc)->flags & SC_FL_SHUTW) return 0; return !sc_ep_test(sc, SE_FL_WAIT_DATA | SE_FL_WONT_CONSUME); @@ -375,7 +375,8 @@ static inline int sc_is_send_allowed(const struct stconn *sc) static inline int sc_rcv_may_expire(const struct stconn *sc) { - if (sc_ic(sc)->flags & (CF_SHUTR|CF_READ_TIMEOUT|CF_READ_EVENT)) + if ((chn_prod(sc_ic(sc))->flags & SC_FL_SHUTR) || + (sc_ic(sc)->flags & (CF_READ_TIMEOUT|CF_READ_EVENT))) return 0; if (sc->flags & (SC_FL_EOI|SC_FL_WONT_READ|SC_FL_NEED_BUFF|SC_FL_NEED_ROOM)) return 0; @@ -386,7 +387,8 @@ static inline int sc_rcv_may_expire(const struct stconn *sc) static inline int sc_snd_may_expire(const struct stconn *sc) { - if (sc_oc(sc)->flags & (CF_SHUTW|CF_WRITE_TIMEOUT|CF_WRITE_EVENT)) + if ((chn_cons(sc_oc(sc))->flags & SC_FL_SHUTW) || + (sc_oc(sc)->flags & (CF_WRITE_TIMEOUT|CF_WRITE_EVENT))) return 0; if (sc_ep_test(sc, SE_FL_WONT_CONSUME)) return 0; diff --git a/include/haproxy/stconn-t.h b/include/haproxy/stconn-t.h index e97bf83ffc..63b882a6c2 100644 --- a/include/haproxy/stconn-t.h +++ b/include/haproxy/stconn-t.h @@ -109,6 +109,33 @@ static forceinline char *se_show_flags(char *buf, size_t len, const char *delim, /* stconn flags. * Please also update the sc_show_flags() function below in case of changes. + * + * When SC_FL_SHUTR_NOW is set, it is strictly forbidden for the producer to alter + * the buffer contents. When SC_FL_SHUTW_NOW is set, the consumer is free to perform + * a shutw() when it has consumed the last contents, otherwise the session processor + * will do it anyway. + * + * The SHUT* flags work like this : + * + * SHUTR SHUTR_NOW meaning + * 0 0 normal case, connection still open and data is being read + * 0 1 closing : the producer cannot feed data anymore but can close + * 1 0 closed: the producer has closed its input channel. + * 1 1 impossible + * + * SHUTW SHUTW_NOW meaning + * 0 0 normal case, connection still open and data is being written + * 0 1 closing: the consumer can send last data and may then close + * 1 0 closed: the consumer has closed its output channel. + * 1 1 impossible + * + * The SHUTW_NOW flag should be set by the session processor when SHUTR and AUTO_CLOSE + * are both set. And it may also be set by the producer when it detects SHUTR while + * directly forwarding data to the consumer. + * + * The SHUTR_NOW flag is mostly used to force the producer to abort when an error is + * detected on the consumer side. + * */ enum sc_flags { SC_FL_NONE = 0x00000000, /* Just for initialization purposes */ @@ -130,6 +157,11 @@ enum sc_flags { SC_FL_SND_ASAP = 0x00000800, /* Don't wait for sending. cleared when all data were sent */ SC_FL_SND_NEVERWAIT = 0x00001000, /* Never wait for sending (permanent) */ SC_FL_SND_EXP_MORE = 0x00001000, /* More data expected to be sent very soon. cleared when all data were sent */ + + SC_FL_SHUTR_NOW = 0x00002000, /* SC is shut down for reads */ + SC_FL_SHUTW_NOW = 0x00004000, /* SC must shut down for reads ASAP */ + SC_FL_SHUTR = 0x00008000, /* SC is shut down for writes */ + SC_FL_SHUTW = 0x00010000, /* SC must shut down for writes ASAP */ }; /* This function is used to report flags in debugging tools. Please reflect @@ -145,7 +177,8 @@ static forceinline char *sc_show_flags(char *buf, size_t len, const char *delim, _(SC_FL_ISBACK, _(SC_FL_EOI, _(SC_FL_NOLINGER, _(SC_FL_NOHALF, _(SC_FL_DONT_WAKE, _(SC_FL_INDEP_STR, _(SC_FL_WONT_READ, _(SC_FL_NEED_BUFF, _(SC_FL_NEED_ROOM, - _(SC_FL_RCV_ONCE, _(SC_FL_SND_ASAP, _(SC_FL_SND_NEVERWAIT, _(SC_FL_SND_EXP_MORE))))))))))))); + _(SC_FL_RCV_ONCE, _(SC_FL_SND_ASAP, _(SC_FL_SND_NEVERWAIT, _(SC_FL_SND_EXP_MORE, + _(SC_FL_SHUTR_NOW, _(SC_FL_SHUTW_NOW, _(SC_FL_SHUTR, _(SC_FL_SHUTW))))))))))))))))); /* epilogue */ _(~0U); return buf; diff --git a/src/activity.c b/src/activity.c index 010fd313ad..bfdd6f3e59 100644 --- a/src/activity.c +++ b/src/activity.c @@ -624,7 +624,8 @@ static int cli_io_handler_show_profiling(struct appctx *appctx) int max_lines; int i, j, max; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side ! */ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; chunk_reset(&trash); @@ -887,7 +888,8 @@ static int cli_io_handler_show_tasks(struct appctx *appctx) int thr, queue; int i, max; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side ! */ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; /* It's not possible to scan queues in small chunks and yield in the @@ -1027,7 +1029,8 @@ static int cli_io_handler_show_activity(struct appctx *appctx) struct timeval up; int thr; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side ! */ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; chunk_reset(&trash); diff --git a/src/applet.c b/src/applet.c index 3ed3c7a1de..0c5b40de14 100644 --- a/src/applet.c +++ b/src/applet.c @@ -471,7 +471,7 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state) (b_size(sc_ib(sc)) && !b_data(sc_ib(sc)) && sc->flags & SC_FL_NEED_ROOM) || // asks for room in an empty buffer (b_data(sc_ob(sc)) && sc_is_send_allowed(sc)) || // asks for data already present (!b_data(sc_ib(sc)) && b_data(sc_ob(sc)) && // didn't return anything ... - (sc_oc(sc)->flags & (CF_WRITE_EVENT|CF_SHUTW_NOW)) == CF_SHUTW_NOW))) { // ... and left data pending after a shut + (!(sc_oc(sc)->flags & CF_WRITE_EVENT) && (chn_cons(sc_oc(sc))->flags & SC_FL_SHUTW_NOW))))) { // ... and left data pending after a shut rate = update_freq_ctr(&app->call_rate, 1); if (rate >= 100000 && app->call_rate.prev_ctr) // looped like this more than 100k times over last second stream_dump_and_crash(&app->obj_type, read_freq_ctr(&app->call_rate)); diff --git a/src/backend.c b/src/backend.c index af39fefde1..4fa5f245e9 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1956,7 +1956,7 @@ int srv_redispatch_connect(struct stream *s) static int back_may_abort_req(struct channel *req, struct stream *s) { return (sc_ep_test(s->scf, SE_FL_ERROR) || - ((req->flags & (CF_SHUTW_NOW|CF_SHUTW)) && /* empty and client aborted */ + ((chn_cons(req)->flags & (SC_FL_SHUTW_NOW|SC_FL_SHUTW)) && /* empty and client aborted */ (channel_is_empty(req) || (s->be->options & PR_O_ABRT_CLOSE)))); } @@ -2246,8 +2246,8 @@ void back_handle_st_con(struct stream *s) DBG_TRACE_ENTER(STRM_EV_STRM_PROC|STRM_EV_CS_ST, s); /* the client might want to abort */ - if ((rep->flags & CF_SHUTW) || - ((req->flags & CF_SHUTW_NOW) && + if ((chn_cons(rep)->flags & SC_FL_SHUTW) || + ((chn_cons(req)->flags & SC_FL_SHUTW_NOW) && (channel_is_empty(req) || (s->be->options & PR_O_ABRT_CLOSE)))) { sc->flags |= SC_FL_NOLINGER; sc_shutw(sc); @@ -2470,8 +2470,8 @@ void back_handle_st_rdy(struct stream *s) */ if (!(req->flags & CF_WROTE_DATA)) { /* client abort ? */ - if ((rep->flags & CF_SHUTW) || - ((req->flags & CF_SHUTW_NOW) && + if ((chn_cons(rep)->flags & SC_FL_SHUTW) || + ((chn_cons(req)->flags & SC_FL_SHUTW_NOW) && (channel_is_empty(req) || (s->be->options & PR_O_ABRT_CLOSE)))) { /* give up */ sc->flags |= SC_FL_NOLINGER; diff --git a/src/channel.c b/src/channel.c index 68360d99d2..70c79311ad 100644 --- a/src/channel.c +++ b/src/channel.c @@ -206,8 +206,8 @@ int co_getdelim(const struct channel *chn, char *str, int len, const char *delim max = len; /* closed or empty + imminent close = -1; empty = 0 */ - if (unlikely((chn->flags & CF_SHUTW) || channel_is_empty(chn))) { - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (unlikely((chn_cons(chn)->flags & SC_FL_SHUTW) || channel_is_empty(chn))) { + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) ret = -1; goto out; } @@ -252,7 +252,7 @@ int co_getdelim(const struct channel *chn, char *str, int len, const char *delim if (ret > 0 && ret < len && (ret < co_data(chn) || channel_may_recv(chn)) && !found && - !(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) + !(chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) ret = 0; out: if (max) @@ -279,8 +279,8 @@ int co_getword(const struct channel *chn, char *str, int len, char sep) max = len; /* closed or empty + imminent close = -1; empty = 0 */ - if (unlikely((chn->flags & CF_SHUTW) || channel_is_empty(chn))) { - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (unlikely((chn_cons(chn)->flags & SC_FL_SHUTW) || channel_is_empty(chn))) { + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) ret = -1; goto out; } @@ -303,7 +303,7 @@ int co_getword(const struct channel *chn, char *str, int len, char sep) if (ret > 0 && ret < len && (ret < co_data(chn) || channel_may_recv(chn)) && *(str-1) != sep && - !(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) + !(chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) ret = 0; out: if (max) @@ -330,8 +330,8 @@ int co_getline(const struct channel *chn, char *str, int len) max = len; /* closed or empty + imminent close = -1; empty = 0 */ - if (unlikely((chn->flags & CF_SHUTW) || channel_is_empty(chn))) { - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (unlikely((chn_cons(chn)->flags & SC_FL_SHUTW) || channel_is_empty(chn))) { + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) ret = -1; goto out; } @@ -354,7 +354,7 @@ int co_getline(const struct channel *chn, char *str, int len) if (ret > 0 && ret < len && (ret < co_data(chn) || channel_may_recv(chn)) && *(str-1) != '\n' && - !(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) + !(chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) ret = 0; out: if (max) @@ -372,11 +372,11 @@ int co_getline(const struct channel *chn, char *str, int len) */ int co_getchar(const struct channel *chn, char *c) { - if (chn->flags & CF_SHUTW) + if (chn_cons(chn)->flags & SC_FL_SHUTW) return -1; if (unlikely(co_data(chn) == 0)) { - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) return -1; return 0; } @@ -395,11 +395,11 @@ int co_getchar(const struct channel *chn, char *c) */ int co_getblk(const struct channel *chn, char *blk, int len, int offset) { - if (chn->flags & CF_SHUTW) + if (chn_cons(chn)->flags & SC_FL_SHUTW) return -1; if (len + offset > co_data(chn) || co_data(chn) == 0) { - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) return -1; return 0; } @@ -418,7 +418,7 @@ int co_getblk(const struct channel *chn, char *blk, int len, int offset) int co_getblk_nc(const struct channel *chn, const char **blk1, size_t *len1, const char **blk2, size_t *len2) { if (unlikely(co_data(chn) == 0)) { - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) return -1; return 0; } @@ -460,7 +460,7 @@ int co_getline_nc(const struct channel *chn, } } - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) { + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) { /* If we have found no LF and the buffer is shut, then * the resulting string is made of the concatenation of * the pending blocks (1 or 2). @@ -484,7 +484,7 @@ int ci_getblk_nc(const struct channel *chn, char **blk2, size_t *len2) { if (unlikely(ci_data(chn) == 0)) { - if (chn->flags & CF_SHUTR) + if (chn_prod(chn)->flags & SC_FL_SHUTR) return -1; return 0; } @@ -536,7 +536,7 @@ int ci_getline_nc(const struct channel *chn, } } - if (chn->flags & CF_SHUTW) { + if (chn_cons(chn)->flags & SC_FL_SHUTW) { /* If we have found no LF and the buffer is shut, then * the resulting string is made of the concatenation of * the pending blocks (1 or 2). diff --git a/src/cli.c b/src/cli.c index 1c942e1b2f..21d662055b 100644 --- a/src/cli.c +++ b/src/cli.c @@ -1213,7 +1213,8 @@ static int cli_io_handler_show_env(struct appctx *appctx) struct stconn *sc = appctx_sc(appctx); char **var = ctx->var; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; chunk_reset(&trash); @@ -1251,7 +1252,8 @@ static int cli_io_handler_show_fd(struct appctx *appctx) int fd = fdctx->fd; int ret = 1; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) goto end; chunk_reset(&trash); @@ -2685,7 +2687,7 @@ send_status: goto read_again; missing_data: - if (req->flags & CF_SHUTR) { + if (chn_prod(req)->flags & SC_FL_SHUTR) { /* There is no more request or a only a partial one and we * receive a close from the client, we can leave */ channel_shutw_now(&s->res); @@ -2709,7 +2711,7 @@ int pcli_wait_for_response(struct stream *s, struct channel *rep, int an_bit) struct proxy *be = s->be; if (sc_ep_test(s->scb, SE_FL_ERR_PENDING|SE_FL_ERROR) || (rep->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) || - ((rep->flags & CF_SHUTW) && (rep->to_forward || co_data(rep)))) { + ((chn_cons(rep)->flags & SC_FL_SHUTW) && (rep->to_forward || co_data(rep)))) { pcli_reply_and_close(s, "Can't connect to the target CLI!\n"); s->req.analysers &= ~AN_REQ_WAIT_CLI; s->res.analysers &= ~AN_RES_WAIT_CLI; @@ -2734,7 +2736,7 @@ int pcli_wait_for_response(struct stream *s, struct channel *rep, int an_bit) return 0; } - if (rep->flags & CF_SHUTR) { + if (chn_prod(rep)->flags & SC_FL_SHUTR) { /* stream cleanup */ pcli_write_prompt(s); @@ -2823,9 +2825,11 @@ int pcli_wait_for_response(struct stream *s, struct channel *rep, int an_bit) sockaddr_free(&s->scb->dst); sc_set_state(s->scb, SC_ST_INI); + s->scb->flags &= ~(SC_FL_SHUTW|SC_FL_SHUTW_NOW); s->scb->flags &= SC_FL_ISBACK | SC_FL_DONT_WAKE; /* we're in the context of process_stream */ - s->req.flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_STREAMER|CF_STREAMER_FAST|CF_WROTE_DATA); - s->res.flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_EVENT|CF_WROTE_DATA|CF_READ_EVENT); + + s->req.flags &= ~(CF_AUTO_CONNECT|CF_STREAMER|CF_STREAMER_FAST|CF_WROTE_DATA); + s->res.flags &= ~(CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_EVENT|CF_WROTE_DATA|CF_READ_EVENT); s->flags &= ~(SF_DIRECT|SF_ASSIGNED|SF_BE_ASSIGNED|SF_FORCE_PRST|SF_IGNORE_PRST); s->flags &= ~(SF_CURR_SESS|SF_REDIRECTABLE|SF_SRV_REUSED); s->flags &= ~(SF_ERR_MASK|SF_FINST_MASK|SF_REDISP); @@ -2846,6 +2850,7 @@ int pcli_wait_for_response(struct stream *s, struct channel *rep, int an_bit) s->store_count = 0; s->uniq_id = global.req_count++; + s->scf->flags &= ~(SC_FL_SHUTR|SC_FL_SHUTR_NOW); s->scf->flags &= ~SC_FL_SND_NEVERWAIT; s->scf->flags |= SC_FL_RCV_ONCE; /* one read is usually enough */ diff --git a/src/debug.c b/src/debug.c index 3d159fd3fd..5209166ed8 100644 --- a/src/debug.c +++ b/src/debug.c @@ -313,7 +313,8 @@ static int cli_io_handler_show_threads(struct appctx *appctx) struct stconn *sc = appctx_sc(appctx); int thr; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; if (appctx->st0) @@ -1160,7 +1161,8 @@ static int debug_iohandler_fd(struct appctx *appctx) int ret = 1; int i, fd; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) goto end; chunk_reset(&trash); @@ -1367,7 +1369,8 @@ static int debug_iohandler_memstats(struct appctx *appctx) const char *pfx = ctx->match; int ret = 1; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) goto end; if (!ctx->width) { diff --git a/src/filters.c b/src/filters.c index 92aeb3a735..7bd52ee433 100644 --- a/src/filters.c +++ b/src/filters.c @@ -1016,11 +1016,11 @@ flt_xfer_data(struct stream *s, struct channel *chn, unsigned int an_bit) * - the input in closed and no data is pending * - There is a READ/WRITE timeout */ - if (chn->flags & CF_SHUTW) { + if (chn_cons(chn)->flags & SC_FL_SHUTW) { ret = 1; goto end; } - if (chn->flags & CF_SHUTR) { + if (chn_prod(chn)->flags & SC_FL_SHUTR) { if (((s->flags & SF_HTX) && htx_is_empty(htxbuf(&chn->buf))) || c_empty(chn)) { ret = 1; goto end; diff --git a/src/flt_bwlim.c b/src/flt_bwlim.c index e14b774912..52fffd5010 100644 --- a/src/flt_bwlim.c +++ b/src/flt_bwlim.c @@ -151,7 +151,7 @@ static int bwlim_apply_limit(struct filter *filter, struct channel *chn, unsigne */ ret = tokens; if (tokens < conf->min_size) { - ret = ((chn_prod(chn)->flags & SC_FL_EOI) || (chn->flags & CF_SHUTR)) + ret = (chn_prod(chn)->flags & (SC_FL_EOI|SC_FL_SHUTR)) ? MIN(len, conf->min_size) : conf->min_size; diff --git a/src/http_ana.c b/src/http_ana.c index 6a309c77c8..e319a287d0 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -114,7 +114,7 @@ int http_wait_for_request(struct stream *s, struct channel *req, int an_bit) /* A SHUTR at this stage means we are performing a "destructive" * HTTP upgrade (TCP>H2). In this case, we can leave. */ - if (req->flags & CF_SHUTR) { + if (chn_prod(req)->flags & SC_FL_SHUTR) { s->logs.logwait = 0; s->logs.level = 0; channel_abort(&s->req); @@ -767,7 +767,7 @@ int http_process_tarpit(struct stream *s, struct channel *req, int an_bit) * there and that the timeout has not expired. */ channel_dont_connect(req); - if (!(req->flags & CF_SHUTR) && + if (!(chn_prod(req)->flags & SC_FL_SHUTR) && !tick_is_expired(req->analyse_exp, now_ms)) { /* Be sure to drain all data from the request channel */ channel_htx_erase(req, htxbuf(&req->buf)); @@ -985,7 +985,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit) if (!(txn->flags & TX_CON_WANT_TUN)) channel_dont_close(req); - if ((req->flags & CF_SHUTW) && co_data(req)) { + if ((chn_cons(req)->flags & SC_FL_SHUTW) && co_data(req)) { /* request errors are most likely due to the server aborting the * transfer. */ goto return_srv_abort; @@ -1004,7 +1004,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit) * it can be abused to exhaust source ports. */ if (s->be->options & PR_O_ABRT_CLOSE) { channel_auto_read(req); - if ((req->flags & CF_SHUTR) && !(txn->flags & TX_CON_WANT_TUN)) + if ((chn_prod(req)->flags & SC_FL_SHUTR) && !(txn->flags & TX_CON_WANT_TUN)) s->scb->flags |= SC_FL_NOLINGER; channel_auto_close(req); } @@ -1020,12 +1020,12 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit) missing_data_or_waiting: /* stop waiting for data if the input is closed before the end */ - if (msg->msg_state < HTTP_MSG_ENDING && req->flags & CF_SHUTR) + if (msg->msg_state < HTTP_MSG_ENDING && chn_prod(req)->flags & SC_FL_SHUTR) goto return_cli_abort; waiting: /* waiting for the last bits to leave the buffer */ - if (req->flags & CF_SHUTW) + if (chn_cons(req)->flags & SC_FL_SHUTW) goto return_srv_abort; /* When TE: chunked is used, we need to get there again to parse remaining @@ -1132,9 +1132,11 @@ static __inline int do_l7_retry(struct stream *s, struct stconn *sc) req = &s->req; res = &s->res; + /* Remove any write error from the request, and read error from the response */ - req->flags &= ~(CF_WRITE_TIMEOUT | CF_SHUTW | CF_SHUTW_NOW); - res->flags &= ~(CF_READ_TIMEOUT | CF_SHUTR | CF_READ_EVENT | CF_SHUTR_NOW); + s->scf->flags &= ~(SC_FL_SHUTR|SC_FL_SHUTR_NOW); + req->flags &= ~CF_WRITE_TIMEOUT; + res->flags &= ~(CF_READ_TIMEOUT | CF_READ_EVENT); res->analysers &= AN_RES_FLT_END; s->conn_err_type = STRM_ET_NONE; s->flags &= ~(SF_CONN_EXP | SF_ERR_MASK | SF_FINST_MASK); @@ -1144,6 +1146,7 @@ static __inline int do_l7_retry(struct stream *s, struct stconn *sc) res->analyse_exp = TICK_ETERNITY; res->total = 0; + s->scb->flags &= ~(SC_FL_SHUTW|SC_FL_SHUTW_NOW); if (sc_reset_endp(s->scb) < 0) { if (!(s->flags & SF_ERR_MASK)) s->flags |= SF_ERR_INTERNAL; @@ -1293,7 +1296,9 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) } /* 3: client abort with an abortonclose */ - else if ((rep->flags & CF_SHUTR) && ((s->req.flags & (CF_SHUTR|CF_SHUTW)) == (CF_SHUTR|CF_SHUTW))) { + else if ((chn_prod(rep)->flags & SC_FL_SHUTR) && + (chn_prod(&s->req)->flags & SC_FL_SHUTR) && + (chn_cons(&s->req)->flags & SC_FL_SHUTW)) { _HA_ATOMIC_INC(&sess->fe->fe_counters.cli_aborts); _HA_ATOMIC_INC(&s->be->be_counters.cli_aborts); if (sess->listener && sess->listener->counters) @@ -1315,7 +1320,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit) } /* 4: close from server, capture the response if the server has started to respond */ - else if (rep->flags & CF_SHUTR) { + else if (chn_prod(rep)->flags & SC_FL_SHUTR) { if ((txn->flags & TX_L7_RETRY) && (s->be->retry_type & PR_RE_DISCONNECTED)) { if (co_data(rep) || do_l7_retry(s, s->scb) == 0) { @@ -2057,7 +2062,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit if (htx->data != co_data(res)) goto missing_data_or_waiting; - if (!(msg->flags & HTTP_MSGF_XFER_LEN) && res->flags & CF_SHUTR) { + if (!(msg->flags & HTTP_MSGF_XFER_LEN) && (chn_prod(res)->flags & SC_FL_SHUTR)) { msg->msg_state = HTTP_MSG_ENDING; goto ending; } @@ -2101,7 +2106,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit channel_dont_close(res); - if ((res->flags & CF_SHUTW) && co_data(res)) { + if ((chn_cons(res)->flags & SC_FL_SHUTW) && co_data(res)) { /* response errors are most likely due to the client aborting * the transfer. */ goto return_cli_abort; @@ -2117,7 +2122,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit return 0; missing_data_or_waiting: - if (res->flags & CF_SHUTW) + if (chn_cons(res)->flags & SC_FL_SHUTW) goto return_cli_abort; /* stop waiting for data if the input is closed before the end. If the @@ -2125,8 +2130,9 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit * so we don't want to count this as a server abort. Otherwise it's a * server abort. */ - if (msg->msg_state < HTTP_MSG_ENDING && res->flags & CF_SHUTR) { - if ((s->req.flags & (CF_SHUTR|CF_SHUTW)) == (CF_SHUTR|CF_SHUTW)) + if (msg->msg_state < HTTP_MSG_ENDING && (chn_prod(res)->flags & SC_FL_SHUTR)) { + if ((chn_prod(&s->req)->flags & SC_FL_SHUTR) && + (chn_cons(&s->req)->flags & SC_FL_SHUTW)) goto return_cli_abort; /* If we have some pending data, we continue the processing */ if (htx_is_empty(htx)) @@ -2670,7 +2676,7 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis /* Always call the action function if defined */ if (rule->action_ptr) { if (sc_ep_test(s->scf, SE_FL_ERROR) || - ((s->req.flags & CF_SHUTR) && + ((chn_prod(&s->req)->flags & SC_FL_SHUTR) && (px->options & PR_O_ABRT_CLOSE))) act_opts |= ACT_OPT_FINAL; @@ -2833,7 +2839,7 @@ resume_execution: /* Always call the action function if defined */ if (rule->action_ptr) { if (sc_ep_test(s->scf, SE_FL_ERROR) || - ((s->req.flags & CF_SHUTR) && + ((chn_prod(&s->req)->flags & SC_FL_SHUTR) && (px->options & PR_O_ABRT_CLOSE))) act_opts |= ACT_OPT_FINAL; @@ -4081,7 +4087,7 @@ enum rule_result http_wait_for_msg_body(struct stream *s, struct channel *chn, } /* we get here if we need to wait for more data */ - if (!(chn->flags & CF_SHUTR)) { + if (!(chn_prod(chn)->flags & SC_FL_SHUTR)) { if (!tick_isset(chn->analyse_exp)) chn->analyse_exp = tick_add_ifset(now_ms, time); ret = HTTP_RULE_RES_YIELD; @@ -4270,7 +4276,7 @@ static void http_end_request(struct stream *s) txn->rsp.msg_state != HTTP_MSG_CLOSED) goto check_channel_flags; - if (!(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) { + if (!(chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) { channel_shutr_now(chn); channel_shutw_now(chn); } @@ -4304,7 +4310,7 @@ static void http_end_request(struct stream *s) check_channel_flags: /* Here, we are in HTTP_MSG_DONE or HTTP_MSG_TUNNEL */ - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) { + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) { /* if we've just closed an output, let's switch */ txn->req.msg_state = HTTP_MSG_CLOSING; goto http_msg_closing; @@ -4369,7 +4375,7 @@ static void http_end_response(struct stream *s) /* we're not expecting any new data to come for this * transaction, so we can close it. */ - if (!(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) { + if (!(chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) { channel_shutr_now(chn); channel_shutw_now(chn); } @@ -4400,7 +4406,7 @@ static void http_end_response(struct stream *s) check_channel_flags: /* Here, we are in HTTP_MSG_DONE or HTTP_MSG_TUNNEL */ - if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) { + if (chn_cons(chn)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) { /* if we've just closed an output, let's switch */ txn->rsp.msg_state = HTTP_MSG_CLOSING; goto http_msg_closing; diff --git a/src/http_fetch.c b/src/http_fetch.c index 2485eb3449..d75541d8e4 100644 --- a/src/http_fetch.c +++ b/src/http_fetch.c @@ -615,7 +615,7 @@ static int smp_fetch_body(const struct arg *args, struct sample *smp, const char smp->flags = SMP_F_VOL_TEST; if (!finished && (check || (chn && !channel_full(chn, global.tune.maxrewrite) && - !(chn_prod(chn)->flags & SC_FL_EOI) && !(chn->flags & CF_SHUTR)))) + !(chn_prod(chn)->flags & (SC_FL_EOI|SC_FL_SHUTR))))) smp->flags |= SMP_F_MAY_CHANGE; return 1; diff --git a/src/map.c b/src/map.c index 9713041572..ff6bbf59ad 100644 --- a/src/map.c +++ b/src/map.c @@ -348,7 +348,8 @@ static int cli_io_handler_pat_list(struct appctx *appctx) struct stconn *sc = appctx_sc(appctx); struct pat_ref_elt *elt; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) { + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) { /* If we're forced to shut down, we might have to remove our * reference to the last ref_elt being dumped. */ diff --git a/src/mworker.c b/src/mworker.c index d71bf61564..17609f6ce0 100644 --- a/src/mworker.c +++ b/src/mworker.c @@ -567,7 +567,8 @@ static int cli_io_handler_show_proc(struct appctx *appctx) char *uptime = NULL; char *reloadtxt = NULL; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; if (up < 0) /* must never be negative because of clock drift */ @@ -713,10 +714,10 @@ static int cli_io_handler_show_loadstatus(struct appctx *appctx) if (!cli_has_level(appctx, ACCESS_LVL_OPER)) return 1; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; - env = getenv("HAPROXY_LOAD_SUCCESS"); if (!env) return 1; diff --git a/src/proxy.c b/src/proxy.c index f08ec93d83..276228c345 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -3208,7 +3208,8 @@ static int cli_io_handler_show_errors(struct appctx *appctx) struct stconn *sc = appctx_sc(appctx); extern const char *monthname[12]; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; chunk_reset(&trash); diff --git a/src/quic_conn.c b/src/quic_conn.c index 42abe0712b..a09216e463 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -8261,7 +8261,8 @@ static int cli_io_handler_dump_quic(struct appctx *appctx) if (ctx->thr >= global.nbthread) goto done; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) { + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) { /* If we're forced to shut down, we might have to remove our * reference to the last stream being dumped. */ diff --git a/src/ring.c b/src/ring.c index c3baf88af8..6d75f0510d 100644 --- a/src/ring.c +++ b/src/ring.c @@ -349,7 +349,8 @@ int cli_io_handler_show_ring(struct appctx *appctx) size_t len, cnt; int ret; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) return 1; HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &ring->lock); @@ -422,7 +423,7 @@ int cli_io_handler_show_ring(struct appctx *appctx) /* we've drained everything and are configured to wait for more * data or an event (keypress, close) */ - if (!sc_oc(sc)->output && !(sc_oc(sc)->flags & CF_SHUTW)) { + if (!sc_oc(sc)->output && !(chn_cons(sc_oc(sc))->flags & SC_FL_SHUTW)) { /* let's be woken up once new data arrive */ HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &ring->lock); LIST_APPEND(&ring->waiters, &appctx->wait_entry); diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c index 6342787a95..bfb4235e4e 100644 --- a/src/ssl_ckch.c +++ b/src/ssl_ckch.c @@ -2148,7 +2148,8 @@ static int cli_io_handler_commit_cert(struct appctx *appctx) struct ckch_store *old_ckchs, *new_ckchs = NULL; struct ckch_inst *ckchi; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) goto end; while (1) { @@ -2824,7 +2825,8 @@ static int cli_io_handler_commit_cafile_crlfile(struct appctx *appctx) struct ckch_inst_link *ckchi_link; char *path; - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) goto end; /* The ctx was already validated by the ca-file/crl-file parsing diff --git a/src/ssl_crtlist.c b/src/ssl_crtlist.c index c31714d4e2..7b410e9ce2 100644 --- a/src/ssl_crtlist.c +++ b/src/ssl_crtlist.c @@ -1116,7 +1116,8 @@ static int cli_io_handler_add_crtlist(struct appctx *appctx) /* for each bind_conf which use the crt-list, a new ckch_inst must be * created. */ - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) goto end; switch (ctx->state) { diff --git a/src/stats.c b/src/stats.c index 5ce61ee664..1f80509878 100644 --- a/src/stats.c +++ b/src/stats.c @@ -4473,7 +4473,7 @@ static void http_stats_io_handler(struct appctx *appctx) if (appctx->st0 == STAT_HTTP_POST) { if (stats_process_http_post(sc)) appctx->st0 = STAT_HTTP_LAST; - else if (req->flags & CF_SHUTR) + else if (chn_prod(req)->flags & SC_FL_SHUTR) appctx->st0 = STAT_HTTP_DONE; } diff --git a/src/stconn.c b/src/stconn.c index d1aa1b5c62..5d94646584 100644 --- a/src/stconn.c +++ b/src/stconn.c @@ -501,13 +501,13 @@ struct appctx *sc_applet_create(struct stconn *sc, struct applet *app) /* Conditionally forward the close to the write side. It return 1 if it can be * forwarded. It is the caller responsibility to forward the close to the write - * side. Otherwise, 0 is returned. In this case, CF_SHUTW_NOW flag may be set on - * the channel if we are only waiting for the outgoing data to be flushed. + * side. Otherwise, 0 is returned. In this case, SC_FL_SHUTW_NOW flag may be set on + * the consumer SC if we are only waiting for the outgoing data to be flushed. */ static inline int sc_cond_forward_shutw(struct stconn *sc) { /* The close must not be forwarded */ - if (!(sc_ic(sc)->flags & CF_SHUTR) || !(sc->flags & SC_FL_NOHALF)) + if (!(chn_prod(sc_ic(sc))->flags & SC_FL_SHUTR) || !(sc->flags & SC_FL_NOHALF)) return 0; if (!channel_is_empty(sc_ic(sc))) { @@ -534,15 +534,17 @@ static void sc_app_shutr(struct stconn *sc) { struct channel *ic = sc_ic(sc); - if (ic->flags & CF_SHUTR) + if (chn_prod(ic)->flags & SC_FL_SHUTR) return; - ic->flags |= CF_SHUTR|CF_READ_EVENT; + + chn_prod(ic)->flags |= SC_FL_SHUTR; + ic->flags |= CF_READ_EVENT; sc_ep_report_read_activity(sc); if (!sc_state_in(sc->state, SC_SB_CON|SC_SB_RDY|SC_SB_EST)) return; - if (sc_oc(sc)->flags & CF_SHUTW) { + if (chn_cons(sc_oc(sc))->flags & SC_FL_SHUTW) { sc->state = SC_ST_DIS; if (sc->flags & SC_FL_ISBACK) __sc_strm(sc)->conn_exp = TICK_ETERNITY; @@ -567,10 +569,11 @@ static void sc_app_shutw(struct stconn *sc) struct channel *ic = sc_ic(sc); struct channel *oc = sc_oc(sc); - oc->flags &= ~CF_SHUTW_NOW; - if (oc->flags & CF_SHUTW) + chn_cons(oc)->flags &= ~SC_FL_SHUTW_NOW; + if (chn_cons(oc)->flags & SC_FL_SHUTW) return; - oc->flags |= CF_SHUTW|CF_WRITE_EVENT; + chn_cons(oc)->flags |= SC_FL_SHUTW; + oc->flags |= CF_WRITE_EVENT; sc_set_hcto(sc); switch (sc->state) { @@ -583,7 +586,7 @@ static void sc_app_shutw(struct stconn *sc) * no risk so we close both sides immediately. */ if (!sc_ep_test(sc, SE_FL_ERROR) && !(sc->flags & SC_FL_NOLINGER) && - !(ic->flags & (CF_SHUTR|CF_DONT_READ))) + !(chn_prod(ic)->flags & SC_FL_SHUTR) && !(ic->flags & CF_DONT_READ)) return; __fallthrough; @@ -596,7 +599,7 @@ static void sc_app_shutw(struct stconn *sc) __fallthrough; default: sc->flags &= ~SC_FL_NOLINGER; - ic->flags |= CF_SHUTR; + chn_prod(ic)->flags |= SC_FL_SHUTR; if (sc->flags & SC_FL_ISBACK) __sc_strm(sc)->conn_exp = TICK_ETERNITY; } @@ -627,7 +630,7 @@ static void sc_app_chk_snd(struct stconn *sc) { struct channel *oc = sc_oc(sc); - if (unlikely(sc->state != SC_ST_EST || (oc->flags & CF_SHUTW))) + if (unlikely(sc->state != SC_ST_EST || (chn_cons(oc)->flags & SC_FL_SHUTW))) return; if (!sc_ep_test(sc, SE_FL_WAIT_DATA) || /* not waiting for data */ @@ -658,14 +661,15 @@ static void sc_app_shutr_conn(struct stconn *sc) BUG_ON(!sc_conn(sc)); - if (ic->flags & CF_SHUTR) + if (chn_prod(ic)->flags & SC_FL_SHUTR) return; - ic->flags |= CF_SHUTR|CF_READ_EVENT; + chn_prod(ic)->flags |= SC_FL_SHUTR; + ic->flags |= CF_READ_EVENT; if (!sc_state_in(sc->state, SC_SB_CON|SC_SB_RDY|SC_SB_EST)) return; - if (sc_oc(sc)->flags & CF_SHUTW) { + if (chn_cons(sc_oc(sc))->flags & SC_FL_SHUTW) { sc_conn_shut(sc); sc->state = SC_ST_DIS; if (sc->flags & SC_FL_ISBACK) @@ -690,10 +694,11 @@ static void sc_app_shutw_conn(struct stconn *sc) BUG_ON(!sc_conn(sc)); - oc->flags &= ~CF_SHUTW_NOW; - if (oc->flags & CF_SHUTW) + chn_cons(oc)->flags &= ~SC_FL_SHUTW_NOW; + if (chn_cons(oc)->flags & SC_FL_SHUTW) return; - oc->flags |= CF_SHUTW|CF_WRITE_EVENT; + chn_cons(oc)->flags |= SC_FL_SHUTW; + oc->flags |= CF_WRITE_EVENT; sc_set_hcto(sc); switch (sc->state) { @@ -726,7 +731,7 @@ static void sc_app_shutw_conn(struct stconn *sc) */ sc_conn_shutw(sc, CO_SHW_NORMAL); - if (!(ic->flags & (CF_SHUTR|CF_DONT_READ))) + if (!(chn_prod(ic)->flags & SC_FL_SHUTR) && !(ic->flags & CF_DONT_READ)) return; } @@ -744,7 +749,7 @@ static void sc_app_shutw_conn(struct stconn *sc) __fallthrough; default: sc->flags &= ~SC_FL_NOLINGER; - ic->flags |= CF_SHUTR; + chn_prod(ic)->flags |= SC_FL_SHUTR; if (sc->flags & SC_FL_ISBACK) __sc_strm(sc)->conn_exp = TICK_ETERNITY; } @@ -778,7 +783,7 @@ static void sc_app_chk_snd_conn(struct stconn *sc) BUG_ON(!sc_conn(sc)); if (unlikely(!sc_state_in(sc->state, SC_SB_RDY|SC_SB_EST) || - (oc->flags & CF_SHUTW))) + (chn_cons(oc)->flags & SC_FL_SHUTW))) return; if (unlikely(channel_is_empty(oc))) /* called with nothing to send ! */ @@ -807,14 +812,14 @@ static void sc_app_chk_snd_conn(struct stconn *sc) * ->o limit was reached. Maybe we just wrote the last * chunk and need to close. */ - if (((oc->flags & (CF_SHUTW|CF_AUTO_CLOSE|CF_SHUTW_NOW)) == - (CF_AUTO_CLOSE|CF_SHUTW_NOW)) && + if ((oc->flags & CF_AUTO_CLOSE) && + ((chn_cons(oc)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) == SC_FL_SHUTW_NOW) && sc_state_in(sc->state, SC_SB_RDY|SC_SB_EST)) { sc_shutw(sc); goto out_wakeup; } - if ((oc->flags & (CF_SHUTW|CF_SHUTW_NOW)) == 0) + if ((chn_cons(oc)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) == 0) sc_ep_set(sc, SE_FL_WAIT_DATA); } else { @@ -827,7 +832,7 @@ static void sc_app_chk_snd_conn(struct stconn *sc) /* in case of special condition (error, shutdown, end of write...), we * have to notify the task. */ - if (likely((oc->flags & CF_SHUTW) || + if (likely((chn_cons(oc)->flags & SC_FL_SHUTW) || ((oc->flags & CF_WRITE_EVENT) && sc->state < SC_ST_EST) || ((oc->flags & CF_WAKE_WRITE) && ((channel_is_empty(oc) && !oc->to_forward) || @@ -852,16 +857,17 @@ static void sc_app_shutr_applet(struct stconn *sc) BUG_ON(!sc_appctx(sc)); - if (ic->flags & CF_SHUTR) + if (chn_prod(ic)->flags & SC_FL_SHUTR) return; - ic->flags |= CF_SHUTR|CF_READ_EVENT; + chn_prod(ic)->flags |= SC_FL_SHUTR; + ic->flags |= CF_READ_EVENT; /* Note: on shutr, we don't call the applet */ if (!sc_state_in(sc->state, SC_SB_CON|SC_SB_RDY|SC_SB_EST)) return; - if (sc_oc(sc)->flags & CF_SHUTW) { + if (chn_cons(sc_oc(sc))->flags & SC_FL_SHUTW) { appctx_shut(__sc_appctx(sc)); sc->state = SC_ST_DIS; if (sc->flags & SC_FL_ISBACK) @@ -885,10 +891,11 @@ static void sc_app_shutw_applet(struct stconn *sc) BUG_ON(!sc_appctx(sc)); - oc->flags &= ~CF_SHUTW_NOW; - if (oc->flags & CF_SHUTW) + chn_cons(oc)->flags &= ~SC_FL_SHUTW_NOW; + if (chn_cons(oc)->flags & SC_FL_SHUTW) return; - oc->flags |= CF_SHUTW|CF_WRITE_EVENT; + chn_cons(oc)->flags |= SC_FL_SHUTW; + oc->flags |= CF_WRITE_EVENT; sc_set_hcto(sc); /* on shutw we always wake the applet up */ @@ -904,7 +911,8 @@ static void sc_app_shutw_applet(struct stconn *sc) * no risk so we close both sides immediately. */ if (!sc_ep_test(sc, SE_FL_ERROR) && !(sc->flags & SC_FL_NOLINGER) && - !(ic->flags & (CF_SHUTR|CF_DONT_READ))) + !(chn_prod(ic)->flags & SC_FL_SHUTR) && + !(ic->flags & CF_DONT_READ)) return; __fallthrough; @@ -918,7 +926,7 @@ static void sc_app_shutw_applet(struct stconn *sc) __fallthrough; default: sc->flags &= ~SC_FL_NOLINGER; - ic->flags |= CF_SHUTR; + chn_prod(ic)->flags |= SC_FL_SHUTR; if (sc->flags & SC_FL_ISBACK) __sc_strm(sc)->conn_exp = TICK_ETERNITY; } @@ -944,7 +952,7 @@ static void sc_app_chk_snd_applet(struct stconn *sc) BUG_ON(!sc_appctx(sc)); - if (unlikely(sc->state != SC_ST_EST || (oc->flags & CF_SHUTW))) + if (unlikely(sc->state != SC_ST_EST || (chn_cons(oc)->flags & SC_FL_SHUTW))) return; /* we only wake the applet up if it was waiting for some data and is ready to consume it */ @@ -971,7 +979,7 @@ void sc_update_rx(struct stconn *sc) { struct channel *ic = sc_ic(sc); - if (ic->flags & CF_SHUTR) + if (chn_prod(ic)->flags & SC_FL_SHUTR) return; /* Read not closed, update FD status and timeout for reads */ @@ -996,14 +1004,14 @@ void sc_update_tx(struct stconn *sc) { struct channel *oc = sc_oc(sc); - if (oc->flags & CF_SHUTW) + if (chn_cons(oc)->flags & SC_FL_SHUTW) return; /* Write not closed, update FD status and timeout for writes */ if (channel_is_empty(oc)) { /* stop writing */ if (!sc_ep_test(sc, SE_FL_WAIT_DATA)) { - if ((oc->flags & CF_SHUTW_NOW) == 0) + if ((chn_cons(oc)->flags & SC_FL_SHUTW_NOW) == 0) sc_ep_set(sc, SE_FL_WAIT_DATA); } return; @@ -1034,17 +1042,17 @@ static void sc_notify(struct stconn *sc) if (channel_is_empty(oc)) { struct connection *conn = sc_conn(sc); - if (((oc->flags & (CF_SHUTW|CF_SHUTW_NOW)) == CF_SHUTW_NOW) && + if (((chn_cons(oc)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) == SC_FL_SHUTW_NOW) && (sc->state == SC_ST_EST) && (!conn || !(conn->flags & (CO_FL_WAIT_XPRT | CO_FL_EARLY_SSL_HS)))) sc_shutw(sc); } /* indicate that we may be waiting for data from the output channel or - * we're about to close and can't expect more data if SHUTW_NOW is there. + * we're about to close and can't expect more data if SC_FL_SHUTW_NOW is there. */ - if (!(oc->flags & (CF_SHUTW|CF_SHUTW_NOW))) + if (!(chn_cons(oc)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) sc_ep_set(sc, SE_FL_WAIT_DATA); - else if ((oc->flags & (CF_SHUTW|CF_SHUTW_NOW)) == CF_SHUTW_NOW) + else if ((chn_cons(oc)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) == SC_FL_SHUTW_NOW) sc_ep_clr(sc, SE_FL_WAIT_DATA); if (oc->flags & CF_DONT_READ) @@ -1100,18 +1108,19 @@ static void sc_notify(struct stconn *sc) * data received and no fast-forwarding (CF_READ_EVENT + !to_forward) * read event while consumer side is not established (CF_READ_EVENT + sco->state != SC_ST_EST) */ - ((ic->flags & CF_READ_EVENT) && ((sc->flags & SC_FL_EOI) || (ic->flags & CF_SHUTR) || !ic->to_forward || sco->state != SC_ST_EST)) || + ((ic->flags & CF_READ_EVENT) && ((sc->flags & SC_FL_EOI) || (chn_prod(ic)->flags & SC_FL_SHUTR) || !ic->to_forward || sco->state != SC_ST_EST)) || sc_ep_test(sc, SE_FL_ERROR) || /* changes on the consumption side */ sc_ep_test(sc, SE_FL_ERR_PENDING) || ((oc->flags & CF_WRITE_EVENT) && ((sc->state < SC_ST_EST) || - (oc->flags & CF_SHUTW) || + (chn_cons(oc)->flags & SC_FL_SHUTW) || (((oc->flags & CF_WAKE_WRITE) || - !(oc->flags & (CF_AUTO_CLOSE|CF_SHUTW_NOW|CF_SHUTW))) && - (sco->state != SC_ST_EST || - (channel_is_empty(oc) && !oc->to_forward)))))) { + (!(oc->flags & CF_AUTO_CLOSE) && + !(chn_cons(oc)->flags & (SC_FL_SHUTW_NOW|SC_FL_SHUTW)))) && + (sco->state != SC_ST_EST || + (channel_is_empty(oc) && !oc->to_forward)))))) { task_wakeup(task, TASK_WOKEN_IO); } @@ -1131,15 +1140,16 @@ static void sc_conn_read0(struct stconn *sc) BUG_ON(!sc_conn(sc)); - if (ic->flags & CF_SHUTR) + if (chn_prod(ic)->flags & SC_FL_SHUTR) return; - ic->flags |= CF_SHUTR|CF_READ_EVENT; + chn_prod(ic)->flags |= SC_FL_SHUTR; + ic->flags |= CF_READ_EVENT; sc_ep_report_read_activity(sc); if (!sc_state_in(sc->state, SC_SB_CON|SC_SB_RDY|SC_SB_EST)) return; - if (oc->flags & CF_SHUTW) + if (chn_cons(oc)->flags & SC_FL_SHUTW) goto do_close; if (sc_cond_forward_shutw(sc)) { @@ -1156,8 +1166,8 @@ static void sc_conn_read0(struct stconn *sc) /* OK we completely close the socket here just as if we went through sc_shut[rw]() */ sc_conn_shut(sc); - oc->flags &= ~CF_SHUTW_NOW; - oc->flags |= CF_SHUTW; + chn_cons(oc)->flags &= ~SC_FL_SHUTW_NOW; + chn_cons(oc)->flags |= SC_FL_SHUTW; sc->state = SC_ST_DIS; if (sc->flags & SC_FL_ISBACK) @@ -1189,7 +1199,7 @@ static int sc_conn_recv(struct stconn *sc) return 0; /* maybe we were called immediately after an asynchronous shutr */ - if (ic->flags & CF_SHUTR) + if (chn_prod(ic)->flags & SC_FL_SHUTR) return 1; /* we must wait because the mux is not installed yet */ @@ -1320,7 +1330,7 @@ static int sc_conn_recv(struct stconn *sc) */ while (sc_ep_test(sc, SE_FL_RCV_MORE) || (!(conn->flags & CO_FL_HANDSHAKE) && - (!sc_ep_test(sc, SE_FL_ERROR | SE_FL_EOS)) && !(ic->flags & CF_SHUTR))) { + (!sc_ep_test(sc, SE_FL_ERROR | SE_FL_EOS)) && !(chn_prod(ic)->flags & SC_FL_SHUTR))) { int cur_flags = flags; /* Compute transient CO_RFL_* flags */ @@ -1361,7 +1371,7 @@ static int sc_conn_recv(struct stconn *sc) cur_read += ret; /* if we're allowed to directly forward data, we must update ->o */ - if (ic->to_forward && !(ic->flags & (CF_SHUTW|CF_SHUTW_NOW))) { + if (ic->to_forward && !(chn_cons(ic)->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) { unsigned long fwd = ret; if (ic->to_forward != CHN_INFINITE_FORWARD) { if (fwd > ic->to_forward) @@ -1484,7 +1494,7 @@ static int sc_conn_recv(struct stconn *sc) if (sc_ep_test(sc, SE_FL_ERROR)) ret = 1; else if (!(sc->flags & (SC_FL_WONT_READ|SC_FL_NEED_BUFF|SC_FL_NEED_ROOM)) && - !(ic->flags & CF_SHUTR)) { + !(chn_prod(ic)->flags & SC_FL_SHUTR)) { /* Subscribe to receive events if we're blocking on I/O */ conn->mux->subscribe(sc, SUB_RETRY_RECV, &sc->wait_event); se_have_no_more_data(sc->sedesc); @@ -1554,7 +1564,7 @@ static int sc_conn_send(struct stconn *sc) return 0; /* we might have been called just after an asynchronous shutw */ - if (oc->flags & CF_SHUTW) + if (chn_cons(oc)->flags & SC_FL_SHUTW) return 1; /* we must wait because the mux is not installed yet */ @@ -1599,9 +1609,10 @@ static int sc_conn_send(struct stconn *sc) ((oc->to_forward && oc->to_forward != CHN_INFINITE_FORWARD) || (sc->flags & SC_FL_SND_EXP_MORE) || (IS_HTX_STRM(s) && - (!(sco->flags & SC_FL_EOI) && !(oc->flags & CF_SHUTR) && htx_expect_more(htxbuf(&oc->buf)))))) || + (!(sco->flags & SC_FL_EOI) && !(chn_prod(oc)->flags & SC_FL_SHUTR) && htx_expect_more(htxbuf(&oc->buf)))))) || ((oc->flags & CF_ISRESP) && - ((oc->flags & (CF_AUTO_CLOSE|CF_SHUTW_NOW)) == (CF_AUTO_CLOSE|CF_SHUTW_NOW)))) + (oc->flags & CF_AUTO_CLOSE) && + (chn_cons(oc)->flags & SC_FL_SHUTW_NOW))) send_flag |= CO_SFL_MSG_MORE; if (oc->flags & CF_STREAMER) @@ -1685,7 +1696,7 @@ void sc_conn_sync_send(struct stconn *sc) oc->flags &= ~CF_WRITE_EVENT; - if (oc->flags & CF_SHUTW) + if (chn_cons(oc)->flags & SC_FL_SHUTW) return; if (channel_is_empty(oc)) @@ -1763,7 +1774,7 @@ static int sc_conn_process(struct stconn *sc) * wake callback. Otherwise sc_conn_recv()/sc_conn_send() already take * care of it. */ - if (sc_ep_test(sc, SE_FL_EOS) && !(ic->flags & CF_SHUTR)) { + if (sc_ep_test(sc, SE_FL_EOS) && !(chn_prod(ic)->flags & SC_FL_SHUTR)) { /* we received a shutdown */ if (ic->flags & CF_AUTO_CLOSE) channel_shutw_now(ic); @@ -1842,7 +1853,7 @@ static int sc_applet_process(struct stconn *sc) /* If the applet wants to write and the channel is closed, it's a * broken pipe and it must be reported. */ - if (!sc_ep_test(sc, SE_FL_HAVE_NO_DATA) && (ic->flags & CF_SHUTR)) + if (!sc_ep_test(sc, SE_FL_HAVE_NO_DATA) && (chn_prod(ic)->flags & SC_FL_SHUTR)) sc_ep_set(sc, SE_FL_ERROR); /* automatically mark the applet having data available if it reported diff --git a/src/stick_table.c b/src/stick_table.c index d748705023..bb4dd5abc0 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -5043,8 +5043,8 @@ static int cli_io_handler_table(struct appctx *appctx) * - STATE_DONE : nothing left to dump, the buffer may contain some * data though. */ - - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) { + /* FIXME: Don't watch the other side !*/ + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) { /* in case of abort, remove any refcount we might have set on an entry */ if (ctx->state == STATE_DUMP) { stksess_kill_if_expired(ctx->t, ctx->entry, 1); diff --git a/src/stream.c b/src/stream.c index 5794fd913f..b53a603390 100644 --- a/src/stream.c +++ b/src/stream.c @@ -879,7 +879,7 @@ int stream_set_timeout(struct stream *s, enum act_timeout_name name, int timeout * SC_ST_EST state. It must only be called after switching from SC_ST_CON (or * SC_ST_INI or SC_ST_RDY) to SC_ST_EST, but only when a ->proto is defined. * Note that it will switch the interface to SC_ST_DIS if we already have - * the CF_SHUTR flag, it means we were able to forward the request, and + * the SC_FL_SHUTR flag, it means we were able to forward the request, and * receive the response, before process_stream() had the opportunity to * make the switch from SC_ST_CON to SC_ST_EST. When that happens, we want * to go through back_establish() anyway, to make sure the analysers run. @@ -948,7 +948,7 @@ static void back_establish(struct stream *s) } /* If we managed to get the whole response, and we don't have anything * left to send, or can't, switch to SC_ST_DIS now. */ - if (rep->flags & (CF_SHUTR | CF_SHUTW)) { + if ((s->scb->flags & SC_FL_SHUTR) || (s->scf->flags & SC_FL_SHUTW)) { s->scb->state = SC_ST_DIS; DBG_TRACE_STATE("response channel shutdwn for read/write", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s); } @@ -1578,12 +1578,12 @@ static void stream_handle_timeouts(struct stream *s) sc_check_timeouts(s->scf); channel_check_timeout(&s->req); - if (unlikely((s->req.flags & (CF_SHUTW|CF_WRITE_TIMEOUT)) == CF_WRITE_TIMEOUT)) { + if (unlikely(!(s->scb->flags & SC_FL_SHUTW) && (s->req.flags & CF_WRITE_TIMEOUT))) { s->scb->flags |= SC_FL_NOLINGER; sc_shutw(s->scb); } - if (unlikely((s->req.flags & (CF_SHUTR|CF_READ_TIMEOUT)) == CF_READ_TIMEOUT)) { + if (unlikely(!(s->scf->flags & SC_FL_SHUTR) && (s->req.flags & CF_READ_TIMEOUT))) { if (s->scf->flags & SC_FL_NOHALF) s->scf->flags |= SC_FL_NOLINGER; sc_shutr(s->scf); @@ -1591,16 +1591,16 @@ static void stream_handle_timeouts(struct stream *s) sc_check_timeouts(s->scb); channel_check_timeout(&s->res); - if (unlikely((s->res.flags & (CF_SHUTW|CF_WRITE_TIMEOUT)) == CF_WRITE_TIMEOUT)) { + if (unlikely(!(s->scf->flags & SC_FL_SHUTW) && (s->res.flags & CF_WRITE_TIMEOUT))) { s->scf->flags |= SC_FL_NOLINGER; sc_shutw(s->scf); } - if (unlikely((s->res.flags & (CF_SHUTR|CF_READ_TIMEOUT)) == CF_READ_TIMEOUT)) { + if (unlikely(!(s->scb->flags & SC_FL_SHUTR) && (s->res.flags & CF_READ_TIMEOUT))) { if (s->scb->flags & SC_FL_NOHALF) s->scb->flags |= SC_FL_NOLINGER; sc_shutr(s->scb); - } + } if (HAS_FILTERS(s)) flt_stream_check_timeouts(s); @@ -1711,6 +1711,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) struct server *srv; struct stream *s = context; struct session *sess = s->sess; + unsigned int scf_flags, scb_flags; unsigned int rqf_last, rpf_last; unsigned int rq_prod_last, rq_cons_last; unsigned int rp_cons_last, rp_prod_last; @@ -1760,6 +1761,10 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) scf->flags |= SC_FL_DONT_WAKE; scb->flags |= SC_FL_DONT_WAKE; + /* Keep a copy of SC flags */ + scf_flags = scf->flags; + scb_flags = scb->flags; + /* update pending events */ s->pending_events |= (state & TASK_WOKEN_ANY); @@ -1774,9 +1779,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * So let's not run a whole stream processing if only an expiration * timeout needs to be refreshed. */ - if (!((req->flags | res->flags) & - (CF_SHUTR|CF_READ_EVENT|CF_READ_TIMEOUT|CF_SHUTW| - CF_WRITE_EVENT|CF_WRITE_TIMEOUT)) && + if (!((scf->flags | scb->flags) & (SC_FL_SHUTR|SC_FL_SHUTW)) && + !((req->flags | res->flags) & (CF_READ_EVENT|CF_READ_TIMEOUT|CF_WRITE_EVENT|CF_WRITE_TIMEOUT)) && !(s->flags & SF_CONN_EXP) && !((sc_ep_get(scf) | scb->flags) & SE_FL_ERROR) && ((s->pending_events & TASK_WOKEN_ANY) == TASK_WOKEN_TIMER)) { @@ -1946,12 +1950,14 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) resync_request: /* Analyse request */ if (((req->flags & ~rqf_last) & CF_MASK_ANALYSER) || - ((req->flags ^ rqf_last) & CF_MASK_STATIC) || - (req->analysers && (req->flags & CF_SHUTW)) || + ((scf->flags ^ scf_flags) & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)) || + ((scb->flags ^ scb_flags) & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) || + (req->analysers && (chn_cons(req)->flags & SC_FL_SHUTW)) || scf->state != rq_prod_last || scb->state != rq_cons_last || s->pending_events & TASK_WOKEN_MSG) { - unsigned int flags = req->flags; + unsigned int scf_flags_ana = scf->flags; + unsigned int scb_flags_ana = scb->flags; if (sc_state_in(scf->state, SC_SB_EST|SC_SB_DIS|SC_SB_CLO)) { int max_loops = global.tune.maxpollevents; @@ -2032,8 +2038,10 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) rq_cons_last = scb->state; req->flags &= ~CF_WAKE_ONCE; rqf_last = req->flags; + scf_flags = (scf_flags & ~(SC_FL_SHUTR|SC_FL_SHUTR_NOW)) | (scf->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)); + scb_flags = (scb_flags & ~(SC_FL_SHUTW|SC_FL_SHUTW_NOW)) | (scb->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)); - if ((req->flags ^ flags) & (CF_SHUTR|CF_SHUTW)) + if (((scf->flags ^ scf_flags_ana) & SC_FL_SHUTR) || ((scb->flags ^ scb_flags_ana) & SC_FL_SHUTW)) goto resync_request; } @@ -2047,12 +2055,14 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) /* Analyse response */ if (((res->flags & ~rpf_last) & CF_MASK_ANALYSER) || - (res->flags ^ rpf_last) & CF_MASK_STATIC || - (res->analysers && (res->flags & CF_SHUTW)) || - scf->state != rp_cons_last || - scb->state != rp_prod_last || - s->pending_events & TASK_WOKEN_MSG) { - unsigned int flags = res->flags; + ((scb->flags ^ scb_flags) & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)) || + ((scf->flags ^ scf_flags) & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) || + (res->analysers && (chn_cons(res)->flags & SC_FL_SHUTW)) || + scf->state != rp_cons_last || + scb->state != rp_prod_last || + s->pending_events & TASK_WOKEN_MSG) { + unsigned int scb_flags_ana = scb->flags; + unsigned int scf_flags_ana = scf->flags; if (sc_state_in(scb->state, SC_SB_EST|SC_SB_DIS|SC_SB_CLO)) { int max_loops = global.tune.maxpollevents; @@ -2101,8 +2111,10 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) rp_prod_last = scb->state; res->flags &= ~CF_WAKE_ONCE; rpf_last = res->flags; + scb_flags = (scb_flags & ~(SC_FL_SHUTR|SC_FL_SHUTR_NOW)) | (scb->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)); + scf_flags = (scf_flags & ~(SC_FL_SHUTW|SC_FL_SHUTW_NOW)) | (scf->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)); - if ((res->flags ^ flags) & (CF_SHUTR|CF_SHUTW)) + if (((scb->flags ^ scb_flags_ana) & SC_FL_SHUTR) || ((scf->flags ^ scf_flags_ana) & SC_FL_SHUTW)) goto resync_response; } @@ -2212,13 +2224,13 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) /* If no one is interested in analysing data, it's time to forward * everything. We configure the buffer to forward indefinitely. - * Note that we're checking CF_SHUTR_NOW as an indication of a possible + * Note that we're checking SC_FL_SHUTR_NOW as an indication of a possible * recent call to channel_abort(). */ if (unlikely((!req->analysers || (req->analysers == AN_REQ_FLT_END && !(req->flags & CF_FLT_ANALYZE))) && - !(req->flags & (CF_SHUTW|CF_SHUTR_NOW)) && - (sc_state_in(scf->state, SC_SB_EST|SC_SB_DIS|SC_SB_CLO)) && - (req->to_forward != CHN_INFINITE_FORWARD))) { + !(scf->flags & SC_FL_SHUTR_NOW) && !(scb->flags & SC_FL_SHUTW) && + (sc_state_in(scf->state, SC_SB_EST|SC_SB_DIS|SC_SB_CLO)) && + (req->to_forward != CHN_INFINITE_FORWARD))) { /* This buffer is freewheeling, there's no analyser * attached to it. If any data are left in, we'll permit them to * move. @@ -2234,7 +2246,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * to the consumer. */ co_set_data(req, htx->data); - if ((global.tune.options & GTUNE_USE_FAST_FWD) && !(req->flags & (CF_SHUTR|CF_SHUTW_NOW))) + if ((global.tune.options & GTUNE_USE_FAST_FWD) && + !(scf->flags & SC_FL_SHUTR) && !(scb->flags & SC_FL_SHUTW_NOW)) channel_htx_forward_forever(req, htx); } else { @@ -2242,13 +2255,15 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * to the consumer (which might possibly not be connected yet). */ c_adv(req, ci_data(req)); - if ((global.tune.options & GTUNE_USE_FAST_FWD) && !(req->flags & (CF_SHUTR|CF_SHUTW_NOW))) + if ((global.tune.options & GTUNE_USE_FAST_FWD) && + !(scf->flags & SC_FL_SHUTR) && !(scb->flags & SC_FL_SHUTW_NOW)) channel_forward_forever(req); } } /* check if it is wise to enable kernel splicing to forward request data */ - if (!(req->flags & (CF_KERN_SPLICING|CF_SHUTR)) && + if (!(req->flags & CF_KERN_SPLICING) && + !(scf->flags & SC_FL_SHUTR) && req->to_forward && (global.tune.options & GTUNE_USE_SPLICE) && (sc_conn(scf) && __sc_conn(scf)->xprt && __sc_conn(scf)->xprt->rcv_pipe && @@ -2264,6 +2279,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) /* reflect what the L7 analysers have seen last */ rqf_last = req->flags; + scf_flags = (scf_flags & ~(SC_FL_SHUTR|SC_FL_SHUTR_NOW)) | (scf->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)); + scb_flags = (scb_flags & ~(SC_FL_SHUTW|SC_FL_SHUTW_NOW)) | (scb->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)); /* it's possible that an upper layer has requested a connection setup or abort. * There are 2 situations where we decide to establish a new connection : @@ -2271,7 +2288,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * - the CF_AUTO_CONNECT flag is set (active connection) */ if (scb->state == SC_ST_INI) { - if (!(req->flags & CF_SHUTW)) { + if (!(scb->flags & SC_FL_SHUTW)) { if ((req->flags & CF_AUTO_CONNECT) || !channel_is_empty(req)) { /* If we have an appctx, there is no connect method, so we * immediately switch to the connected state, otherwise we @@ -2343,14 +2360,14 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * the other side's timeout as well. However this doesn't have effect during the * connection setup unless the backend has abortonclose set. */ - if (unlikely((req->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CLOSE|CF_SHUTR)) == - (CF_AUTO_CLOSE|CF_SHUTR) && + if (unlikely((req->flags & CF_AUTO_CLOSE) && (scf->flags & SC_FL_SHUTR) && + !(scb->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) && (scb->state != SC_ST_CON || (s->be->options & PR_O_ABRT_CLOSE)))) { channel_shutw_now(req); } /* shutdown(write) pending */ - if (unlikely((req->flags & (CF_SHUTW|CF_SHUTW_NOW)) == CF_SHUTW_NOW && + if (unlikely((scb->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) == SC_FL_SHUTW_NOW && channel_is_empty(req))) { if (sc_ep_test(s->scf, SE_FL_ERROR)) scb->flags |= SC_FL_NOLINGER; @@ -2358,12 +2375,12 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) } /* shutdown(write) done on server side, we must stop the client too */ - if (unlikely((req->flags & (CF_SHUTW|CF_SHUTR|CF_SHUTR_NOW)) == CF_SHUTW && - !req->analysers)) + if (unlikely((scb->flags & SC_FL_SHUTW) && !(scf->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW))) && + !req->analysers) channel_shutr_now(req); /* shutdown(read) pending */ - if (unlikely((req->flags & (CF_SHUTR|CF_SHUTR_NOW)) == CF_SHUTR_NOW)) { + if (unlikely((scf->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)) == SC_FL_SHUTR_NOW)) { if (scf->flags & SC_FL_NOHALF) scf->flags |= SC_FL_NOLINGER; sc_shutr(scf); @@ -2377,20 +2394,20 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) goto resync_stconns; /* otherwise we want to check if we need to resync the req buffer or not */ - if ((req->flags ^ rqf_last) & (CF_SHUTR|CF_SHUTW)) + if (((scf->flags ^ scf_flags) & SC_FL_SHUTR) || ((scb->flags ^ scb_flags) & SC_FL_SHUTW)) goto resync_request; /* perform output updates to the response buffer */ /* If no one is interested in analysing data, it's time to forward * everything. We configure the buffer to forward indefinitely. - * Note that we're checking CF_SHUTR_NOW as an indication of a possible + * Note that we're checking SC_FL_SHUTR_NOW as an indication of a possible * recent call to channel_abort(). */ if (unlikely((!res->analysers || (res->analysers == AN_RES_FLT_END && !(res->flags & CF_FLT_ANALYZE))) && - !(res->flags & (CF_SHUTW|CF_SHUTR_NOW)) && - sc_state_in(scb->state, SC_SB_EST|SC_SB_DIS|SC_SB_CLO) && - (res->to_forward != CHN_INFINITE_FORWARD))) { + !(scf->flags & SC_FL_SHUTR_NOW) && !(scb->flags & SC_FL_SHUTW_NOW) && + sc_state_in(scb->state, SC_SB_EST|SC_SB_DIS|SC_SB_CLO) && + (res->to_forward != CHN_INFINITE_FORWARD))) { /* This buffer is freewheeling, there's no analyser * attached to it. If any data are left in, we'll permit them to * move. @@ -2405,7 +2422,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * to the consumer. */ co_set_data(res, htx->data); - if ((global.tune.options & GTUNE_USE_FAST_FWD) && !(res->flags & (CF_SHUTR|CF_SHUTW_NOW))) + if ((global.tune.options & GTUNE_USE_FAST_FWD) && + !(scf->flags & SC_FL_SHUTR) && !(scb->flags & SC_FL_SHUTW_NOW)) channel_htx_forward_forever(res, htx); } else { @@ -2413,7 +2431,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) * to the consumer. */ c_adv(res, ci_data(res)); - if ((global.tune.options & GTUNE_USE_FAST_FWD) && !(res->flags & (CF_SHUTR|CF_SHUTW_NOW))) + if ((global.tune.options & GTUNE_USE_FAST_FWD) && + !(scf->flags & SC_FL_SHUTR) && !(scb->flags & SC_FL_SHUTW_NOW)) channel_forward_forever(res); } @@ -2424,15 +2443,16 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) if (!req->analysers && s->tunnel_timeout) { scf->ioto = scb->ioto = s->tunnel_timeout; - if (((req->flags & CF_SHUTR) || (res->flags & CF_SHUTW)) && tick_isset(sess->fe->timeout.clientfin)) + if ((scf->flags & (SC_FL_SHUTR|SC_FL_SHUTW)) && tick_isset(sess->fe->timeout.clientfin)) scf->ioto = sess->fe->timeout.clientfin; - if (((res->flags & CF_SHUTR) || (req->flags & CF_SHUTW)) && tick_isset(s->be->timeout.serverfin)) + if ((scb->flags & (SC_FL_SHUTR|SC_FL_SHUTW)) && tick_isset(s->be->timeout.serverfin)) scb->ioto = s->be->timeout.serverfin; } } /* check if it is wise to enable kernel splicing to forward response data */ - if (!(res->flags & (CF_KERN_SPLICING|CF_SHUTR)) && + if (!(res->flags & CF_KERN_SPLICING) && + !(scb->flags & SC_FL_SHUTR) && res->to_forward && (global.tune.options & GTUNE_USE_SPLICE) && (sc_conn(scf) && __sc_conn(scf)->xprt && __sc_conn(scf)->xprt->snd_pipe && @@ -2448,6 +2468,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) /* reflect what the L7 analysers have seen last */ rpf_last = res->flags; + scb_flags = (scb_flags & ~(SC_FL_SHUTR|SC_FL_SHUTR_NOW)) | (scb->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)); + scf_flags = (scf_flags & ~(SC_FL_SHUTW|SC_FL_SHUTW_NOW)) | (scf->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)); /* Let's see if we can send the pending response now */ sc_conn_sync_send(scf); @@ -2461,24 +2483,24 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) */ /* first, let's check if the response buffer needs to shutdown(write) */ - if (unlikely((res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CLOSE|CF_SHUTR)) == - (CF_AUTO_CLOSE|CF_SHUTR))) { + if (unlikely((res->flags & CF_AUTO_CLOSE) && (scb->flags & SC_FL_SHUTR) && + !(scf->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)))) { channel_shutw_now(res); } /* shutdown(write) pending */ - if (unlikely((res->flags & (CF_SHUTW|CF_SHUTW_NOW)) == CF_SHUTW_NOW && + if (unlikely((scf->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) == SC_FL_SHUTW_NOW && channel_is_empty(res))) { sc_shutw(scf); } /* shutdown(write) done on the client side, we must stop the server too */ - if (unlikely((res->flags & (CF_SHUTW|CF_SHUTR|CF_SHUTR_NOW)) == CF_SHUTW) && + if (unlikely((scf->flags & SC_FL_SHUTW) && !(scb->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW))) && !res->analysers) channel_shutr_now(res); /* shutdown(read) pending */ - if (unlikely((res->flags & (CF_SHUTR|CF_SHUTR_NOW)) == CF_SHUTR_NOW)) { + if (unlikely((scb->flags & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)) == SC_FL_SHUTR_NOW)) { if (scb->flags & SC_FL_NOHALF) scb->flags |= SC_FL_NOLINGER; sc_shutr(scb); @@ -2493,7 +2515,8 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) if ((req->flags & ~rqf_last) & CF_MASK_ANALYSER) goto resync_request; - if ((res->flags ^ rpf_last) & CF_MASK_STATIC) + if (((scb->flags ^ scb_flags) & (SC_FL_SHUTR|SC_FL_SHUTR_NOW)) || + ((scf->flags ^ scf_flags) & (SC_FL_SHUTW|SC_FL_SHUTW_NOW))) goto resync_response; if (((req->flags ^ rqf_last) | (res->flags ^ rpf_last)) & CF_MASK_ANALYSER) @@ -2751,7 +2774,7 @@ void default_srv_error(struct stream *s, struct stconn *sc) /* kill a stream and set the termination flags to (one of SF_ERR_*) */ void stream_shutdown(struct stream *stream, int why) { - if (stream->req.flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (stream->scb->flags & (SC_FL_SHUTW|SC_FL_SHUTW_NOW)) return; channel_shutw_now(&stream->req); @@ -3576,7 +3599,7 @@ static int cli_io_handler_dump_sess(struct appctx *appctx) goto done; } - if (unlikely(sc_ic(sc)->flags & CF_SHUTW)) { + if (unlikely(chn_cons(sc_ic(sc))->flags & SC_FL_SHUTW)) { /* If we're forced to shut down, we might have to remove our * reference to the last stream being dumped. */ diff --git a/src/tcp_rules.c b/src/tcp_rules.c index bb4e51f3da..10a45ddf9f 100644 --- a/src/tcp_rules.c +++ b/src/tcp_rules.c @@ -116,7 +116,7 @@ int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit) * - if one rule returns KO, then return KO */ - if ((s->scf->flags & SC_FL_EOI) || (req->flags & CF_SHUTR) || channel_full(req, global.tune.maxrewrite) || + if ((s->scf->flags & (SC_FL_EOI|SC_FL_SHUTR)) || channel_full(req, global.tune.maxrewrite) || sc_waiting_room(chn_prod(req)) || !s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) { partial = SMP_OPT_FINAL; @@ -299,7 +299,7 @@ int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit) * - if one rule returns OK, then return OK * - if one rule returns KO, then return KO */ - if ((s->scb->flags & SC_FL_EOI) || (rep->flags & CF_SHUTR) || channel_full(rep, global.tune.maxrewrite) || + if ((s->scb->flags & (SC_FL_EOI|SC_FL_SHUTR)) || channel_full(rep, global.tune.maxrewrite) || sc_waiting_room(chn_prod(rep)) || !s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) { partial = SMP_OPT_FINAL;