mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-04 20:46:11 +02:00
MEDIUM: quic/mux-quic: adjust app-ops install
This patch reworks the installation of app-ops layer by QUIC MUX. Previously, app_ops field was stored directly into the quic_conn structure. Then the MUX reused it directly during its qmux_init(). This patch removes app_ops field from quic_conn and replaces it with a copy of the negotiated ALPN. By using quic_alpn_to_app_ops(), it ensures it remains compatible with a known application layer. On the MUX layer, qcc_install_app_ops() now uses the standard conn_get_alpn() to retrieve the ALPN from the transport layer. This is done via the newly defined <get_alpn> QUIC xprt callback. This new architecture should be cleaner as it better highlights the responsibility of each layers in the ALPN/app negotiation.
This commit is contained in:
parent
9c7cf1c684
commit
940e1820f6
@ -200,6 +200,8 @@ enum qcc_app_ops_close_side {
|
||||
|
||||
/* QUIC application layer operations */
|
||||
struct qcc_app_ops {
|
||||
const char *alpn;
|
||||
|
||||
/* Initialize <qcc> connection app context. */
|
||||
int (*init)(struct qcc *qcc);
|
||||
/* Finish connection initialization if prelude required. */
|
||||
|
||||
@ -91,7 +91,7 @@ static inline char *qcs_st_to_str(enum qcs_state st)
|
||||
}
|
||||
}
|
||||
|
||||
int qcc_install_app_ops(struct qcc *qcc, const struct qcc_app_ops *app_ops);
|
||||
int qcc_install_app_ops(struct qcc *qcc);
|
||||
|
||||
/* Register <qcs> stream for http-request timeout. If the stream is not yet
|
||||
* attached in the configured delay, qcc timeout task will be triggered. This
|
||||
|
||||
@ -400,6 +400,8 @@ struct quic_conn {
|
||||
|
||||
struct eb_root streams_by_id; /* qc_stream_desc tree */
|
||||
|
||||
const char *alpn;
|
||||
|
||||
/* MUX */
|
||||
struct qcc *qcc;
|
||||
struct task *timer_task;
|
||||
@ -408,7 +410,6 @@ struct quic_conn {
|
||||
/* Handshake expiration date */
|
||||
unsigned int hs_expire;
|
||||
|
||||
const struct qcc_app_ops *app_ops;
|
||||
/* Callback to close any stream after MUX closure - set by the MUX itself */
|
||||
int (*strm_reject)(struct list *out, uint64_t stream_id);
|
||||
|
||||
|
||||
@ -204,7 +204,7 @@ static inline void *qc_counters(enum obj_type *o, const struct stats_module *m)
|
||||
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
|
||||
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
|
||||
void quic_set_tls_alert(struct quic_conn *qc, int alert);
|
||||
int quic_set_app_ops(struct quic_conn *qc, const char *alpn, int alpn_len);
|
||||
int qc_register_alpn(struct quic_conn *qc, const char *alpn, int alpn_len);
|
||||
int qc_check_dcid(struct quic_conn *qc, unsigned char *dcid, size_t dcid_len);
|
||||
|
||||
void qc_notify_err(struct quic_conn *qc);
|
||||
|
||||
2
src/h3.c
2
src/h3.c
@ -3398,6 +3398,8 @@ int h3_reject(struct list *out, uint64_t id)
|
||||
|
||||
/* HTTP/3 application layer operations */
|
||||
const struct qcc_app_ops h3_ops = {
|
||||
.alpn = "h3",
|
||||
|
||||
.init = h3_init,
|
||||
.finalize = h3_finalize,
|
||||
.attach = h3_attach,
|
||||
|
||||
@ -324,6 +324,8 @@ static int hq_interop_attach(struct qcs *qcs, void *conn_ctx)
|
||||
}
|
||||
|
||||
const struct qcc_app_ops hq_interop_ops = {
|
||||
.alpn = "hq-interop",
|
||||
|
||||
.rcv_buf = hq_interop_rcv_buf,
|
||||
.snd_buf = hq_interop_snd_buf,
|
||||
.nego_ff = hq_interop_nego_ff,
|
||||
|
||||
@ -1688,26 +1688,38 @@ void qcc_abort_stream_read(struct qcs *qcs)
|
||||
TRACE_LEAVE(QMUX_EV_QCC_NEW, qcc->conn, qcs);
|
||||
}
|
||||
|
||||
/* Install the <app_ops> applicative layer of a QUIC connection on mux <qcc>.
|
||||
/* Install the applicative layer of a QUIC connection on mux <qcc>.
|
||||
* Returns 0 on success else non-zero.
|
||||
*/
|
||||
int qcc_install_app_ops(struct qcc *qcc, const struct qcc_app_ops *app_ops)
|
||||
int qcc_install_app_ops(struct qcc *qcc)
|
||||
{
|
||||
TRACE_ENTER(QMUX_EV_QCC_NEW, qcc->conn);
|
||||
struct connection *conn = qcc->conn;
|
||||
const struct qcc_app_ops *app_ops;
|
||||
const char *alpn;
|
||||
int alpn_len;
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_NEW, conn);
|
||||
|
||||
if (!conn_get_alpn(conn, &alpn, &alpn_len))
|
||||
goto err;
|
||||
|
||||
app_ops = quic_alpn_to_app_ops(alpn, alpn_len);
|
||||
if (!app_ops)
|
||||
goto err;
|
||||
|
||||
if (app_ops->init && !app_ops->init(qcc)) {
|
||||
TRACE_ERROR("application layer install error", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
TRACE_ERROR("application layer install error", QMUX_EV_QCC_NEW, conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
TRACE_PROTO("application layer installed", QMUX_EV_QCC_NEW, qcc->conn);
|
||||
TRACE_PROTO("application layer installed", QMUX_EV_QCC_NEW, conn);
|
||||
qcc->app_ops = app_ops;
|
||||
|
||||
TRACE_LEAVE(QMUX_EV_QCC_NEW, qcc->conn);
|
||||
TRACE_LEAVE(QMUX_EV_QCC_NEW, conn);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
TRACE_LEAVE(QMUX_EV_QCC_NEW, qcc->conn);
|
||||
TRACE_LEAVE(QMUX_EV_QCC_NEW, conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3740,7 +3752,7 @@ static int qmux_init(struct connection *conn, struct proxy *prx,
|
||||
/* Register conn as app_ops may use it. */
|
||||
qcc->conn = conn;
|
||||
|
||||
if (qcc_install_app_ops(qcc, conn->handle.qc->app_ops)) {
|
||||
if (qcc_install_app_ops(qcc)) {
|
||||
TRACE_PROTO("Cannot install app layer", QMUX_EV_QCC_NEW|QMUX_EV_QCC_ERR, conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -267,21 +267,23 @@ void quic_set_tls_alert(struct quic_conn *qc, int alert)
|
||||
TRACE_LEAVE(QUIC_EV_CONN_SSLALERT, qc);
|
||||
}
|
||||
|
||||
/* Set the application for <qc> QUIC connection.
|
||||
* Return 1 if succeeded, 0 if not.
|
||||
/* Register the negotiated TLS ALPN <alpn> of length <alpn_len> for <qc> QUIC
|
||||
* connection. This checks that the protocol is compatible with the QUIC stack.
|
||||
*
|
||||
* Returns 1 on success else 0.
|
||||
*/
|
||||
int quic_set_app_ops(struct quic_conn *qc, const char *alpn, int alpn_len)
|
||||
int qc_register_alpn(struct quic_conn *qc, const char *alpn, int alpn_len)
|
||||
{
|
||||
if (!(qc->app_ops = quic_alpn_to_app_ops(alpn, alpn_len)))
|
||||
const struct qcc_app_ops *app_ops;
|
||||
|
||||
if (!(app_ops = quic_alpn_to_app_ops(alpn, alpn_len)))
|
||||
return 0;
|
||||
|
||||
qc->alpn = app_ops->alpn;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Try to reuse <alpn> ALPN and <etps> early transport parameters.
|
||||
* This function also sets the application operations calling
|
||||
* quic_set_app_ops().
|
||||
* Return 1 if succeeded, 0 if not.
|
||||
*/
|
||||
int quic_reuse_srv_params(struct quic_conn *qc,
|
||||
@ -292,7 +294,7 @@ int quic_reuse_srv_params(struct quic_conn *qc,
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_NEW, qc);
|
||||
|
||||
if (!alpn || !quic_set_app_ops(qc, alpn, strlen(alpn)))
|
||||
if (!alpn || !qc_register_alpn(qc, alpn, strlen(alpn)))
|
||||
goto err;
|
||||
|
||||
qc_early_transport_params_reuse(qc, &qc->tx.params, etps);
|
||||
@ -1124,6 +1126,7 @@ struct quic_conn *qc_new_conn(void *target,
|
||||
LIST_INIT(&qc->rx.pkt_list);
|
||||
|
||||
qc->streams_by_id = EB_ROOT_UNIQUE;
|
||||
qc->alpn = NULL;
|
||||
|
||||
/* Required to call free_quic_conn_cids() from quic_conn_release() */
|
||||
qc->cids = NULL;
|
||||
@ -1143,7 +1146,6 @@ struct quic_conn *qc_new_conn(void *target,
|
||||
qc->xprt_ctx = NULL;
|
||||
qc->conn = conn;
|
||||
qc->qcc = NULL;
|
||||
qc->app_ops = NULL;
|
||||
qc->strm_reject = NULL;
|
||||
qc->path = NULL;
|
||||
|
||||
|
||||
@ -1004,7 +1004,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
|
||||
|
||||
/* Check the alpn could be negotiated */
|
||||
if (!qc_is_back(qc)) {
|
||||
if (!qc->app_ops) {
|
||||
if (!qc->alpn) {
|
||||
TRACE_ERROR("No negotiated ALPN", QUIC_EV_CONN_IO_CB, qc, &state);
|
||||
quic_set_tls_alert(qc, SSL_AD_NO_APPLICATION_PROTOCOL);
|
||||
goto err;
|
||||
@ -1016,7 +1016,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
|
||||
|
||||
qc->conn->flags &= ~(CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN);
|
||||
if (!ssl_sock_get_alpn(qc->conn, ctx, &alpn, &alpn_len) ||
|
||||
!quic_set_app_ops(qc, alpn, alpn_len)) {
|
||||
!qc_register_alpn(qc, alpn, alpn_len)) {
|
||||
TRACE_ERROR("No negotiated ALPN", QUIC_EV_CONN_IO_CB, qc, &state);
|
||||
quic_set_tls_alert(qc, SSL_AD_NO_APPLICATION_PROTOCOL);
|
||||
goto err;
|
||||
|
||||
@ -2242,7 +2242,7 @@ static int ssl_sock_advertise_alpn_protos(SSL *s, const unsigned char **out,
|
||||
}
|
||||
|
||||
#ifdef USE_QUIC
|
||||
if (qc && !quic_set_app_ops(qc, (const char *)*out, *outlen)) {
|
||||
if (qc && !qc_register_alpn(qc, (const char *)*out, *outlen)) {
|
||||
quic_set_tls_alert(qc, SSL_AD_NO_APPLICATION_PROTOCOL);
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
@ -239,6 +239,22 @@ static void qc_xprt_dump_info(struct buffer *msg, const struct connection *conn)
|
||||
quic_dump_qc_info(msg, conn->handle.qc);
|
||||
}
|
||||
|
||||
static int qc_get_alpn(const struct connection *conn, void *xprt_ctx, const char **str, int *len)
|
||||
{
|
||||
struct quic_conn *qc = conn->handle.qc;
|
||||
int ret = 0;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_NEW, qc);
|
||||
if (qc->alpn) {
|
||||
*str = qc->alpn;
|
||||
*len = strlen(qc->alpn);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QUIC_EV_CONN_NEW, qc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* transport-layer operations for QUIC connections. */
|
||||
static struct xprt_ops ssl_quic = {
|
||||
.close = quic_close,
|
||||
@ -250,7 +266,7 @@ static struct xprt_ops ssl_quic = {
|
||||
.destroy_bind_conf = ssl_sock_destroy_bind_conf,
|
||||
.prepare_srv = ssl_sock_prepare_srv_ctx,
|
||||
.destroy_srv = ssl_sock_free_srv_ctx,
|
||||
.get_alpn = ssl_sock_get_alpn,
|
||||
.get_alpn = qc_get_alpn,
|
||||
.get_ssl_sock_ctx = qc_get_ssl_sock_ctx,
|
||||
.dump_info = qc_xprt_dump_info,
|
||||
.name = "QUIC",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user