MINOR: quic: support CONNECTION_CLOSE_APP emission

Complete quic-conn API for error reporting. A new parameter <app> is
defined in the function quic_set_connection_close(). This will transform
the frame into a CONNECTION_CLOSE_APP type.

This type of frame will be generated by the applicative layer, h3 or
hq-interop for the moment. A new function qcc_emit_cc_app() is exported
by the MUX layer for them.
This commit is contained in:
Amaury Denoyelle 2022-05-23 16:12:15 +02:00
parent 65df3add33
commit f9e190e49a
5 changed files with 24 additions and 7 deletions

View File

@ -25,6 +25,7 @@ void qcs_notify_recv(struct qcs *qcs);
void qcs_notify_send(struct qcs *qcs); void qcs_notify_send(struct qcs *qcs);
void qcs_consume(struct qcs *qcs, uint64_t bytes); void qcs_consume(struct qcs *qcs, uint64_t bytes);
void qcc_emit_cc_app(struct qcc *qcc, int err);
int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset, int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
char fin, char *data); char fin, char *data);
int qcc_recv_max_data(struct qcc *qcc, uint64_t max); int qcc_recv_max_data(struct qcc *qcc, uint64_t max);

View File

@ -684,10 +684,12 @@ enum qc_mux_state {
#define QUIC_FL_CONN_POST_HANDSHAKE_FRAMES_BUILT (1U << 2) #define QUIC_FL_CONN_POST_HANDSHAKE_FRAMES_BUILT (1U << 2)
#define QUIC_FL_CONN_LISTENER (1U << 3) #define QUIC_FL_CONN_LISTENER (1U << 3)
#define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4) #define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4)
/* gap here */
#define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6) #define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6)
#define QUIC_FL_CONN_RETRANS_NEEDED (1U << 7) #define QUIC_FL_CONN_RETRANS_NEEDED (1U << 7)
#define QUIC_FL_CONN_RETRANS_OLD_DATA (1U << 8) #define QUIC_FL_CONN_RETRANS_OLD_DATA (1U << 8)
#define QUIC_FL_CONN_TLS_ALERT (1U << 9) #define QUIC_FL_CONN_TLS_ALERT (1U << 9)
#define QUIC_FL_CONN_APP_ALERT (1U << 10) /* A connection error of type CONNECTION_CLOSE_APP must be emitted. */
#define QUIC_FL_CONN_NOTIFY_CLOSE (1U << 27) /* MUX notified about quic-conn imminent closure (idle-timeout or CONNECTION_CLOSE emission/reception) */ #define QUIC_FL_CONN_NOTIFY_CLOSE (1U << 27) /* MUX notified about quic-conn imminent closure (idle-timeout or CONNECTION_CLOSE emission/reception) */
#define QUIC_FL_CONN_EXP_TIMER (1U << 28) /* timer has expired, quic-conn can be freed */ #define QUIC_FL_CONN_EXP_TIMER (1U << 28) /* timer has expired, quic-conn can be freed */
#define QUIC_FL_CONN_CLOSING (1U << 29) #define QUIC_FL_CONN_CLOSING (1U << 29)

View File

@ -1255,7 +1255,7 @@ static inline void qc_list_all_rx_pkts(struct quic_conn *qc)
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm); void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
void quic_set_connection_close(struct quic_conn *qc, int err); void quic_set_connection_close(struct quic_conn *qc, int err, int app);
void quic_set_tls_alert(struct quic_conn *qc, int alert); void quic_set_tls_alert(struct quic_conn *qc, int alert);
int quic_set_app_ops(struct quic_conn *qc, const unsigned char *alpn, size_t alpn_len); int quic_set_app_ops(struct quic_conn *qc, const unsigned char *alpn, size_t alpn_len);
struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state); struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state);

View File

