MINOR: mux-quic: adjust local error API
When a fatal error is detected by the QUIC MUX or H3 layer, the connection should be closed with a CONNECTION_CLOSE with an error code as the reason. Previously, a direct call was used to the quic_conn layer to try to close the connection. This API was adjusted to be more flexible. Now, when an error is detected, the function qcc_set_error() is called. This set the flag QC_CF_ERRL with the error code stored by the MUX. The connection will be closed soon so most of the operations are not conducted anymore. Connection is then finally closed during qc_send() via quic_conn layer if QC_CF_ERRL is set. This will set the flag QC_CF_ERRL_DONE which indicates that the MUX instance can be freed. This model is cleaner and brings the following improvments : - interaction with quic_conn layer for closure is centralized on a single function - CO_FL_ERROR is not set anymore. This was incorrect as this should be reserved to errors reported by the transport layer to be similar with other haproxy components. As a consequence, qcc_is_dead() has been adjusted to check for QC_CF_ERRL_DONE to release the MUX instance. This should be backported up to 2.7.
This commit is contained in:
parent
b8901d2c86
commit
51f116d65e
@ -13,6 +13,7 @@
|
||||
#include <haproxy/htx-t.h>
|
||||
#include <haproxy/list-t.h>
|
||||
#include <haproxy/ncbuf-t.h>
|
||||
#include <haproxy/quic_frame-t.h>
|
||||
#include <haproxy/quic_stream-t.h>
|
||||
#include <haproxy/stconn-t.h>
|
||||
|
||||
@ -27,10 +28,11 @@ enum qcs_type {
|
||||
QCS_MAX_TYPES
|
||||
};
|
||||
|
||||
#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. */
|
||||
#define QC_CF_ERRL 0x00000001 /* fatal error detected locally, connection should be closed soon */
|
||||
#define QC_CF_ERRL_DONE 0x00000002 /* local error properly handled, connection can be released */
|
||||
#define QC_CF_BLK_MFCTL 0x00000004 /* sending blocked due to connection flow-control */
|
||||
#define QC_CF_CONN_FULL 0x00000008 /* no stream buffers available on connection */
|
||||
#define QC_CF_APP_SHUT 0x00000010 /* Application layer shutdown done. */
|
||||
|
||||
struct qcc {
|
||||
struct connection *conn;
|
||||
@ -107,6 +109,7 @@ struct qcc {
|
||||
int timeout;
|
||||
int shut_timeout;
|
||||
int idle_start; /* base time for http-keep-alive timeout */
|
||||
struct quic_err err; /* code for locally detected error */
|
||||
|
||||
const struct qcc_app_ops *app_ops;
|
||||
void *ctx; /* Application layer context */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <haproxy/mux_quic-t.h>
|
||||
#include <haproxy/stream.h>
|
||||
|
||||
void qcc_set_error(struct qcc *qcc, int err);
|
||||
struct qcs *qcc_init_stream_local(struct qcc *qcc, int bidi);
|
||||
struct buffer *qc_get_buf(struct qcs *qcs, struct buffer *bptr);
|
||||
|
||||
|
21
src/h3.c
21
src/h3.c
@ -38,6 +38,7 @@
|
||||
#include <haproxy/qpack-enc.h>
|
||||
#include <haproxy/quic_conn-t.h>
|
||||
#include <haproxy/quic_enc.h>
|
||||
#include <haproxy/quic_frame.h>
|
||||
#include <haproxy/stats-t.h>
|
||||
#include <haproxy/tools.h>
|
||||
#include <haproxy/trace.h>
|
||||
@ -190,7 +191,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
|
||||
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_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
|
||||
qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
h3c->flags |= H3_CF_UNI_CTRL_SET;
|
||||
@ -205,7 +206,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
|
||||
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_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
|
||||
qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
h3c->flags |= H3_CF_UNI_QPACK_DEC_SET;
|
||||
@ -216,7 +217,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
|
||||
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_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
|
||||
qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR);
|
||||
goto err;
|
||||
}
|
||||
h3c->flags |= H3_CF_UNI_QPACK_ENC_SET;
|
||||
@ -1030,7 +1031,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
*/
|
||||
if (h3s->type == H3S_T_CTRL && fin) {
|
||||
TRACE_ERROR("control stream closed by remote peer", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
||||
qcc_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
|
||||
qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1066,7 +1067,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
|
||||
if (!h3_is_frame_valid(h3c, qcs, ftype)) {
|
||||
TRACE_ERROR("received an invalid frame", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
||||
qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED, 1);
|
||||
qcc_set_error(qcs->qcc, H3_FRAME_UNEXPECTED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1089,7 +1090,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
*/
|
||||
if (flen > QC_S_RX_BUF_SZ) {
|
||||
TRACE_ERROR("received a too big frame", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
||||
qcc_emit_cc_app(qcs->qcc, H3_EXCESSIVE_LOAD, 1);
|
||||
qcc_set_error(qcs->qcc, H3_EXCESSIVE_LOAD);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
@ -1128,7 +1129,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
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_emit_cc_app(qcs->qcc, h3c->err, 1);
|
||||
qcc_set_error(qcs->qcc, h3c->err);
|
||||
goto err;
|
||||
}
|
||||
h3c->flags |= H3_CF_SETTINGS_RECV;
|
||||
@ -1162,7 +1163,7 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
return b_data(b);
|
||||
}
|
||||
else if (h3c->err) {
|
||||
qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
|
||||
qcc_set_error(qcs->qcc, h3c->err);
|
||||
return b_data(b);
|
||||
}
|
||||
|
||||
@ -1669,7 +1670,7 @@ static int h3_close(struct qcs *qcs, enum qcc_app_ops_close_side side)
|
||||
*/
|
||||
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_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
|
||||
qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1870,7 +1871,7 @@ static void h3_shutdown(void *ctx)
|
||||
* graceful shutdown SHOULD use the H3_NO_ERROR error code when closing
|
||||
* the connection.
|
||||
*/
|
||||
qcc_emit_cc_app(h3c->qcc, H3_NO_ERROR, 0);
|
||||
h3c->qcc->err = quic_err_app(H3_NO_ERROR);
|
||||
|
||||
TRACE_LEAVE(H3_EV_H3C_END, h3c->qcc->conn);
|
||||
}
|
||||
|
164
src/mux_quic.c
164
src/mux_quic.c
@ -24,24 +24,6 @@
|
||||
DECLARE_POOL(pool_head_qcc, "qcc", sizeof(struct qcc));
|
||||
DECLARE_POOL(pool_head_qcs, "qcs", sizeof(struct qcs));
|
||||
|
||||
/* Emit a CONNECTION_CLOSE with error <err>. This will interrupt all future
|
||||
* send/receive operations.
|
||||
*/
|
||||
static void qcc_emit_cc(struct qcc *qcc, int err)
|
||||
{
|
||||
TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
|
||||
|
||||
/* This function must not be called multiple times. */
|
||||
BUG_ON(qcc->flags & QC_CF_CC_EMIT);
|
||||
|
||||
TRACE_STATE("set CONNECTION_CLOSE on quic-conn", QMUX_EV_QCC_ERR, qcc->conn);
|
||||
quic_set_connection_close(qcc->conn->handle.qc, quic_err_transport(err));
|
||||
qcc->flags |= QC_CF_CC_EMIT;
|
||||
tasklet_wakeup(qcc->wait_event.tasklet);
|
||||
|
||||
TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn);
|
||||
}
|
||||
|
||||
static void qc_free_ncbuf(struct qcs *qcs, struct ncbuf *ncbuf)
|
||||
{
|
||||
struct buffer buf;
|
||||
@ -225,13 +207,19 @@ static forceinline void qcc_rm_hreq(struct qcc *qcc)
|
||||
|
||||
static inline int qcc_is_dead(const struct qcc *qcc)
|
||||
{
|
||||
/* Mux connection is considered dead if :
|
||||
* - all stream-desc are detached AND
|
||||
* = connection is on error OR
|
||||
* = mux timeout has already fired or is unset
|
||||
/* Maintain connection if stream endpoints are still active. */
|
||||
if (qcc->nb_sc)
|
||||
return 0;
|
||||
|
||||
/* Connection considered dead if either :
|
||||
* - remote error detected at tranport level
|
||||
* - error detected locally
|
||||
* - MUX timeout expired or unset
|
||||
*/
|
||||
if (!qcc->nb_sc && ((qcc->conn->flags & CO_FL_ERROR) || !qcc->task))
|
||||
if (qcc->conn->flags & CO_FL_ERROR || qcc->flags & QC_CF_ERRL_DONE ||
|
||||
!qcc->task) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -508,6 +496,21 @@ void qcs_notify_send(struct qcs *qcs)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
void qcc_set_error(struct qcc *qcc, int err)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Open a locally initiated stream for the connection <qcc>. Set <bidi> for a
|
||||
* bidirectional stream, else an unidirectional stream is opened. The next
|
||||
* available ID on the connection will be used according to the stream type.
|
||||
@ -538,7 +541,7 @@ struct qcs *qcc_init_stream_local(struct qcc *qcc, int bidi)
|
||||
qcs = qcs_new(qcc, *next, type);
|
||||
if (!qcs) {
|
||||
TRACE_LEAVE(QMUX_EV_QCS_NEW, qcc->conn);
|
||||
qcc_emit_cc(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -585,7 +588,7 @@ static struct qcs *qcc_init_stream_remote(struct qcc *qcc, uint64_t id)
|
||||
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_emit_cc(qcc, QC_ERR_STREAM_LIMIT_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_STREAM_LIMIT_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -599,7 +602,7 @@ static struct qcs *qcc_init_stream_remote(struct qcc *qcc, uint64_t id)
|
||||
qcs = qcs_new(qcc, *largest, type);
|
||||
if (!qcs) {
|
||||
TRACE_ERROR("stream fallocation failure", QMUX_EV_QCS_NEW, qcc->conn);
|
||||
qcc_emit_cc(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -658,13 +661,13 @@ int qcc_get_qcs(struct qcc *qcc, uint64_t id, int receive_only, int send_only,
|
||||
|
||||
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_emit_cc(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
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_emit_cc(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -696,7 +699,7 @@ int qcc_get_qcs(struct qcc *qcc, uint64_t id, int receive_only, int send_only,
|
||||
* 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_emit_cc(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
else {
|
||||
@ -752,7 +755,7 @@ static void qcs_consume(struct qcs *qcs, uint64_t bytes)
|
||||
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_emit_cc(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -771,7 +774,7 @@ static void qcs_consume(struct qcs *qcs, uint64_t bytes)
|
||||
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_emit_cc(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -830,38 +833,6 @@ static int qcc_decode_qcs(struct qcc *qcc, struct qcs *qcs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Emit a CONNECTION_CLOSE_APP with error <err>. Reserved for application error
|
||||
* 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, int immediate)
|
||||
{
|
||||
TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
|
||||
|
||||
/* This function must not be called multiple times after immediate is set. */
|
||||
BUG_ON(qcc->flags & QC_CF_CC_EMIT);
|
||||
|
||||
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.
|
||||
* Do not overwrite quic-conn existing code if already set.
|
||||
* TODO implement a wrapper function for this in quic-conn module
|
||||
*/
|
||||
if (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))
|
||||
qcc->conn->handle.qc->err = quic_err_app(err);
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn);
|
||||
}
|
||||
|
||||
/* Prepare for the emission of RESET_STREAM on <qcs> with error code <err>. */
|
||||
void qcc_reset_stream(struct qcs *qcs, int err)
|
||||
{
|
||||
@ -985,8 +956,8 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
|
||||
if (qcc->flags & QC_CF_CC_EMIT) {
|
||||
TRACE_DATA("connection closed", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
TRACE_DATA("connection on error", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1018,7 +989,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
|
||||
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_emit_cc(qcc, QC_ERR_FINAL_SIZE_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_FINAL_SIZE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1051,7 +1022,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
|
||||
*/
|
||||
TRACE_ERROR("flow control error", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV|QMUX_EV_PROTO_ERR,
|
||||
qcc->conn, qcs);
|
||||
qcc_emit_cc(qcc, QC_ERR_FLOW_CONTROL_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_FLOW_CONTROL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -1090,7 +1061,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
|
||||
*/
|
||||
TRACE_ERROR("overlapping data rejected", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV|QMUX_EV_PROTO_ERR,
|
||||
qcc->conn, qcs);
|
||||
qcc_emit_cc(qcc, QC_ERR_PROTOCOL_VIOLATION);
|
||||
qcc_set_error(qcc, QC_ERR_PROTOCOL_VIOLATION);
|
||||
return 1;
|
||||
|
||||
case NCB_RET_GAP_SIZE:
|
||||
@ -1158,8 +1129,8 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
|
||||
if (qcc->flags & QC_CF_CC_EMIT) {
|
||||
TRACE_DATA("connection closed", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
TRACE_DATA("connection on error", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1211,8 +1182,8 @@ int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t f
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
|
||||
if (qcc->flags & QC_CF_CC_EMIT) {
|
||||
TRACE_DATA("connection closed", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
TRACE_DATA("connection on error", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1223,7 +1194,7 @@ int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t f
|
||||
*/
|
||||
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_emit_cc(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_STREAM_STATE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1243,7 +1214,7 @@ int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t f
|
||||
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_emit_cc(qcc, QC_ERR_FINAL_SIZE_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_FINAL_SIZE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1277,8 +1248,8 @@ int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err)
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
|
||||
if (qcc->flags & QC_CF_CC_EMIT) {
|
||||
TRACE_DATA("connection closed", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
TRACE_DATA("connection on error", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1370,7 +1341,7 @@ static int qcc_release_remote_stream(struct qcc *qcc, uint64_t id)
|
||||
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_emit_cc(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1414,7 +1385,7 @@ static void qcs_destroy(struct qcs *qcs)
|
||||
*/
|
||||
BUG_ON(qcs->tx.offset < qcs->tx.sent_offset);
|
||||
|
||||
if (!(qcc->flags & QC_CF_CC_EMIT)) {
|
||||
if (!(qcc->flags & QC_CF_ERRL)) {
|
||||
if (quic_stream_is_remote(qcc, id))
|
||||
qcc_release_remote_stream(qcc, id);
|
||||
}
|
||||
@ -1885,7 +1856,19 @@ static int qc_send(struct qcc *qcc)
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
|
||||
|
||||
if (qcc->conn->flags & CO_FL_SOCK_WR_SH || qcc->flags & QC_CF_CC_EMIT) {
|
||||
/* Check for locally detected connection error. */
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
/* Prepare a CONNECTION_CLOSE if not already done. */
|
||||
if (!(qcc->flags & QC_CF_ERRL_DONE)) {
|
||||
TRACE_DATA("report a connection error", QMUX_EV_QCC_SEND|QMUX_EV_QCC_ERR, qcc->conn);
|
||||
quic_set_connection_close(qcc->conn->handle.qc, qcc->err);
|
||||
qcc->flags |= QC_CF_ERRL_DONE;
|
||||
}
|
||||
TRACE_DEVEL("connection on error", QMUX_EV_QCC_SEND, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (qcc->conn->flags & CO_FL_SOCK_WR_SH) {
|
||||
qcc->conn->flags |= CO_FL_ERROR;
|
||||
TRACE_DEVEL("connection on error", QMUX_EV_QCC_SEND, qcc->conn);
|
||||
goto err;
|
||||
@ -2032,7 +2015,8 @@ static int qc_recv(struct qcc *qcc)
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
|
||||
if (qcc->flags & QC_CF_CC_EMIT) {
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
TRACE_DATA("connection on error", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
return 0;
|
||||
}
|
||||
@ -2113,19 +2097,33 @@ static void qc_shutdown(struct qcc *qcc)
|
||||
{
|
||||
TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
|
||||
|
||||
if (qcc->flags & (QC_CF_APP_SHUT|QC_CF_CC_EMIT)) {
|
||||
TRACE_DATA("connection closed", QMUX_EV_QCC_END, qcc->conn);
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
TRACE_DATA("connection on error", QMUX_EV_QCC_END, qcc->conn);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qcc->flags & QC_CF_APP_SHUT)
|
||||
goto out;
|
||||
|
||||
TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn);
|
||||
if (qcc->app_ops && qcc->app_ops->shutdown) {
|
||||
qcc->app_ops->shutdown(qcc->ctx);
|
||||
qc_send(qcc);
|
||||
}
|
||||
else {
|
||||
qcc_emit_cc_app(qcc, QC_ERR_NO_ERROR, 0);
|
||||
qcc->err = quic_err_app(QC_ERR_NO_ERROR);
|
||||
}
|
||||
|
||||
/* Register "no error" code at transport layer. Do not use
|
||||
* quic_set_connection_close() as retransmission may be performed to
|
||||
* finalized transfers. Do not overwrite quic-conn existing code if
|
||||
* already set.
|
||||
*
|
||||
* TODO implement a wrapper function for this in quic-conn module
|
||||
*/
|
||||
if (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))
|
||||
qcc->conn->handle.qc->err = qcc->err;
|
||||
|
||||
out:
|
||||
qcc->flags |= QC_CF_APP_SHUT;
|
||||
TRACE_LEAVE(QMUX_EV_QCC_END, qcc->conn);
|
||||
|
@ -111,7 +111,7 @@ int qpack_decode_enc(struct buffer *buf, int fin, void *ctx)
|
||||
* connection error of type H3_CLOSED_CRITICAL_STREAM.
|
||||
*/
|
||||
if (fin) {
|
||||
qcc_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
|
||||
qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ int qpack_decode_dec(struct buffer *buf, int fin, void *ctx)
|
||||
* connection error of type H3_CLOSED_CRITICAL_STREAM.
|
||||
*/
|
||||
if (fin) {
|
||||
qcc_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
|
||||
qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user