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 */
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
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 */
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);
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;
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);
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;
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;
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;
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);
}
}