#define QUIC_FL_CONN_LISTENER (1U << 3)
#define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4)
#define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6)
+#define QUIC_FL_CONN_EXP_TIMER (1U << 28) /* timer has expired, quic-conn can be freed */
#define QUIC_FL_CONN_CLOSING (1U << 29)
#define QUIC_FL_CONN_DRAINING (1U << 30)
#define QUIC_FL_CONN_IMMEDIATE_CLOSE (1U << 31)
struct eb64_node *node;
struct quic_tls_ctx *app_tls_ctx;
+ /* We must not free the quic-conn if the MUX is still allocated. */
+ BUG_ON(qc->mux_state == QC_MUX_READY);
+
/* free remaining stream descriptors */
node = eb64_first(&qc->streams_by_id);
while (node) {
/* Next application data can be dropped. */
qc->mux_state = QC_MUX_RELEASED;
+ /* If the quic-conn timer has already expired free the quic-conn. */
+ if (qc->flags & QUIC_FL_CONN_EXP_TIMER) {
+ quic_conn_release(qc);
+ TRACE_LEAVE(QUIC_EV_CONN_CLOSE);
+ return;
+ }
+
TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
}
{
struct quic_conn *qc = ctx;
- quic_conn_release(qc);
+ /* If the MUX is still alive, keep the quic-conn. The MUX is
+ * responsible to call quic_close to release it.
+ */
+ qc->flags |= QUIC_FL_CONN_EXP_TIMER;
+ if (qc->mux_state != QC_MUX_READY)
+ quic_conn_release(qc);
+
+ /* TODO if the quic-conn cannot be freed because of the MUX, we may at
+ * least clean some parts of it such as the tasklet.
+ */
return NULL;
}