Skip to content

Commit cfde8dc

Browse files
committed
MINOR: quic/h3: implement app_ops reject callback
1 parent 4eefabe commit cfde8dc

6 files changed

Lines changed: 66 additions & 60 deletions

File tree

include/haproxy/mux_quic-t.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ struct qcc_app_ops {
232232
void (*inc_err_cnt)(void *ctx, int err_code);
233233
/* Set QCC error code as suspicious activity has been detected. */
234234
void (*report_susp)(void *ctx);
235+
236+
/* Free function to close a stream after MUX layer shutdown. */
237+
int (*reject)(struct list *out, uint64_t id);
235238
};
236239

237240
#endif /* USE_QUIC */

include/haproxy/quic_conn-t.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ struct quic_conn {
409409
unsigned int hs_expire;
410410

411411
const struct qcc_app_ops *app_ops;
412+
int (*request_reject)(struct list *out, uint64_t stream_id);
412413
/* Proxy counters */
413414
struct quic_counters *prx_counters;
414415

src/h3.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3345,6 +3345,57 @@ static void h3_trace(enum trace_level level, uint64_t mask,
33453345
}
33463346
}
33473347

3348+
/* Cancel a request on stream id <id>. This is useful when the client opens a
3349+
* new stream but the MUX has already been released. A STOP_SENDING +
3350+
* RESET_STREAM frames are prepared for emission.
3351+
*
3352+
* Returns 1 on success else 0.
3353+
*/
3354+
int h3_reject(struct list *out, uint64_t id)
3355+
{
3356+
int ret = 0;
3357+
struct quic_frame *ss, *rs;
3358+
const uint64_t app_error_code = H3_ERR_REQUEST_REJECTED;
3359+
3360+
TRACE_ENTER(H3_EV_TX_FRAME);
3361+
3362+
/* Do not emit rejection for unknown unidirectional stream as it is
3363+
* forbidden to close some of them (H3 control stream and QPACK
3364+
* encoder/decoder streams).
3365+
*/
3366+
if (quic_stream_is_uni(id)) {
3367+
ret = 1;
3368+
goto out;
3369+
}
3370+
3371+
ss = qc_frm_alloc(QUIC_FT_STOP_SENDING);
3372+
if (!ss) {
3373+
TRACE_ERROR("failed to allocate quic_frame", H3_EV_TX_FRAME);
3374+
goto out;
3375+
}
3376+
3377+
ss->stop_sending.id = id;
3378+
ss->stop_sending.app_error_code = app_error_code;
3379+
3380+
rs = qc_frm_alloc(QUIC_FT_RESET_STREAM);
3381+
if (!rs) {
3382+
TRACE_ERROR("failed to allocate quic_frame", H3_EV_TX_FRAME);
3383+
qc_frm_free(NULL, &ss);
3384+
goto out;
3385+
}
3386+
3387+
rs->reset_stream.id = id;
3388+
rs->reset_stream.app_error_code = app_error_code;
3389+
rs->reset_stream.final_size = 0;
3390+
3391+
LIST_APPEND(out, &ss->list);
3392+
LIST_APPEND(out, &rs->list);
3393+
ret = 1;
3394+
out:
3395+
TRACE_LEAVE(H3_EV_TX_FRAME);
3396+
return ret;
3397+
}
3398+
33483399
/* HTTP/3 application layer operations */
33493400
const struct qcc_app_ops h3_ops = {
33503401
.init = h3_init,
@@ -3360,4 +3411,5 @@ const struct qcc_app_ops h3_ops = {
33603411
.inc_err_cnt = h3_stats_inc_err_cnt,
33613412
.report_susp = h3_report_susp,
33623413
.release = h3_release,
3414+
.reject = h3_reject,
33633415
};

src/mux_quic.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,8 +3377,12 @@ static void qcc_release(struct qcc *qcc)
33773377

33783378
qcc_clear_frms(qcc);
33793379

3380-
if (qcc->app_ops && qcc->app_ops->release)
3381-
qcc->app_ops->release(qcc->ctx);
3380+
if (qcc->app_ops) {
3381+
if (qcc->app_ops->release)
3382+
qcc->app_ops->release(qcc->ctx);
3383+
if (conn->handle.qc)
3384+
conn->handle.qc->request_reject = qcc->app_ops->reject;
3385+
}
33823386
TRACE_PROTO("application layer released", QMUX_EV_QCC_END, conn);
33833387

33843388
pool_free(pool_head_qcc, qcc);

src/quic_conn.c

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -377,61 +377,6 @@ void quic_conn_closed_err_count_inc(struct quic_conn *qc, struct quic_frame *frm
377377
TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
378378
}
379379

380-
/* Cancel a request on connection <qc> for stream id <id>. This is useful when
381-
* the client opens a new stream but the MUX has already been released. A
382-
* STOP_SENDING + RESET_STREAM frames are prepared for emission.
383-
*
384-
* TODO this function is closely related to H3. Its place should be in H3 layer
385-
* instead of quic-conn but this requires an architecture adjustment.
386-
*
387-
* Returns 1 on success else 0.
388-
*/
389-
int qc_h3_request_reject(struct quic_conn *qc, uint64_t id)
390-
{
391-
int ret = 0;
392-
struct quic_frame *ss, *rs;
393-
struct quic_enc_level *qel = qc->ael;
394-
const uint64_t app_error_code = H3_ERR_REQUEST_REJECTED;
395-
396-
TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc);
397-
398-
/* Do not emit rejection for unknown unidirectional stream as it is
399-
* forbidden to close some of them (H3 control stream and QPACK
400-
* encoder/decoder streams).
401-
*/
402-
if (quic_stream_is_uni(id)) {
403-
ret = 1;
404-
goto out;
405-
}
406-
407-
ss = qc_frm_alloc(QUIC_FT_STOP_SENDING);
408-
if (!ss) {
409-
TRACE_ERROR("failed to allocate quic_frame", QUIC_EV_CONN_PRSHPKT, qc);
410-
goto out;
411-
}
412-
413-
ss->stop_sending.id = id;
414-
ss->stop_sending.app_error_code = app_error_code;
415-
416-
rs = qc_frm_alloc(QUIC_FT_RESET_STREAM);
417-
if (!rs) {
418-
TRACE_ERROR("failed to allocate quic_frame", QUIC_EV_CONN_PRSHPKT, qc);
419-
qc_frm_free(qc, &ss);
420-
goto out;
421-
}
422-
423-
rs->reset_stream.id = id;
424-
rs->reset_stream.app_error_code = app_error_code;
425-
rs->reset_stream.final_size = 0;
426-
427-
LIST_APPEND(&qel->pktns->tx.frms, &ss->list);
428-
LIST_APPEND(&qel->pktns->tx.frms, &rs->list);
429-
ret = 1;
430-
out:
431-
TRACE_LEAVE(QUIC_EV_CONN_PRSHPKT, qc);
432-
return ret;
433-
}
434-
435380
/* Remove a <qc> quic-conn from its ha_thread_ctx list. If <closing> is true,
436381
* it will immediately be reinserted in the ha_thread_ctx quic_conns_clo list.
437382
*/
@@ -1204,6 +1149,7 @@ struct quic_conn *qc_new_conn(void *target,
12041149
qc->conn = conn;
12051150
qc->qcc = NULL;
12061151
qc->app_ops = NULL;
1152+
qc->request_reject = NULL;
12071153
qc->path = NULL;
12081154

12091155
/* Keyupdate: required to safely call quic_tls_ku_free() from

src/quic_rx.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
#include <haproxy/quic_rx.h>
1616

17-
#include <haproxy/h3.h>
1817
#include <haproxy/list.h>
1918
#include <haproxy/ncbmbuf.h>
2019
#include <haproxy/proto_quic.h>
@@ -962,8 +961,9 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
962961
}
963962
else {
964963
TRACE_DEVEL("No mux for new stream", QUIC_EV_CONN_PRSHPKT, qc);
965-
if (qc->app_ops == &h3_ops) {
966-
if (!qc_h3_request_reject(qc, strm_frm->id)) {
964+
if (qc->request_reject) {
965+
struct list *out = &qc->ael->pktns->tx.frms;
966+
if (!qc->request_reject(out, strm_frm->id)) {
967967
TRACE_ERROR("error on request rejection", QUIC_EV_CONN_PRSHPKT, qc);
968968
/* This packet will not be acknowledged */
969969
goto err;

0 commit comments

Comments
 (0)