#define QC_CF_CC_EMIT 0x00000001 /* A CONNECTION_CLOSE is set by the MUX */
#define QC_CF_BLK_MFCTL 0x00000002 /* sending blocked due to connection flow-control */
#define QC_CF_CONN_FULL 0x00000004 /* no stream buffers available on connection */
+#define QC_CF_APP_SHUT 0x00000008 /* Application layer shutdown done. */
struct qcc {
struct connection *conn;
return release;
}
-/* release function. This one should be called to free all resources allocated
- * to the mux.
+/* 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.
*/
-static void qc_release(struct qcc *qcc)
+static void qc_shutdown(struct qcc *qcc)
{
- struct connection *conn = qcc->conn;
- struct eb64_node *node;
+ TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
- TRACE_ENTER(QMUX_EV_QCC_END, conn);
+ if (qcc->flags & QC_CF_APP_SHUT)
+ goto out;
if (qcc->app_ops && qcc->app_ops->shutdown) {
- /* Application protocol with dedicated connection closing
- * procedure.
- */
qcc->app_ops->shutdown(qcc->ctx);
-
- /* useful if application protocol should emit some closing
- * frames. For example HTTP/3 GOAWAY frame.
- */
qc_send(qcc);
}
else {
qcc_emit_cc_app(qcc, QC_ERR_NO_ERROR, 0);
}
+ out:
+ qcc->flags |= QC_CF_APP_SHUT;
+ TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn);
+}
+
+/* release function. This one should be called to free all resources allocated
+ * to the mux.
+ */
+static void qc_release(struct qcc *qcc)
+{
+ struct connection *conn = qcc->conn;
+ struct eb64_node *node;
+
+ TRACE_ENTER(QMUX_EV_QCC_END, conn);
+
+ qc_shutdown(qcc);
+
if (qcc->task) {
task_destroy(qcc->task);
qcc->task = NULL;