From 3abfcfec2bebcf28b01f9875e2194decceeeebc2 Mon Sep 17 00:00:00 2001 From: Alan Frindell Date: Wed, 17 Dec 2025 09:22:44 -0800 Subject: [PATCH 1/4] Use new picoquic_iovect_t in alpn callback signature --- picohttp/demoserver.c | 2 +- picohttp/demoserver.h | 2 +- picoquic/picoquic.h | 2 +- pqbench_app/pqbench.c | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/picohttp/demoserver.c b/picohttp/demoserver.c index 1bdc1102f..c6fa56033 100644 --- a/picohttp/demoserver.c +++ b/picohttp/demoserver.c @@ -600,7 +600,7 @@ int picoquic_h09_server_callback(picoquic_cnx_t* cnx, } /* Callback from the TLS stack upon receiving a list of proposed ALPN in the Client Hello */ -size_t picoquic_demo_server_callback_select_alpn(picoquic_quic_t* quic, ptls_iovec_t* list, size_t count) +size_t picoquic_demo_server_callback_select_alpn(picoquic_quic_t* quic, picoquic_iovec_t* list, size_t count) { size_t ret = count; picoquic_alpn_enum alpn_code = picoquic_alpn_undef; diff --git a/picohttp/demoserver.h b/picohttp/demoserver.h index 40d1814c3..025ebeb5a 100644 --- a/picohttp/demoserver.h +++ b/picohttp/demoserver.h @@ -72,7 +72,7 @@ int picoquic_h09_server_callback(picoquic_cnx_t* cnx, * according to the ALPN selected by the client */ -size_t picoquic_demo_server_callback_select_alpn(picoquic_quic_t* quic, ptls_iovec_t* list, size_t count); +size_t picoquic_demo_server_callback_select_alpn(picoquic_quic_t* quic, picoquic_iovec_t* list, size_t count); int demo_server_is_path_sane(const uint8_t* path, size_t path_length); diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h index 086cdaac1..4f31b4fc6 100644 --- a/picoquic/picoquic.h +++ b/picoquic/picoquic.h @@ -450,7 +450,7 @@ typedef int (*picoquic_stream_data_cb_fn)(picoquic_cnx_t* cnx, * * The callback is only called if no default ALPN is specified in the Quic context. */ -typedef size_t (*picoquic_alpn_select_fn)(picoquic_quic_t* quic, ptls_iovec_t* list, size_t count); +typedef size_t (*picoquic_alpn_select_fn)(picoquic_quic_t* quic, picoquic_iovec_t* list, size_t count); /* Function used during callback to provision an ALPN context. The stack * issues a callback of type diff --git a/pqbench_app/pqbench.c b/pqbench_app/pqbench.c index bb0179580..7055ebbf1 100644 --- a/pqbench_app/pqbench.c +++ b/pqbench_app/pqbench.c @@ -212,11 +212,10 @@ static int server_loop_cb(picoquic_quic_t* quic, picoquic_packet_loop_cb_enum cb */ /* Callback from the TLS stack upon receiving a list of proposed ALPN in the Client Hello */ -size_t pqb_server_callback_select_alpn(picoquic_quic_t* quic, ptls_iovec_t* ptls_list, size_t count) +size_t pqb_server_callback_select_alpn(picoquic_quic_t* quic, picoquic_iovec_t* list, size_t count) { size_t ret = count; picoquic_cnx_t* cnx = picoquic_get_cnx_in_progress(quic); - picoquic_iovec_t* list = (picoquic_iovec_t*)ptls_list; for (size_t i = 0; i < count; i++) { if ((const char*)list[i].base != NULL && From 4ebb1a5bec33e6411f9947b21149f68d191fcad7 Mon Sep 17 00:00:00 2001 From: Alan Frindell Date: Wed, 17 Dec 2025 11:00:49 -0800 Subject: [PATCH 2/4] Add v2 ALPN callback API with backward compatibility Introduce picoquic_alpn_select_fn_v2 that uses picoquic_iovec_t instead of ptls_iovec_t. The old picoquic_alpn_select_fn remains backward compatible. If both are set, the older one takes precedence - Add picoquic_set_alpn_select_fn_v2() to set new-style callbacks - Update sample apps to use v2 API - Remove unneeded picotls.h and tls_api.h includes from demoserver --- picohttp/demoserver.c | 2 -- picoquic/picoquic.h | 8 +++++++- picoquic/picoquic_internal.h | 1 + picoquic/quicctx.c | 9 +++++++++ picoquic/tls_api.c | 10 ++++++++-- picoquicfirst/picoquicdemo.c | 2 +- pqbench_app/pqbench.c | 2 +- 7 files changed, 27 insertions(+), 7 deletions(-) diff --git a/picohttp/demoserver.c b/picohttp/demoserver.c index c6fa56033..7b97d47c3 100644 --- a/picohttp/demoserver.c +++ b/picohttp/demoserver.c @@ -27,9 +27,7 @@ #include "ws2ipdef.h" #pragma warning(disable:4100) #endif -#include #include "picoquic_internal.h" -#include "tls_api.h" #include "h3zero.h" #include "democlient.h" #include "demoserver.h" diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h index 4f31b4fc6..f8a29e3b3 100644 --- a/picoquic/picoquic.h +++ b/picoquic/picoquic.h @@ -450,7 +450,10 @@ typedef int (*picoquic_stream_data_cb_fn)(picoquic_cnx_t* cnx, * * The callback is only called if no default ALPN is specified in the Quic context. */ -typedef size_t (*picoquic_alpn_select_fn)(picoquic_quic_t* quic, picoquic_iovec_t* list, size_t count); +typedef size_t (*picoquic_alpn_select_fn)(picoquic_quic_t* quic, ptls_iovec_t* list, size_t count); + +/* V2 callback using picoquic_iovec_t instead of ptls_iovec_t */ +typedef size_t (*picoquic_alpn_select_fn_v2)(picoquic_quic_t* quic, picoquic_iovec_t* list, size_t count); /* Function used during callback to provision an ALPN context. The stack * issues a callback of type @@ -849,6 +852,9 @@ void picoquic_set_mtu_max(picoquic_quic_t* quic, uint32_t mtu_max); /* Set the ALPN function used to verify incoming ALPN */ void picoquic_set_alpn_select_fn(picoquic_quic_t* quic, picoquic_alpn_select_fn alpn_select_fn); +/* V2 API using picoquic_iovec_t */ +void picoquic_set_alpn_select_fn_v2(picoquic_quic_t* quic, picoquic_alpn_select_fn_v2 alpn_select_fn); + /* Set the default callback function for new connections. * This must be defined for every server implementation. */ diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h index a4ec7cdd8..ed082a8cc 100644 --- a/picoquic/picoquic_internal.h +++ b/picoquic/picoquic_internal.h @@ -575,6 +575,7 @@ typedef struct st_picoquic_quic_t { struct st_picomask_fns_t* picomask_fns; char const* default_alpn; picoquic_alpn_select_fn alpn_select_fn; + picoquic_alpn_select_fn_v2 alpn_select_fn_v2; uint8_t reset_seed[PICOQUIC_RESET_SECRET_SIZE]; uint8_t retry_seed[PICOQUIC_RETRY_SECRET_SIZE]; uint64_t* p_simulated_time; diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c index 42e7280e9..d6b93a327 100644 --- a/picoquic/quicctx.c +++ b/picoquic/quicctx.c @@ -4635,6 +4635,15 @@ void picoquic_set_alpn_select_fn(picoquic_quic_t* quic, picoquic_alpn_select_fn quic->alpn_select_fn = alpn_select_fn; } +void picoquic_set_alpn_select_fn_v2(picoquic_quic_t* quic, picoquic_alpn_select_fn_v2 alpn_select_fn) +{ + if (quic->default_alpn != NULL) { + free((void *)quic->default_alpn); + quic->default_alpn = NULL; + } + quic->alpn_select_fn_v2 = alpn_select_fn; +} + void picoquic_set_default_callback(picoquic_quic_t* quic, picoquic_stream_data_cb_fn callback_fn, void* callback_ctx) { diff --git a/picoquic/tls_api.c b/picoquic/tls_api.c index 08ae3aa8e..9c163d1d0 100644 --- a/picoquic/tls_api.c +++ b/picoquic/tls_api.c @@ -1025,8 +1025,14 @@ int picoquic_client_hello_call_back(ptls_on_client_hello_t* on_hello_cb_ctx, } } } - else if (quic->alpn_select_fn != NULL) { - size_t selected = quic->alpn_select_fn(quic, params->negotiated_protocols.list, params->negotiated_protocols.count); + else { + size_t selected = params->negotiated_protocols.count; + if (quic->alpn_select_fn != NULL) { + selected = quic->alpn_select_fn(quic, params->negotiated_protocols.list, params->negotiated_protocols.count); + } + else if (quic->alpn_select_fn_v2 != NULL) { + selected = quic->alpn_select_fn_v2(quic, (picoquic_iovec_t*)params->negotiated_protocols.list, params->negotiated_protocols.count); + } if (selected < params->negotiated_protocols.count) { alpn_found = params->negotiated_protocols.list[selected].base; diff --git a/picoquicfirst/picoquicdemo.c b/picoquicfirst/picoquicdemo.c index e837b5d31..eeac9e29e 100644 --- a/picoquicfirst/picoquicdemo.c +++ b/picoquicfirst/picoquicdemo.c @@ -316,7 +316,7 @@ int quic_server(const char* server_name, picoquic_quic_config_t * config, int ju else { picoquic_set_key_log_file_from_env(qserver); - picoquic_set_alpn_select_fn(qserver, picoquic_demo_server_callback_select_alpn); + picoquic_set_alpn_select_fn_v2(qserver, picoquic_demo_server_callback_select_alpn); picoquic_use_unique_log_names(qserver, 1); diff --git a/pqbench_app/pqbench.c b/pqbench_app/pqbench.c index 7055ebbf1..4c65d11cf 100644 --- a/pqbench_app/pqbench.c +++ b/pqbench_app/pqbench.c @@ -252,7 +252,7 @@ int pqb_server(picoquic_quic_config_t* config) else { picoquic_set_key_log_file_from_env(qserver); - picoquic_set_alpn_select_fn(qserver, pqb_server_callback_select_alpn); + picoquic_set_alpn_select_fn_v2(qserver, pqb_server_callback_select_alpn); if (config->qlog_dir != NULL) { From 40ef6411b4d37acdac51d2369c49b6b1e89de676 Mon Sep 17 00:00:00 2001 From: Alan Frindell Date: Wed, 17 Dec 2025 17:57:37 -0800 Subject: [PATCH 3/4] Fix tests --- picoquictest/h3zerotest.c | 6 +++--- picoquictest/webtransport_test.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/picoquictest/h3zerotest.c b/picoquictest/h3zerotest.c index 9a1fb7e46..860c1f645 100644 --- a/picoquictest/h3zerotest.c +++ b/picoquictest/h3zerotest.c @@ -1843,7 +1843,7 @@ static int demo_server_test(char const * alpn, picoquic_stream_data_cb_fn server * We want to replace that by the demo client callback */ if (ret == 0) { - picoquic_set_alpn_select_fn(test_ctx->qserver, picoquic_demo_server_callback_select_alpn); + picoquic_set_alpn_select_fn_v2(test_ctx->qserver, picoquic_demo_server_callback_select_alpn); picoquic_set_default_callback(test_ctx->qserver, NULL, server_param); picoquic_set_callback(test_ctx->cnx_client, picoquic_demo_client_callback, &callback_ctx); if (ret == 0) { @@ -3153,7 +3153,7 @@ int http_stress_test_one(int do_corrupt, int do_drop, int initial_random) ret = -1; } else { - picoquic_set_alpn_select_fn(qserver, picoquic_demo_server_callback_select_alpn); + picoquic_set_alpn_select_fn_v2(qserver, picoquic_demo_server_callback_select_alpn); if (initial_random) { picoquic_set_random_initial(qserver, 1); } @@ -3679,7 +3679,7 @@ static int h3_grease_test_one(int server_test) * We want to replace that by the demo client callback */ if (ret == 0) { - picoquic_set_alpn_select_fn(test_ctx->qserver, picoquic_demo_server_callback_select_alpn); + picoquic_set_alpn_select_fn_v2(test_ctx->qserver, picoquic_demo_server_callback_select_alpn); picoquic_set_default_callback(test_ctx->qserver, h3zero_callback, server_param); picoquic_set_callback(test_ctx->cnx_client, picoquic_demo_client_callback, &callback_ctx); if (ret == 0) { diff --git a/picoquictest/webtransport_test.c b/picoquictest/webtransport_test.c index 4770b2baa..64bdddac6 100644 --- a/picoquictest/webtransport_test.c +++ b/picoquictest/webtransport_test.c @@ -181,7 +181,7 @@ static int picowt_baton_test_one( server_param.path_table = path_item_list; server_param.path_table_nb = 1; - picoquic_set_alpn_select_fn(test_ctx->qserver, picoquic_demo_server_callback_select_alpn); + picoquic_set_alpn_select_fn_v2(test_ctx->qserver, picoquic_demo_server_callback_select_alpn); picoquic_set_default_callback(test_ctx->qserver, h3zero_callback, &server_param); } } From 1e911345b01bf09bd84f030a73e3886d92d97868 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Wed, 17 Dec 2025 22:30:06 -0800 Subject: [PATCH 4/4] Update picoquic/quicctx.c Make sure the latest update wins! --- picoquic/quicctx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c index d6b93a327..2b54091b1 100644 --- a/picoquic/quicctx.c +++ b/picoquic/quicctx.c @@ -4642,6 +4642,9 @@ void picoquic_set_alpn_select_fn_v2(picoquic_quic_t* quic, picoquic_alpn_select_ quic->default_alpn = NULL; } quic->alpn_select_fn_v2 = alpn_select_fn; + if (alpn_select_fn != NULL) { + quic->alpn_select_fn = NULL; + } } void picoquic_set_default_callback(picoquic_quic_t* quic,