diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 342abba5d..aad813e0c 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -411,7 +411,7 @@ struct mux_ops { size_t (*done_fastfwd)(struct stconn *sc); /* Callback to terminate fast data forwarding */ int (*fastfwd)(struct stconn *sc, unsigned int count, unsigned int flags); /* Callback to init fast data forwarding */ int (*resume_fastfwd)(struct stconn *sc, unsigned int flags); /* Callback to resume fast data forwarding */ - void (*shut)(struct stconn *sc, enum se_shut_mode); /* shutdown function */ + void (*shut)(struct stconn *sc, enum se_shut_mode, struct se_abort_info *reason); /* shutdown function */ int (*attach)(struct connection *conn, struct sedesc *, struct session *sess); /* attach a stconn to an outgoing connection */ struct stconn *(*get_first_sc)(const struct connection *); /* retrieves any valid stconn from this connection */ diff --git a/include/haproxy/stconn-t.h b/include/haproxy/stconn-t.h index 50645d0ac..8f0460d33 100644 --- a/include/haproxy/stconn-t.h +++ b/include/haproxy/stconn-t.h @@ -266,6 +266,24 @@ enum sc_state_bit { struct stconn; +/* represent the abort code, enriched with contextual info: + * - First 5 bits are used for the source (31 possible sources) + * - other bits are reserved for now + */ +#define SE_ABRT_SRC_SHIFT 0 +#define SE_ABRT_SRC_MASK 0x0000001f + +#define SE_ABRT_SRC_MUX_PT 0x01 /* Code set by the PT mux */ +#define SE_ABRT_SRC_MUX_H1 0x02 /* Code set bu the H1 mux */ +#define SE_ABRT_SRC_MUX_H2 0x03 /* Code set bu the H2 mux */ +#define SE_ABRT_SRC_MUX_QUIC 0x04 /* Code set bu the QUIC/H3 mux */ +#define SE_ABRT_SRC_MUX_FCGI 0x05 /* Code set bu the FCGI mux */ + +struct se_abort_info { + uint32_t info; + uint64_t code; +}; + /* A Stream Endpoint Descriptor (sedesc) is the link between the stream * connector (ex. stconn) and the Stream Endpoint (mux or appctx). * It always exists for either of them, and binds them together. It also @@ -296,6 +314,7 @@ struct sedesc { struct stconn *sc; /* the stream connector we're attached to, or NULL */ struct iobuf iobuf; /* contains data forwarded by the other side and that must be sent by the stream endpoint */ unsigned int flags; /* SE_FL_* */ + struct se_abort_info abort_info; /* Info about abort, as reported by the endpoint and eventually enriched by the app level */ unsigned int lra; /* the last read activity */ unsigned int fsb; /* the first send blocked */ /* 4 bytes hole here */ diff --git a/src/mux_fcgi.c b/src/mux_fcgi.c index b914eadfe..a611c0a7e 100644 --- a/src/mux_fcgi.c +++ b/src/mux_fcgi.c @@ -3791,7 +3791,7 @@ struct task *fcgi_deferred_shut(struct task *t, void *ctx, unsigned int state) return NULL; } -static void fcgi_shut(struct stconn *sc, enum se_shut_mode mode) +static void fcgi_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason) { struct fcgi_strm *fstrm = __sc_mux_strm(sc); diff --git a/src/mux_h1.c b/src/mux_h1.c index 397f75a12..39e23956c 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -4291,7 +4291,7 @@ static void h1_detach(struct sedesc *sd) TRACE_LEAVE(H1_EV_STRM_END); } -static void h1_shut(struct stconn *sc, enum se_shut_mode mode) +static void h1_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason) { struct h1s *h1s = __sc_mux_strm(sc); struct h1c *h1c; diff --git a/src/mux_h2.c b/src/mux_h2.c index a3ce0eb89..fbf03a6e7 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -5079,7 +5079,7 @@ struct task *h2_deferred_shut(struct task *t, void *ctx, unsigned int state) return t; } -static void h2_shut(struct stconn *sc, enum se_shut_mode mode) +static void h2_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason) { struct h2s *h2s = __sc_mux_strm(sc); diff --git a/src/mux_pt.c b/src/mux_pt.c index 7aa97d793..dc9702eb0 100644 --- a/src/mux_pt.c +++ b/src/mux_pt.c @@ -462,7 +462,7 @@ static int mux_pt_avail_streams(struct connection *conn) return 1 - mux_pt_used_streams(conn); } -static void mux_pt_shut(struct stconn *sc, enum se_shut_mode mode) +static void mux_pt_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason) { struct connection *conn = __sc_conn(sc); struct mux_pt_ctx *ctx = conn->ctx; diff --git a/src/mux_quic.c b/src/mux_quic.c index 883ef01bb..d7474ffb2 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -3095,7 +3095,7 @@ static int qmux_wake(struct connection *conn) return 1; } -static void qmux_strm_shut(struct stconn *sc, enum se_shut_mode mode) +static void qmux_strm_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason) { struct qcs *qcs = __sc_mux_strm(sc); struct qcc *qcc = qcs->qcc; diff --git a/src/stconn.c b/src/stconn.c index f6d20ea4f..53888efb4 100644 --- a/src/stconn.c +++ b/src/stconn.c @@ -100,6 +100,9 @@ void sedesc_init(struct sedesc *sedesc) sedesc->xref.peer = NULL; se_fl_setall(sedesc, SE_FL_NONE); + sedesc->abort_info.info = 0; + sedesc->abort_info.code = 0; + sedesc->iobuf.pipe = NULL; sedesc->iobuf.buf = NULL; sedesc->iobuf.offset = sedesc->iobuf.data = 0; @@ -150,8 +153,20 @@ void se_shutdown(struct sedesc *sedesc, enum se_shut_mode mode) flags |= (mode & SE_SHR_DRAIN) ? SE_FL_SHRD : SE_FL_SHRR; if (flags) { - if (mux && mux->shut) - mux->shut(sedesc->sc, mode); + if (mux && mux->shut) { + struct se_abort_info *reason = NULL; + struct xref *peer = xref_get_peer_and_lock(&sedesc->xref); + + if (peer) { + struct sedesc *sdo = container_of(peer, struct sedesc, xref); + + reason = &sdo->abort_info; + xref_unlock(&sedesc->xref, peer); + } + + mux->shut(sedesc->sc, mode, reason); + + } se_fl_set(sedesc, flags); } }