static int qcc_subscribe_send(struct qcc *qcc)
{
struct connection *conn = qcc->conn;
+
+ /* Do not subscribe if lower layer in error. */
+ if (conn->flags & CO_FL_ERROR)
+ return 0;
+
if (qcc->wait_event.events & SUB_RETRY_SEND)
return 1;
if (!qc_send_mux(qcc->conn->handle.qc, frms)) {
TRACE_DEVEL("error on sending", QMUX_EV_QCC_SEND, qcc->conn);
- /* TODO should subscribe only for a transient send error */
qcc_subscribe_send(qcc);
goto err;
}
TRACE_ENTER(QMUX_EV_QCC_WAKE, conn);
- if (conn->handle.qc->flags & QUIC_FL_CONN_NOTIFY_CLOSE)
- qcc->conn->flags |= (CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH);
-
- qc_send(qcc);
-
if (qc_process(qcc)) {
TRACE_STATE("releasing dead connection", QMUX_EV_QCC_WAKE, qcc->conn);
goto release;
TRACE_PROTO("killing the connection", QUIC_EV_CONN_KILL, qc);
qc->flags |= QUIC_FL_CONN_TO_KILL;
task_wakeup(qc->idle_timer_task, TASK_WOKEN_OTHER);
+
+ qc_notify_err(qc);
+
TRACE_LEAVE(QUIC_EV_CONN_KILL, qc);
}
qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE;
qc->err.code = err.code;
qc->err.app = err.app;
+
leave:
TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
}
if (++frm->loss_count >= global.tune.quic_max_frame_loss) {
TRACE_ERROR("retransmission limit reached, closing the connection", QUIC_EV_CONN_PRSAFRM, qc);
quic_set_connection_close(qc, quic_err_transport(QC_ERR_INTERNAL_ERROR));
+ qc_notify_err(qc);
close = 1;
}
if (ncb_ret == NCB_RET_DATA_REJ) {
TRACE_ERROR("overlapping data rejected", QUIC_EV_CONN_PRSHPKT, qc);
quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION));
+ qc_notify_err(qc);
}
else if (ncb_ret == NCB_RET_GAP_SIZE) {
TRACE_ERROR("cannot bufferize frame due to gap size limit",
return ret;
protocol_violation:
quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION));
+ qc_notify_err(qc);
goto leave;
}
qc->flags |= QUIC_FL_CONN_DRAINING|QUIC_FL_CONN_IMMEDIATE_CLOSE;
qc_detach_th_ctx_list(qc, 1);
qc_idle_timer_do_rearm(qc, 0);
- qc_notify_close(qc);
+ qc_notify_err(qc);
}
break;
case QUIC_FT_HANDSHAKE_DONE:
(pkt->flags & QUIC_FL_TX_PACKET_CC)) {
qc->flags |= QUIC_FL_CONN_CLOSING;
qc_detach_th_ctx_list(qc, 1);
- qc_notify_close(qc);
/* RFC 9000 10.2. Immediate Close:
* The closing and draining connection states exist to ensure
TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
BUG_ON(qc->mux_state != QC_MUX_READY); /* Only MUX can uses this function so it must be ready. */
+ if (qc->conn->flags & CO_FL_SOCK_WR_SH) {
+ qc->conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH;
+ TRACE_DEVEL("connection on error", QUIC_EV_CONN_TXPKT, qc);
+ return 0;
+ }
+
/* Try to send post handshake frames first unless on 0-RTT. */
if ((qc->flags & QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS) &&
qc->state >= QUIC_HS_ST_COMPLETE) {
/* Notify the MUX before settings QUIC_FL_CONN_EXP_TIMER or the MUX
* might free the quic-conn too early via quic_close().
*/
- qc_notify_close(qc);
+ qc_notify_err(qc);
/* If the MUX is still alive, keep the quic-conn. The MUX is
* responsible to call quic_close to release it.
goto leave;
}
-/* Notify the MUX layer if alive about an imminent close of <qc>. */
-void qc_notify_close(struct quic_conn *qc)
+/* Notify upper layer of a fatal error which forces to close the connection. */
+void qc_notify_err(struct quic_conn *qc)
{
TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc);
- if (qc->flags & QUIC_FL_CONN_NOTIFY_CLOSE)
- goto leave;
+ if (qc->mux_state == QC_MUX_READY) {
+ TRACE_STATE("error notified to mux", QUIC_EV_CONN_CLOSE, qc);
+
+ /* Mark socket as closed. */
+ qc->conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
- qc->flags |= QUIC_FL_CONN_NOTIFY_CLOSE;
- /* wake up the MUX */
- if (qc->mux_state == QC_MUX_READY && qc->conn->mux->wake) {
- TRACE_STATE("connection closure notidfied to mux",
- QUIC_FL_CONN_NOTIFY_CLOSE, qc);
- qc->conn->mux->wake(qc->conn);
+ /* TODO quic-conn layer must stay active until MUX is released.
+ * Thus, we have to wake up directly to ensure upper stream
+ * layer will be notified of the error. If a proper separation
+ * is made between MUX and quic-conn layer, wake up could be
+ * conducted only with qc.subs.
+ */
+ tasklet_wakeup(qc->qcc->wait_event.tasklet);
}
- else
- TRACE_STATE("connection closure not notidfied to mux",
- QUIC_FL_CONN_NOTIFY_CLOSE, qc);
- leave:
+
TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
}