MEDIUM: mux-quic: implement shutw

Implement mux_ops shutw operation for QUIC mux. A RESET_STREAM is
emitted unless the stream is already closed due to all data or
RESET_STREAM already transmitted.

This operation is notably useful when upper stream layer wants to close
the connection early due to an error.

This was tested by using a HTTP server which listens with PROXY protocol
support. The corresponding server line on haproxy configuration
deliberately not specify send-proxy. This causes the server to close
abruptly the connection. Without this patch, nothing was done on the QUIC
stream which was kept open until the whole connection is closed. Now, a
proper RESET_STREAM is emitted to report the error.

This should be backported up to 2.7.
This commit is contained in:
Amaury Denoyelle 2022-12-21 10:21:58 +01:00
parent be6a873096
commit a473f196f1
2 changed files with 27 additions and 5 deletions

View File

@ -34,17 +34,19 @@ static const struct trace_event qmux_trace_events[] = {
{ .mask = QMUX_EV_STRM_RECV, .name = "strm_recv", .desc = "receiving data for stream" },
#define QMUX_EV_STRM_SEND (1ULL << 11)
{ .mask = QMUX_EV_STRM_SEND, .name = "strm_send", .desc = "sending data for stream" },
#define QMUX_EV_STRM_END (1ULL << 12)
#define QMUX_EV_STRM_SHUT (1ULL << 12)
{ .mask = QMUX_EV_STRM_SHUT, .name = "strm_shut", .desc = "stream shutdown" },
#define QMUX_EV_STRM_END (1ULL << 13)
{ .mask = QMUX_EV_STRM_END, .name = "strm_end", .desc = "detaching app-layer stream" },
#define QMUX_EV_SEND_FRM (1ULL << 13)
#define QMUX_EV_SEND_FRM (1ULL << 14)
{ .mask = QMUX_EV_SEND_FRM, .name = "send_frm", .desc = "sending QUIC frame" },
/* special event dedicated to qcs_xfer_data */
#define QMUX_EV_QCS_XFER_DATA (1ULL << 14)
#define QMUX_EV_QCS_XFER_DATA (1ULL << 15)
{ .mask = QMUX_EV_QCS_XFER_DATA, .name = "qcs_xfer_data", .desc = "qcs_xfer_data" },
/* special event dedicated to qcs_build_stream_frm */
#define QMUX_EV_QCS_BUILD_STRM (1ULL << 15)
#define QMUX_EV_QCS_BUILD_STRM (1ULL << 16)
{ .mask = QMUX_EV_QCS_BUILD_STRM, .name = "qcs_build_stream_frm", .desc = "qcs_build_stream_frm" },
#define QMUX_EV_PROTO_ERR (1ULL << 16)
#define QMUX_EV_PROTO_ERR (1ULL << 17)
{ .mask = QMUX_EV_PROTO_ERR, .name = "proto_err", .desc = "protocol error" },
{ }
};

View File

@ -2269,6 +2269,25 @@ static int qc_wake(struct connection *conn)
return 1;
}
static void qc_shutw(struct stconn *sc, enum co_shw_mode mode)
{
struct qcs *qcs = __sc_mux_strm(sc);
TRACE_ENTER(QMUX_EV_STRM_SHUT, qcs->qcc->conn, qcs);
/* If QC_SF_FIN_STREAM is not set and stream is not closed locally, it
* means that upper layer reported an early closure. A RESET_STREAM is
* necessary if not already scheduled.
*/
if (!qcs_is_close_local(qcs) &&
!(qcs->flags & (QC_SF_FIN_STREAM|QC_SF_TO_RESET))) {
qcc_reset_stream(qcs, 0);
se_fl_set_error(qcs->sd);
}
TRACE_LEAVE(QMUX_EV_STRM_SHUT, qcs->qcc->conn, qcs);
}
/* for debugging with CLI's "show sess" command. May emit multiple lines, each
* new one being prefixed with <pfx>, if <pfx> is not NULL, otherwise a single
@ -2306,6 +2325,7 @@ static const struct mux_ops qc_ops = {
.subscribe = qc_subscribe,
.unsubscribe = qc_unsubscribe,
.wake = qc_wake,
.shutw = qc_shutw,
.show_sd = qc_show_sd,
.flags = MX_FL_HTX|MX_FL_NO_UPG|MX_FL_FRAMED,
.name = "QUIC",