void qcs_notify_recv(struct qcs *qcs);
void qcs_notify_send(struct qcs *qcs);
-void qcc_emit_cc_app(struct qcc *qcc, int err);
+void qcc_emit_cc_app(struct qcc *qcc, int err, int immediate);
void qcc_reset_stream(struct qcs *qcs, int err);
int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
char fin, char *data);
switch (type) {
case H3_UNI_S_T_CTRL:
if (h3c->flags & H3_CF_UNI_CTRL_SET) {
- qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR);
+ qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
return -1;
}
h3c->flags |= H3_CF_UNI_CTRL_SET;
case H3_UNI_S_T_QPACK_DEC:
if (h3c->flags & H3_CF_UNI_QPACK_DEC_SET) {
- qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR);
+ qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
return -1;
}
h3c->flags |= H3_CF_UNI_QPACK_DEC_SET;
case H3_UNI_S_T_QPACK_ENC:
if (h3c->flags & H3_CF_UNI_QPACK_ENC_SET) {
- qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR);
+ qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
return -1;
}
h3c->flags |= H3_CF_UNI_QPACK_ENC_SET;
total += hlen;
if (!h3_is_frame_valid(h3c, qcs, ftype)) {
- qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED);
+ qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED, 1);
return -1;
}
* excessive decompressed size.
*/
if (flen > QC_S_RX_BUF_SZ) {
- qcc_emit_cc_app(qcs->qcc, H3_EXCESSIVE_LOAD);
+ qcc_emit_cc_app(qcs->qcc, H3_EXCESSIVE_LOAD, 1);
return -1;
}
break;
* only close the stream once RESET_STREAM is
* supported.
*/
- qcc_emit_cc_app(qcs->qcc, h3c->err);
+ qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
return -1;
}
break;
case H3_FT_SETTINGS:
ret = h3_parse_settings_frm(qcs->qcc->ctx, b, flen);
if (ret < 0) {
- qcc_emit_cc_app(qcs->qcc, h3c->err);
+ qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
return -1;
}
h3c->flags |= H3_CF_SETTINGS_RECV;
}
/* Emit a CONNECTION_CLOSE_APP with error <err>. Reserved for application error
- * code. This will interrupt all future send/receive operations.
+ * code. To close the connection right away, set <immediate> : this is useful
+ * when dealing with a connection fatal error. Else a graceful shutdown will be
+ * conducted : the error-code is only registered. The lower layer is
+ * responsible to close the connection when deemed suitable. Note that in this
+ * case the error code might be overwritten if an immediate close is requested
+ * in the interval.
*/
-void qcc_emit_cc_app(struct qcc *qcc, int err)
+void qcc_emit_cc_app(struct qcc *qcc, int err, int immediate)
{
- quic_set_connection_close(qcc->conn->handle.qc, quic_err_app(err));
- qcc->flags |= QC_CF_CC_EMIT;
- tasklet_wakeup(qcc->wait_event.tasklet);
+ if (immediate) {
+ quic_set_connection_close(qcc->conn->handle.qc, quic_err_app(err));
+ qcc->flags |= QC_CF_CC_EMIT;
+ tasklet_wakeup(qcc->wait_event.tasklet);
+ }
+ else {
+ /* Only register the error code for graceful shutdown. */
+ qcc->conn->handle.qc->err = quic_err_app(err);
+ }
}
/* Prepare for the emission of RESET_STREAM on <qcs> with error code <err>. */