@ -106,7 +106,7 @@ INITCALL1(STG_REGISTER, trace_register_source, TRACE_SOURCE);
*/ */
static void qcc_emit_cc(struct qcc *qcc, int err) static void qcc_emit_cc(struct qcc *qcc, int err)
{ {
quic_set_connection_close(qcc->conn->handle.qc, err); quic_set_connection_close(qcc->conn->handle.qc, err, 0);
qcc->flags |= QC_CF_CC_EMIT; qcc->flags |= QC_CF_CC_EMIT;
tasklet_wakeup(qcc->wait_event.tasklet); tasklet_wakeup(qcc->wait_event.tasklet);
} }
@ -445,6 +445,16 @@ static int qcc_decode_qcs(struct qcc *qcc, struct qcs *qcs)
return 0; return 0;
} }
/* Emit a CONNECTION_CLOSE_APP with error <err>. Reserved for application error
* code. This will interrupt all future send/receive operations.
*/
void qcc_emit_cc_app(struct qcc *qcc, int err)
{
quic_set_connection_close(qcc->conn->handle.qc, err, 1);
qcc->flags |= QC_CF_CC_EMIT;
tasklet_wakeup(qcc->wait_event.tasklet);
}
/* Handle a new STREAM frame for stream with id <id>. Payload is pointed by /* Handle a new STREAM frame for stream with id <id>. Payload is pointed by
* <data> with length <len> and represents the offset <offset>. <fin> is set if * <data> with length <len> and represents the offset <offset>. <fin> is set if
* the QUIC frame FIN bit is set. * the QUIC frame FIN bit is set.

View File

@ -1109,20 +1109,23 @@ static int quic_crypto_data_cpy(struct quic_enc_level *qel,
/* Prepare the emission of CONNECTION_CLOSE with error <err>. All send/receive /* Prepare the emission of CONNECTION_CLOSE with error <err>. All send/receive
* activity for <qc> will be interrupted. * activity for <qc> will be interrupted.
*/ */
void quic_set_connection_close(struct quic_conn *qc, int err) void quic_set_connection_close(struct quic_conn *qc, int err, int app)
{ {
if (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) if (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)
return; return;
qc->err_code = err; qc->err_code = err;
qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE; qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE;
if (app)
qc->flags |= QUIC_FL_CONN_APP_ALERT;
} }
/* Set <alert> TLS alert as QUIC CRYPTO_ERROR error */ /* Set <alert> TLS alert as QUIC CRYPTO_ERROR error */
void quic_set_tls_alert(struct quic_conn *qc, int alert) void quic_set_tls_alert(struct quic_conn *qc, int alert)
{ {
HA_ATOMIC_DEC(&qc->prx_counters->conn_opening); HA_ATOMIC_DEC(&qc->prx_counters->conn_opening);
quic_set_connection_close(qc, QC_ERR_CRYPTO_ERROR | alert); quic_set_connection_close(qc, QC_ERR_CRYPTO_ERROR | alert, 0);
qc->flags |= QUIC_FL_CONN_TLS_ALERT; qc->flags |= QUIC_FL_CONN_TLS_ALERT;
TRACE_PROTO("Alert set", QUIC_EV_CONN_SSLDATA, qc); TRACE_PROTO("Alert set", QUIC_EV_CONN_SSLDATA, qc);
} }
@ -5985,7 +5988,7 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end,
size_t len, len_sz, len_frms, padding_len; size_t len, len_sz, len_frms, padding_len;
struct quic_frame frm = { .type = QUIC_FT_CRYPTO, }; struct quic_frame frm = { .type = QUIC_FT_CRYPTO, };
struct quic_frame ack_frm = { .type = QUIC_FT_ACK, }; struct quic_frame ack_frm = { .type = QUIC_FT_ACK, };
struct quic_frame cc_frm = { . type = QUIC_FT_CONNECTION_CLOSE, }; struct quic_frame cc_frm = { };
size_t ack_frm_len, head_len; size_t ack_frm_len, head_len;
int64_t rx_largest_acked_pn; int64_t rx_largest_acked_pn;
int add_ping_frm; int add_ping_frm;
@ -6084,9 +6087,10 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end,
len += QUIC_TLS_TAG_LEN; len += QUIC_TLS_TAG_LEN;
/* CONNECTION_CLOSE frame */ /* CONNECTION_CLOSE frame */
if (cc) { if (cc) {
struct quic_connection_close *cc = &cc_frm.connection_close; cc_frm.type = qc->flags & QUIC_FL_CONN_APP_ALERT ?
QUIC_FT_CONNECTION_CLOSE_APP : QUIC_FT_CONNECTION_CLOSE;
cc->error_code = qc->err_code; cc_frm.connection_close.error_code = qc->err_code;
len += qc_frm_len(&cc_frm); len += qc_frm_len(&cc_frm);
} }
add_ping_frm = 0; add_ping_frm = 0;