Introduce a new QCC field to track the current application layer state.
For the moment, only INIT and SHUT state are defined. This allows to
replace the older flag QC_CF_APP_SHUT.
This commit does not bring major changes. It is only necessary to permit
future evolutions on QUIC MUX. The only noticeable change is that QMUX
traces can now display this new field.
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. */
#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) */
_(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;
* 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);
}
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;
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);
/* 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 <qcc> application state context.
*/
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);
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);
}
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);
/* 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;
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,