MEDIUM: mux-quic: adjust transport layer error handling

Following previous patch, error notification from quic_conn has been
adjusted to rely on standard connection flags. Most notably, CO_FL_ERROR
on the connection instance when a fatal error is detected.

Check for CO_FL_ERROR is implemented by qc_send(). If set the new flag
QC_CF_ERR_CONN will be set for the MUX instance. This flag is similar to
the local error flag and will abort most of the futur processing. To
ensure stream upper layer is also notified, qc_wake_some_streams()
called by qc_process() will put the stream on error if this new flag is
set.

This should be backported up to 2.7.
This commit is contained in:
Amaury Denoyelle 2023-05-04 18:52:42 +02:00
parent b2e31d33f5
commit 5f67b17a59
2 changed files with 22 additions and 9 deletions

View File

@ -33,6 +33,7 @@ enum qcs_type {
#define QC_CF_BLK_MFCTL 0x00000004 /* sending blocked due to connection flow-control */
#define QC_CF_CONN_FULL 0x00000008 /* no stream buffers available on connection */
#define QC_CF_APP_SHUT 0x00000010 /* Application layer shutdown done. */
#define QC_CF_ERR_CONN 0x00000020 /* fatal error reported by transport layer */
struct qcc {
struct connection *conn;

View File

@ -216,7 +216,7 @@ static inline int qcc_is_dead(const struct qcc *qcc)
* - error detected locally
* - MUX timeout expired or unset
*/
if (qcc->conn->flags & CO_FL_ERROR || qcc->flags & QC_CF_ERRL_DONE ||
if (qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL_DONE) ||
!qcc->task) {
return 1;
}
@ -1900,6 +1900,12 @@ static int qc_send(struct qcc *qcc)
* apply for STREAM frames.
*/
/* Check for transport error. */
if (qcc->flags & QC_CF_ERR_CONN || qcc->conn->flags & CO_FL_ERROR) {
TRACE_DEVEL("connection on error", QMUX_EV_QCC_SEND, qcc->conn);
goto out;
}
/* Check for locally detected connection error. */
if (qcc->flags & QC_CF_ERRL) {
/* Prepare a CONNECTION_CLOSE if not already done. */
@ -2039,6 +2045,12 @@ static int qc_send(struct qcc *qcc)
}
out:
if (qcc->conn->flags & CO_FL_ERROR && !(qcc->flags & QC_CF_ERR_CONN)) {
TRACE_ERROR("error reported by transport layer",
QMUX_EV_QCC_SEND, qcc->conn);
qcc->flags |= QC_CF_ERR_CONN;
}
TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn);
return total;
}
@ -2134,7 +2146,7 @@ static void qc_shutdown(struct qcc *qcc)
{
TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
if (qcc->flags & QC_CF_ERRL) {
if (qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL)) {
TRACE_DATA("connection on error", QMUX_EV_QCC_END, qcc->conn);
goto out;
}
@ -2183,7 +2195,7 @@ static int qc_wake_some_streams(struct qcc *qcc)
if (!qcs_sc(qcs))
continue;
if (qcc->conn->flags & CO_FL_ERROR || qcc->flags & QC_CF_ERRL) {
if (qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL)) {
TRACE_POINT(QMUX_EV_QCC_WAKE, qcc->conn, qcs);
se_fl_set_error(qcs->sd);
qcs_alert(qcs);
@ -2243,7 +2255,7 @@ static int qc_process(struct qcc *qcc)
}
/* Report error if set on stream endpoint layer. */
if (qcc->flags & QC_CF_ERRL)
if (qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL))
qc_wake_some_streams(qcc);
out:
@ -2571,8 +2583,8 @@ static void qc_detach(struct sedesc *sd)
qcc_rm_sc(qcc);
if (!qcs_is_close_local(qcs) && !(qcc->conn->flags & CO_FL_ERROR) &&
!(qcc->flags & QC_CF_ERRL)) {
if (!qcs_is_close_local(qcs) &&
!(qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL))) {
TRACE_STATE("remaining data, detaching qcs", QMUX_EV_STRM_END, qcc->conn, qcs);
qcs->flags |= QC_SF_DETACH;
qcc_refresh_timeout(qcc);
@ -2671,7 +2683,7 @@ static size_t qc_send_buf(struct stconn *sc, struct buffer *buf,
BUG_ON_HOT(qcs->flags & QC_SF_DETACH);
/* Report error if set on stream endpoint layer. */
if (qcs->qcc->flags & QC_CF_ERRL) {
if (qcs->qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL)) {
se_fl_set(qcs->sd, SE_FL_ERROR);
TRACE_DEVEL("connection in error", QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs);
goto end;
@ -2766,7 +2778,7 @@ static void qc_shutw(struct stconn *sc, enum co_shw_mode mode)
if (qcs->flags & QC_SF_UNKNOWN_PL_LENGTH) {
/* Close stream with a FIN STREAM frame. */
if (!(qcc->flags & QC_CF_ERRL)) {
if (!(qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL))) {
TRACE_STATE("set FIN STREAM",
QMUX_EV_STRM_SHUT, qcc->conn, qcs);
qcs->flags |= QC_SF_FIN_STREAM;
@ -2775,7 +2787,7 @@ static void qc_shutw(struct stconn *sc, enum co_shw_mode mode)
}
else {
/* RESET_STREAM necessary. */
if (!(qcc->flags & QC_CF_ERRL))
if (!(qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL)))
qcc_reset_stream(qcs, 0);
se_fl_set_error(qcs->sd);
}