MINOR: quic: Post handshake I/O callback switching

Implement a simple task quic_conn_app_io_cb() to be used after the handshakes
have completed.
This commit is contained in:
Frédéric Lécaille 2022-02-18 17:13:45 +01:00 committed by Amaury Denoyelle
parent 5757b4a50e
commit 00e2400fa6
2 changed files with 78 additions and 13 deletions

View File

@ -196,7 +196,7 @@ enum quic_pkt_type {
#define QUIC_EV_CONN_HPKT (1ULL << 9)
#define QUIC_EV_CONN_PAPKT (1ULL << 10)
#define QUIC_EV_CONN_PAPKTS (1ULL << 11)
#define QUIC_EV_CONN_HDSHK (1ULL << 12)
#define QUIC_EV_CONN_IO_CB (1ULL << 12)
#define QUIC_EV_CONN_RMHP (1ULL << 13)
#define QUIC_EV_CONN_PRSHPKT (1ULL << 14)
#define QUIC_EV_CONN_PRSAPKT (1ULL << 15)

View File

@ -93,7 +93,7 @@ static const struct trace_event quic_trace_events[] = {
{ .mask = QUIC_EV_CONN_HPKT, .name = "hdshk_pkt", .desc = "handhshake packet building" },
{ .mask = QUIC_EV_CONN_PAPKT, .name = "phdshk_apkt", .desc = "post handhshake application packet preparation" },
{ .mask = QUIC_EV_CONN_PAPKTS, .name = "phdshk_apkts", .desc = "post handhshake application packets preparation" },
{ .mask = QUIC_EV_CONN_HDSHK, .name = "hdshk", .desc = "SSL handhshake processing" },
{ .mask = QUIC_EV_CONN_IO_CB, .name = "qc_io_cb", .desc = "QUIC conn. I/O processin" },
{ .mask = QUIC_EV_CONN_RMHP, .name = "rm_hp", .desc = "Remove header protection" },
{ .mask = QUIC_EV_CONN_PRSHPKT, .name = "parse_hpkt", .desc = "parse handshake packet" },
{ .mask = QUIC_EV_CONN_PRSAPKT, .name = "parse_apkt", .desc = "parse application packet" },
@ -173,6 +173,7 @@ static struct quic_tx_packet *qc_build_pkt(unsigned char **pos, const unsigned c
struct quic_enc_level *qel,
struct quic_conn *qc, size_t dglen, int pkt_type,
int padding, int ack, int probe, int cc, int *err);
static struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state);
/* Only for debug purpose */
struct enc_debug_info {
@ -319,7 +320,7 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace
}
}
if (mask & QUIC_EV_CONN_HDSHK) {
if (mask & QUIC_EV_CONN_IO_CB) {
const enum quic_handshake_state *state = a2;
const int *err = a3;
@ -1904,18 +1905,20 @@ static inline int qc_provide_cdata(struct quic_enc_level *el,
ssl_err = SSL_get_error(ctx->ssl, ssl_err);
if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
TRACE_PROTO("SSL handshake",
QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
goto out;
}
TRACE_DEVEL("SSL handshake error",
QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
qc_ssl_dump_errors(ctx->conn);
ERR_clear_error();
goto err;
}
TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_HDSHK, qc, &state);
TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_IO_CB, qc, &state);
/* I/O callback switch */
ctx->wait_event.tasklet->process = quic_conn_app_io_cb;
if (qc_is_listener(ctx->qc)) {
HA_ATOMIC_STORE(&qc->state, QUIC_HS_ST_CONFIRMED);
/* The connection is ready to be accepted. */
@ -1930,17 +1933,17 @@ static inline int qc_provide_cdata(struct quic_enc_level *el,
ssl_err = SSL_get_error(ctx->ssl, ssl_err);
if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
TRACE_DEVEL("SSL post handshake",
QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
goto out;
}
TRACE_DEVEL("SSL post handshake error",
QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
goto err;
}
TRACE_PROTO("SSL post handshake succeeded",
QUIC_EV_CONN_HDSHK, qc, &state);
QUIC_EV_CONN_IO_CB, qc, &state);
}
out:
@ -3155,6 +3158,68 @@ static int qc_qel_may_rm_hp(struct quic_conn *qc, struct quic_enc_level *qel)
return 1;
}
/* Sends application level packets from <qc> QUIC connection */
static int qc_send_app_pkts(struct quic_conn *qc)
{
int ret;
struct qring *qr;
qr = MT_LIST_POP(qc->tx.qring_list, typeof(qr), mt_list);
if (!qr)
/* Never happens */
return 1;
ret = qc_prep_pkts(qc, qr, QUIC_TLS_ENC_LEVEL_APP, QUIC_TLS_ENC_LEVEL_NONE);
if (ret == -1)
goto err;
else if (ret == 0)
goto out;
if (!qc_send_ppkts(qr, qc->xprt_ctx))
goto err;
out:
MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
return 1;
err:
MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
TRACE_DEVEL("leaving in error", QUIC_EV_CONN_IO_CB, qc);
return 0;
}
/* QUIC connection packet handler task (post handshake) */
static struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state)
{
struct ssl_sock_ctx *ctx;
struct quic_conn *qc;
struct quic_enc_level *qel;
int st;
ctx = context;
qc = ctx->qc;
qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP];
st = HA_ATOMIC_LOAD(&qc->state);
TRACE_PROTO("state", QUIC_EV_CONN_IO_CB, qc, &st);
if (!MT_LIST_ISEMPTY(&qel->rx.pqpkts) && qc_qel_may_rm_hp(qc, qel))
qc_rm_hp_pkts(qc, qel);
if (!qc_treat_rx_pkts(qel, NULL, ctx, 0))
goto err;
if (!qc_send_app_pkts(qc))
goto err;
return t;
err:
TRACE_DEVEL("leaving in error", QUIC_EV_CONN_IO_CB, qc, &st);
return t;
}
/* QUIC connection packet handler task. */
struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
{
@ -3168,10 +3233,10 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
ctx = context;
qc = ctx->qc;
TRACE_ENTER(QUIC_EV_CONN_HDSHK, qc);
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
qr = NULL;
st = HA_ATOMIC_LOAD(&qc->state);
TRACE_PROTO("state", QUIC_EV_CONN_HDSHK, qc, &st);
TRACE_PROTO("state", QUIC_EV_CONN_IO_CB, qc, &st);
if (HA_ATOMIC_LOAD(&qc->flags) & QUIC_FL_CONN_IO_CB_WAKEUP) {
HA_ATOMIC_BTR(&qc->flags, QUIC_FL_CONN_IO_CB_WAKEUP_BIT);
/* The I/O handler has been woken up by the dgram listener
@ -3267,13 +3332,13 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
}
MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
TRACE_LEAVE(QUIC_EV_CONN_HDSHK, qc, &st);
TRACE_LEAVE(QUIC_EV_CONN_IO_CB, qc, &st);
return t;
err:
if (qr)
MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
TRACE_DEVEL("leaving in error", QUIC_EV_CONN_HDSHK, qc, &st, &ssl_err);
TRACE_DEVEL("leaving in error", QUIC_EV_CONN_IO_CB, qc, &st, &ssl_err);
return t;
}