Skip to content

Commit 5854fc0

Browse files
committed
MINOR: mux-quic: handle RESET_STREAM reception
Implement RESET_STREAM reception by mux-quic. On reception, qcs instance will be mark as remotely closed and its Rx buffer released. The stream layer will be flagged on error if still attached. This commit is part of implementing H3 errors at the stream level. Indeed, on H3 stream errors, STOP_SENDING + RESET_STREAM should be emitted. The STOP_SENDING will in turn generate a RESET_STREAM by the remote peer which will be handled thanks to this patch. This should be backported up to 2.7.
1 parent bb6296c commit 5854fc0

3 files changed

Lines changed: 65 additions & 2 deletions

File tree

include/haproxy/mux_quic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
2525
char fin, char *data);
2626
int qcc_recv_max_data(struct qcc *qcc, uint64_t max);
2727
int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max);
28+
int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t final_size);
2829
int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err);
2930
void qcc_streams_sent_done(struct qcs *qcs, uint64_t data, uint64_t offset);
3031

src/mux_quic.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,11 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
888888
goto err;
889889
}
890890

891+
if (qcs_is_close_remote(qcs)) {
892+
TRACE_DATA("skipping STREAM for remotely closed", QMUX_EV_QCC_RECV, qcc->conn);
893+
goto out;
894+
}
895+
891896
if (offset + len <= qcs->rx.offset) {
892897
/* TODO offset may have been received without FIN first and now
893898
* with it. In this case, it must be notified to be able to
@@ -1055,6 +1060,60 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
10551060
return 0;
10561061
}
10571062

1063+
/* Handle a new RESET_STREAM frame from stream ID <id> with error code <err>
1064+
* and final stream size <final_size>.
1065+
*
1066+
* Returns 0 on success else non-zero. On error, the received frame should not
1067+
* be acknowledged.
1068+
*/
1069+
int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t final_size)
1070+
{
1071+
struct qcs *qcs;
1072+
1073+
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
1074+
1075+
/* RFC 9000 19.4. RESET_STREAM Frames
1076+
*
1077+
* An endpoint that receives a RESET_STREAM frame for a send-only stream
1078+
* MUST terminate the connection with error STREAM_STATE_ERROR.
1079+
*/
1080+
if (qcc_get_qcs(qcc, id, 1, 0, &qcs)) {
1081+
TRACE_ERROR("RESET_STREAM for send-only stream received", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
1082+
qcc_emit_cc(qcc, QC_ERR_STREAM_STATE_ERROR);
1083+
goto err;
1084+
}
1085+
1086+
if (!qcs || qcs_is_close_remote(qcs))
1087+
goto out;
1088+
1089+
TRACE_PROTO("receiving RESET_STREAM", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
1090+
qcs_idle_open(qcs);
1091+
1092+
if (qcs->rx.offset_max > final_size ||
1093+
((qcs->flags & QC_SF_SIZE_KNOWN) && qcs->rx.offset_max != final_size)) {
1094+
TRACE_ERROR("final size error on RESET_STREAM", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
1095+
qcc_emit_cc(qcc, QC_ERR_FINAL_SIZE_ERROR);
1096+
goto err;
1097+
}
1098+
1099+
qcs->flags |= QC_SF_SIZE_KNOWN;
1100+
qcs_close_remote(qcs);
1101+
qc_free_ncbuf(qcs, &qcs->rx.ncbuf);
1102+
1103+
if (qcs_sc(qcs)) {
1104+
se_fl_set_error(qcs->sd);
1105+
qcs_alert(qcs);
1106+
}
1107+
1108+
out:
1109+
TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
1110+
return 0;
1111+
1112+
err:
1113+
TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
1114+
return 1;
1115+
}
1116+
10581117
/* Handle a new STOP_SENDING frame for stream ID <id>. The error code should be
10591118
* specified in <err>.
10601119
*

src/quic_conn.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,8 +2802,11 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
28022802
break;
28032803
}
28042804
case QUIC_FT_RESET_STREAM:
2805-
/* TODO: handle this frame at STREAM level */
2806-
break;
2805+
if (qc->mux_state == QC_MUX_READY) {
2806+
struct quic_reset_stream *rs = &frm.reset_stream;
2807+
qcc_recv_reset_stream(qc->qcc, rs->id, rs->app_error_code, rs->final_size);
2808+
}
2809+
break;
28072810
case QUIC_FT_STOP_SENDING:
28082811
{
28092812
struct quic_stop_sending *stop_sending = &frm.stop_sending;

0 commit comments

Comments
 (0)