case H3_UNI_S_T_CTRL:
if (h3c->flags & H3_CF_UNI_CTRL_SET) {
TRACE_ERROR("duplicated control stream", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR);
+ qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
goto err;
}
h3c->flags |= H3_CF_UNI_CTRL_SET;
case H3_UNI_S_T_QPACK_DEC:
if (h3c->flags & H3_CF_UNI_QPACK_DEC_SET) {
TRACE_ERROR("duplicated qpack decoder stream", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR);
+ qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
goto err;
}
h3c->flags |= H3_CF_UNI_QPACK_DEC_SET;
case H3_UNI_S_T_QPACK_ENC:
if (h3c->flags & H3_CF_UNI_QPACK_ENC_SET) {
TRACE_ERROR("duplicated qpack encoder stream", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR);
+ qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
goto err;
}
h3c->flags |= H3_CF_UNI_QPACK_ENC_SET;
*/
if (h3s->type == H3S_T_CTRL && fin) {
TRACE_ERROR("control stream closed by remote peer", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM);
+ qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
goto err;
}
if (!h3_is_frame_valid(h3c, qcs, ftype)) {
TRACE_ERROR("received an invalid frame", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_FRAME_UNEXPECTED);
+ qcc_set_error(qcs->qcc, H3_FRAME_UNEXPECTED, 1);
goto err;
}
*/
if (flen > QC_S_RX_BUF_SZ) {
TRACE_ERROR("received a too big frame", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_EXCESSIVE_LOAD);
+ qcc_set_error(qcs->qcc, H3_EXCESSIVE_LOAD, 1);
goto err;
}
break;
ret = h3_parse_settings_frm(qcs->qcc->ctx, b, flen);
if (ret < 0) {
TRACE_ERROR("error on SETTINGS parsing", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, h3c->err);
+ qcc_set_error(qcs->qcc, h3c->err, 1);
goto err;
}
h3c->flags |= H3_CF_SETTINGS_RECV;
return b_data(b);
}
else if (h3c->err) {
- qcc_set_error(qcs->qcc, h3c->err);
+ qcc_set_error(qcs->qcc, h3c->err, 1);
return b_data(b);
}
*/
if (qcs == h3c->ctrl_strm || h3s->type == H3S_T_CTRL) {
TRACE_ERROR("closure detected on control stream", H3_EV_H3S_END, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM);
+ qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
return 1;
}
}
/* A fatal error is detected locally for <qcc> connection. It should be closed
- * with a CONNECTION_CLOSE using <err> code. This function must not be called
- * more than once by connection.
+ * with a CONNECTION_CLOSE using <err> code. Set <app> to true to indicate that
+ * the code must be considered as an application level error. This function
+ * must not be called more than once by connection.
*/
-void qcc_set_error(struct qcc *qcc, int err)
+void qcc_set_error(struct qcc *qcc, int err, int app)
{
/* This must not be called multiple times per connection. */
BUG_ON(qcc->flags & QC_CF_ERRL);
TRACE_STATE("connection on error", QMUX_EV_QCC_ERR, qcc->conn);
qcc->flags |= QC_CF_ERRL;
- qcc->err = quic_err_app(err);
+ qcc->err = app ? quic_err_app(err) : quic_err_transport(err);
}
/* Open a locally initiated stream for the connection <qcc>. Set <bidi> for a
qcs = qcs_new(qcc, *next, type);
if (!qcs) {
TRACE_LEAVE(QMUX_EV_QCS_NEW, qcc->conn);
- qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
+ qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
return NULL;
}
qcc->lfctl.ms_uni * 4;
if (id >= max_id) {
TRACE_ERROR("flow control error", QMUX_EV_QCS_NEW|QMUX_EV_PROTO_ERR, qcc->conn);
- qcc_set_error(qcc, QC_ERR_STREAM_LIMIT_ERROR);
+ qcc_set_error(qcc, QC_ERR_STREAM_LIMIT_ERROR, 0);
goto err;
}
qcs = qcs_new(qcc, *largest, type);
if (!qcs) {
TRACE_ERROR("stream fallocation failure", QMUX_EV_QCS_NEW, qcc->conn);
- qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
+ qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
goto err;
}
if (!receive_only && quic_stream_is_uni(id) && quic_stream_is_remote(qcc, id)) {
TRACE_ERROR("receive-only stream not allowed", QMUX_EV_QCC_RECV|QMUX_EV_QCC_NQCS|QMUX_EV_PROTO_ERR, qcc->conn, NULL, &id);
- qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
+ qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR, 0);
goto err;
}
if (!send_only && quic_stream_is_uni(id) && quic_stream_is_local(qcc, id)) {
TRACE_ERROR("send-only stream not allowed", QMUX_EV_QCC_RECV|QMUX_EV_QCC_NQCS|QMUX_EV_PROTO_ERR, qcc->conn, NULL, &id);
- qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
+ qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR, 0);
goto err;
}
* stream.
*/
TRACE_ERROR("locally initiated stream not yet created", QMUX_EV_QCC_RECV|QMUX_EV_QCC_NQCS|QMUX_EV_PROTO_ERR, qcc->conn, NULL, &id);
- qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
+ qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR, 0);
goto err;
}
else {
TRACE_DATA("increase stream credit via MAX_STREAM_DATA", QMUX_EV_QCS_RECV, qcc->conn, qcs);
frm = qc_frm_alloc(QUIC_FT_MAX_STREAM_DATA);
if (!frm) {
- qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
+ qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
return;
}
TRACE_DATA("increase conn credit via MAX_DATA", QMUX_EV_QCS_RECV, qcc->conn, qcs);
frm = qc_frm_alloc(QUIC_FT_MAX_DATA);
if (!frm) {
- qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
+ qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
return;
}
if (qcs->flags & QC_SF_SIZE_KNOWN &&
(offset + len > qcs->rx.offset_max || (fin && offset + len < qcs->rx.offset_max))) {
TRACE_ERROR("final size error", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV|QMUX_EV_PROTO_ERR, qcc->conn, qcs);
- qcc_set_error(qcc, QC_ERR_FINAL_SIZE_ERROR);
+ qcc_set_error(qcc, QC_ERR_FINAL_SIZE_ERROR, 0);
goto err;
}
*/
TRACE_ERROR("flow control error", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV|QMUX_EV_PROTO_ERR,
qcc->conn, qcs);
- qcc_set_error(qcc, QC_ERR_FLOW_CONTROL_ERROR);
+ qcc_set_error(qcc, QC_ERR_FLOW_CONTROL_ERROR, 0);
goto err;
}
}
*/
TRACE_ERROR("overlapping data rejected", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV|QMUX_EV_PROTO_ERR,
qcc->conn, qcs);
- qcc_set_error(qcc, QC_ERR_PROTOCOL_VIOLATION);
+ qcc_set_error(qcc, QC_ERR_PROTOCOL_VIOLATION, 0);
return 1;
case NCB_RET_GAP_SIZE:
*/
if (qcc_get_qcs(qcc, id, 1, 0, &qcs)) {
TRACE_ERROR("RESET_STREAM for send-only stream received", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
- qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
+ qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR, 0);
goto err;
}
if (qcs->rx.offset_max > final_size ||
((qcs->flags & QC_SF_SIZE_KNOWN) && qcs->rx.offset_max != final_size)) {
TRACE_ERROR("final size error on RESET_STREAM", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
- qcc_set_error(qcc, QC_ERR_FINAL_SIZE_ERROR);
+ qcc_set_error(qcc, QC_ERR_FINAL_SIZE_ERROR, 0);
goto err;
}
TRACE_DATA("increase max stream limit with MAX_STREAMS_BIDI", QMUX_EV_QCC_SEND, qcc->conn);
frm = qc_frm_alloc(QUIC_FT_MAX_STREAMS_BIDI);
if (!frm) {
- qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
+ qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
goto err;
}