diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index 5b6df8b1e..e9e3bf5e7 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -32,11 +32,17 @@ enum qcs_type { QCS_MAX_TYPES }; +enum qcc_app_st { + QCC_APP_ST_INIT, + QCC_APP_ST_SHUT, +} __attribute__((packed)); + struct qcc { struct connection *conn; uint64_t nb_sc; /* number of attached stream connectors */ uint64_t nb_hreq; /* number of in-progress http requests */ uint32_t flags; /* QC_CF_* */ + enum qcc_app_st app_st; /* application layer state */ int glitches; /* total number of glitches on this connection */ /* flow-control fields set by us enforced on our side. */ @@ -221,7 +227,7 @@ struct qcc_app_ops { #define QC_CF_ERRL_DONE 0x00000002 /* local error properly handled, connection can be released */ /* unused 0x00000004 */ #define QC_CF_CONN_FULL 0x00000008 /* no stream buffers available on connection */ -#define QC_CF_APP_SHUT 0x00000010 /* Application layer shutdown done. */ +/* unused 0x00000010 */ #define QC_CF_ERR_CONN 0x00000020 /* fatal error reported by transport layer */ #define QC_CF_WAIT_HS 0x00000040 /* MUX init before QUIC handshake completed (0-RTT) */ @@ -238,9 +244,8 @@ static forceinline char *qcc_show_flags(char *buf, size_t len, const char *delim _(QC_CF_ERRL, _(QC_CF_ERRL_DONE, _(QC_CF_CONN_FULL, - _(QC_CF_APP_SHUT, _(QC_CF_ERR_CONN, - _(QC_CF_WAIT_HS)))))); + _(QC_CF_WAIT_HS))))); /* epilogue */ _(~0U); return buf; diff --git a/src/mux_quic.c b/src/mux_quic.c index 3bf9577ce..50f266533 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -309,7 +309,7 @@ static void qcc_refresh_timeout(struct qcc *qcc) * processed if shutdown already one or connection is idle. */ if (!conn_is_back(qcc->conn)) { - if (qcc->nb_hreq && !(qcc->flags & QC_CF_APP_SHUT)) { + if (qcc->nb_hreq && qcc->app_st < QCC_APP_ST_SHUT) { TRACE_DEVEL("one or more requests still in progress", QMUX_EV_QCC_WAKE, qcc->conn); qcc->task->expire = tick_add_ifset(now_ms, qcc->timeout); task_queue(qcc->task); @@ -317,7 +317,7 @@ static void qcc_refresh_timeout(struct qcc *qcc) } if ((!LIST_ISEMPTY(&qcc->opening_list) || unlikely(!qcc->largest_bidi_r)) && - !(qcc->flags & QC_CF_APP_SHUT)) { + qcc->app_st < QCC_APP_ST_SHUT) { int timeout = px->timeout.httpreq; struct qcs *qcs = NULL; int base_time; @@ -333,7 +333,7 @@ static void qcc_refresh_timeout(struct qcc *qcc) qcc->task->expire = tick_add_ifset(base_time, timeout); } else { - if (qcc->flags & QC_CF_APP_SHUT) { + if (qcc->app_st >= QCC_APP_ST_SHUT) { TRACE_DEVEL("connection in closing", QMUX_EV_QCC_WAKE, qcc->conn); qcc->task->expire = tick_add_ifset(now_ms, qcc->shut_timeout); @@ -2704,7 +2704,7 @@ static void qcc_purge_streams(struct qcc *qcc) /* Execute application layer shutdown. If this operation is not defined, a * CONNECTION_CLOSE will be prepared as a fallback. This function is protected - * against multiple invocation with the flag QC_CF_APP_SHUT. + * against multiple invocation thanks to application state context. */ static void qcc_shutdown(struct qcc *qcc) { @@ -2715,7 +2715,7 @@ static void qcc_shutdown(struct qcc *qcc) goto out; } - if (qcc->flags & QC_CF_APP_SHUT) + if (qcc->app_st >= QCC_APP_ST_SHUT) goto out; TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn); @@ -2738,7 +2738,7 @@ static void qcc_shutdown(struct qcc *qcc) qcc->conn->handle.qc->err = qcc->err; out: - qcc->flags |= QC_CF_APP_SHUT; + qcc->app_st = QCC_APP_ST_SHUT; TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn); } @@ -3042,6 +3042,7 @@ static int qmux_init(struct connection *conn, struct proxy *prx, conn->ctx = qcc; qcc->nb_hreq = qcc->nb_sc = 0; qcc->flags = 0; + qcc->app_st = QCC_APP_ST_INIT; qcc->glitches = 0; qcc->err = quic_err_transport(QC_ERR_NO_ERROR); diff --git a/src/qmux_trace.c b/src/qmux_trace.c index f75e702cc..3788e3d91 100644 --- a/src/qmux_trace.c +++ b/src/qmux_trace.c @@ -130,6 +130,15 @@ static void qmux_trace_fill_ctx(struct trace_ctx *ctx, const struct trace_source /* register qmux traces */ INITCALL1(STG_REGISTER, trace_register_source, TRACE_SOURCE); +static char *qcc_app_st_to_str(const enum qcc_app_st st) +{ + switch (st) { + case QCC_APP_ST_INIT: return "INIT"; + case QCC_APP_ST_SHUT: return "SHUT"; + default: return ""; + } +} + void qmux_dump_qcc_info(struct buffer *msg, const struct qcc *qcc) { const struct quic_conn *qc = qcc->conn->handle.qc; @@ -137,7 +146,9 @@ void qmux_dump_qcc_info(struct buffer *msg, const struct qcc *qcc) chunk_appendf(msg, " qcc=%p(F)", qcc); if (qcc->conn->handle.qc) chunk_appendf(msg, " qc=%p", qcc->conn->handle.qc); - chunk_appendf(msg, " .sc=%llu .hreq=%llu .flg=0x%04x", (ullong)qcc->nb_sc, (ullong)qcc->nb_hreq, qcc->flags); + chunk_appendf(msg, " .st=%s .sc=%llu .hreq=%llu .flg=0x%04x", + qcc_app_st_to_str(qcc->app_st), (ullong)qcc->nb_sc, + (ullong)qcc->nb_hreq, qcc->flags); chunk_appendf(msg, " .tx=%llu %llu/%llu bwnd=%llu/%llu", (ullong)qcc->tx.fc.off_soft, (ullong)qcc->tx.fc.off_real, (ullong)qcc->tx.fc.limit,