From a39c4be42b056b296ed40e690c7f9bd29a8a9f55 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Sun, 7 Jun 2026 01:21:47 +0000 Subject: [PATCH] deps: update ngtcp2 to 1.23.0 --- .../ngtcp2/crypto/boringssl/boringssl.c | 6 +- deps/ngtcp2/ngtcp2/crypto/cryptotest.c | 46 + .../crypto/includes/ngtcp2/ngtcp2_crypto.h | 26 +- deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c | 14 +- deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c | 8 +- deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c | 4 +- deps/ngtcp2/ngtcp2/crypto/shared.c | 152 +- deps/ngtcp2/ngtcp2/crypto/shared.h | 2 +- deps/ngtcp2/ngtcp2/crypto/shared_test.c | 218 ++ deps/ngtcp2/ngtcp2/crypto/shared_test.h | 41 + deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c | 4 +- deps/ngtcp2/ngtcp2/examples/client.cc | 817 +---- deps/ngtcp2/ngtcp2/examples/client.h | 27 +- deps/ngtcp2/ngtcp2/examples/client_base.cc | 1 - deps/ngtcp2/ngtcp2/examples/client_base.h | 15 +- deps/ngtcp2/ngtcp2/examples/debug.cc | 21 +- deps/ngtcp2/ngtcp2/examples/debug.h | 2 +- .../ngtcp2/ngtcp2/examples/gtlssimpleclient.c | 8 +- deps/ngtcp2/ngtcp2/examples/h09client.cc | 2863 --------------- deps/ngtcp2/ngtcp2/examples/h09client.h | 210 -- deps/ngtcp2/ngtcp2/examples/h09server.cc | 3220 ----------------- deps/ngtcp2/ngtcp2/examples/h09server.h | 267 -- .../ngtcp2/examples/hq_client_proto_codec.cc | 192 + .../ngtcp2/examples/hq_client_proto_codec.h | 95 + .../ngtcp2/examples/hq_server_proto_codec.cc | 261 ++ .../ngtcp2/examples/hq_server_proto_codec.h | 98 + .../examples/http3_client_proto_codec.cc | 606 ++++ .../examples/http3_client_proto_codec.h | 102 + .../examples/http3_server_proto_codec.cc | 844 +++++ .../examples/http3_server_proto_codec.h | 120 + deps/ngtcp2/ngtcp2/examples/server.cc | 1124 +----- deps/ngtcp2/ngtcp2/examples/server.h | 76 +- deps/ngtcp2/ngtcp2/examples/server_base.cc | 1 - deps/ngtcp2/ngtcp2/examples/server_base.h | 11 +- deps/ngtcp2/ngtcp2/examples/shared.cc | 1 - deps/ngtcp2/ngtcp2/examples/shared.h | 5 +- deps/ngtcp2/ngtcp2/examples/sim.cc | 184 +- deps/ngtcp2/ngtcp2/examples/sim.h | 45 +- deps/ngtcp2/ngtcp2/examples/sim_test.cc | 2 - deps/ngtcp2/ngtcp2/examples/simpleclient.c | 8 +- .../examples/tls_client_context_boringssl.cc | 7 +- .../examples/tls_client_context_ossl.cc | 7 +- .../examples/tls_client_context_picotls.cc | 8 +- .../examples/tls_client_context_quictls.cc | 7 +- .../examples/tls_client_context_wolfssl.cc | 9 +- .../examples/tls_client_session_boringssl.cc | 13 +- .../examples/tls_client_session_boringssl.h | 5 +- .../examples/tls_client_session_ossl.cc | 9 +- .../ngtcp2/examples/tls_client_session_ossl.h | 5 +- .../examples/tls_client_session_picotls.cc | 9 +- .../examples/tls_client_session_picotls.h | 5 +- .../examples/tls_client_session_quictls.cc | 9 +- .../examples/tls_client_session_quictls.h | 5 +- .../examples/tls_client_session_wolfssl.cc | 13 +- .../examples/tls_client_session_wolfssl.h | 5 +- .../examples/tls_server_context_boringssl.cc | 21 +- .../examples/tls_server_context_ossl.cc | 11 +- .../examples/tls_server_context_picotls.cc | 5 +- .../examples/tls_server_context_quictls.cc | 11 +- .../examples/tls_server_context_wolfssl.cc | 7 +- .../examples/tls_server_session_boringssl.cc | 1 - .../examples/tls_server_session_ossl.cc | 2 - .../examples/tls_server_session_picotls.cc | 1 - .../examples/tls_server_session_quictls.cc | 2 - .../examples/tls_server_session_wolfssl.cc | 2 - deps/ngtcp2/ngtcp2/examples/util.cc | 141 +- deps/ngtcp2/ngtcp2/examples/util.h | 37 +- deps/ngtcp2/ngtcp2/examples/util_openssl.cc | 32 +- deps/ngtcp2/ngtcp2/examples/util_test.cc | 53 +- deps/ngtcp2/ngtcp2/examples/util_test.h | 1 + deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc | 25 +- .../ngtcp2/lib/includes/ngtcp2/ngtcp2.h | 1054 +++++- .../ngtcp2/lib/includes/ngtcp2/version.h | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c | 2 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c | 2 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c | 115 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h | 1 + deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c | 84 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c | 797 ++-- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h | 44 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c | 24 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h | 10 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c | 9 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c | 2 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.c | 112 + deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.h | 1211 +++++++ deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c | 10 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c | 7 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c | 427 +-- deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h | 59 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h | 90 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h | 70 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c | 67 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h | 90 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c | 6 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c | 70 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.h | 17 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pq.c | 11 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c | 2 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c | 7 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_range.c | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c | 8 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c | 12 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h | 12 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c | 42 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h | 2 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_settings.c | 4 + deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c | 137 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h | 52 +- .../ngtcp2/lib/ngtcp2_transport_params.c | 5 +- .../ngtcp2/lib/ngtcp2_transport_params.h | 40 +- 114 files changed, 7184 insertions(+), 9765 deletions(-) create mode 100644 deps/ngtcp2/ngtcp2/crypto/cryptotest.c create mode 100644 deps/ngtcp2/ngtcp2/crypto/shared_test.c create mode 100644 deps/ngtcp2/ngtcp2/crypto/shared_test.h delete mode 100644 deps/ngtcp2/ngtcp2/examples/h09client.cc delete mode 100644 deps/ngtcp2/ngtcp2/examples/h09client.h delete mode 100644 deps/ngtcp2/ngtcp2/examples/h09server.cc delete mode 100644 deps/ngtcp2/ngtcp2/examples/h09server.h create mode 100644 deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.cc create mode 100644 deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.h create mode 100644 deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.cc create mode 100644 deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.h create mode 100644 deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.cc create mode 100644 deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.h create mode 100644 deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.cc create mode 100644 deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.c create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.h diff --git a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c index e43faa76850a25..6daedf1075557b 100644 --- a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c @@ -432,7 +432,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, int ngtcp2_crypto_read_write_crypto_data( ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, const uint8_t *data, size_t datalen) { - SSL *ssl = ngtcp2_conn_get_tls_native_handle(conn); + SSL *ssl = ngtcp2_conn_get_tls_native_handle2(conn); int rv; int err; @@ -444,7 +444,7 @@ int ngtcp2_crypto_read_write_crypto_data( return -1; } - if (!ngtcp2_conn_get_handshake_completed(conn)) { + if (!ngtcp2_conn_get_handshake_completed2(conn)) { retry: rv = SSL_do_handshake(ssl); if (rv <= 0) { @@ -456,7 +456,7 @@ int ngtcp2_crypto_read_write_crypto_data( case SSL_ERROR_SSL: return -1; case SSL_ERROR_EARLY_DATA_REJECTED: - assert(!ngtcp2_conn_is_server(conn)); + assert(!ngtcp2_conn_is_server2(conn)); SSL_reset_early_data_reject(ssl); diff --git a/deps/ngtcp2/ngtcp2/crypto/cryptotest.c b/deps/ngtcp2/ngtcp2/crypto/cryptotest.c new file mode 100644 index 00000000000000..0752c9357d5f7d --- /dev/null +++ b/deps/ngtcp2/ngtcp2/crypto/cryptotest.c @@ -0,0 +1,46 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +# include +#endif /* defined(HAVE_CONFIG_H) */ + +#include "munit.h" + +/* include test cases' include files here */ +#include "shared_test.h" + +int main(int argc, char *argv[]) { + const MunitSuite suites[] = { + shared_suite, + {0}, + }; + const MunitSuite suite = { + .prefix = "", + .suites = suites, + .iterations = 1, + }; + + return munit_suite_main(&suite, NULL, argc, argv); +} diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h index 28eeeb5ead8061..9ff353ef46b102 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h @@ -338,16 +338,16 @@ ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to * set negotiated AEAD and message digest algorithm. After the * successful call of this function, application can use - * `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_0rtt_crypto_ctx` - * if |level| == + * `ngtcp2_conn_get_crypto_ctx2` (or + * `ngtcp2_conn_get_0rtt_crypto_ctx2` if |level| == * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to * get :type:`ngtcp2_crypto_ctx`. * * If |conn| is initialized as client, and |level| is * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_1RTT`, this * function retrieves a remote QUIC transport parameters extension - * from an object obtained by `ngtcp2_conn_get_tls_native_handle`, and - * sets it to |conn| by calling + * from an object obtained by `ngtcp2_conn_get_tls_native_handle2`, + * and sets it to |conn| by calling * `ngtcp2_conn_decode_and_set_remote_transport_params`. * * This function returns 0 if it succeeds, or -1. @@ -385,16 +385,16 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_rx_key( * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to * set negotiated AEAD and message digest algorithm. After the * successful call of this function, application can use - * `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_0rtt_crypto_ctx` - * if |level| == + * `ngtcp2_conn_get_crypto_ctx2` (or + * `ngtcp2_conn_get_0rtt_crypto_ctx2` if |level| == * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to * get :type:`ngtcp2_crypto_ctx`. * * If |conn| is initialized as server, and |level| is * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_1RTT`, this * function retrieves a remote QUIC transport parameters extension - * from an object obtained by `ngtcp2_conn_get_tls_native_handle`, and - * sets it to |conn| by calling + * from an object obtained by `ngtcp2_conn_get_tls_native_handle2`, + * and sets it to |conn| by calling * `ngtcp2_conn_decode_and_set_remote_transport_params`. * * This function returns 0 if it succeeds, or -1. @@ -986,15 +986,17 @@ NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_cipher_ctx_cb( /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use `ngtcp2_crypto_get_path_challenge_data2_cb` instead. + * * `ngtcp2_crypto_get_path_challenge_data_cb` writes unpredictable * sequence of :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes to |data| * which is sent with PATH_CHALLENGE frame. * * This function can be directly passed to * :member:`ngtcp2_callbacks.get_path_challenge_data` field. - * - * Deprecated since v1.22.0. Use - * `ngtcp2_crypto_get_path_challenge_data2_cb` instead. */ NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data, @@ -1010,7 +1012,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, * This function can be directly passed to * :member:`ngtcp2_callbacks.get_path_challenge_data2` field. * - * This function has been available since v1.22.0. + * .. version-added:: 1.22.0 */ NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data2_cb( ngtcp2_conn *conn, ngtcp2_path_challenge_data *data, void *user_data); diff --git a/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c b/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c index fa393c8ece5200..6159567aceb6af 100644 --- a/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c +++ b/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c @@ -440,7 +440,7 @@ static int crypto_ossl_ctx_write_crypto_data(ngtcp2_crypto_ossl_ctx *ossl_ctx, left = crypto_buf_left(ossl_ctx->crypto_write); } - n = ngtcp2_min_size((size_t)(end - data), left); + n = ngtcp2_min((size_t)(end - data), left); crypto_buf_write(ossl_ctx->crypto_write, data, n); data += n; } @@ -871,7 +871,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, int ngtcp2_crypto_read_write_crypto_data( ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, const uint8_t *data, size_t datalen) { - ngtcp2_crypto_ossl_ctx *ossl_ctx = ngtcp2_conn_get_tls_native_handle(conn); + ngtcp2_crypto_ossl_ctx *ossl_ctx = ngtcp2_conn_get_tls_native_handle2(conn); SSL *ssl = ossl_ctx->ssl; int rv; int err; @@ -881,7 +881,7 @@ int ngtcp2_crypto_read_write_crypto_data( return -1; } - if (!ngtcp2_conn_get_handshake_completed(conn)) { + if (!ngtcp2_conn_get_handshake_completed2(conn)) { rv = SSL_do_handshake(ssl); if (rv <= 0) { err = SSL_get_error(ssl, rv); @@ -1033,7 +1033,7 @@ static int ossl_yield_secret(SSL *ssl, uint32_t ossl_level, int direction, } conn = conn_ref->get_conn(conn_ref); - ossl_ctx = ngtcp2_conn_get_tls_native_handle(conn); + ossl_ctx = ngtcp2_conn_get_tls_native_handle2(conn); if (direction) { if (ngtcp2_crypto_derive_and_install_tx_key(conn, NULL, NULL, NULL, level, @@ -1067,7 +1067,7 @@ static int ossl_crypto_send(SSL *ssl, const unsigned char *buf, size_t buflen, } conn = conn_ref->get_conn(conn_ref); - ossl_ctx = ngtcp2_conn_get_tls_native_handle(conn); + ossl_ctx = ngtcp2_conn_get_tls_native_handle2(conn); rv = ngtcp2_conn_submit_crypto_data(conn, ossl_ctx->tx_level, buf, buflen); if (rv != 0) { @@ -1094,7 +1094,7 @@ static int ossl_crypto_recv_rcd(SSL *ssl, const unsigned char **buf, } conn = conn_ref->get_conn(conn_ref); - ossl_ctx = ngtcp2_conn_get_tls_native_handle(conn); + ossl_ctx = ngtcp2_conn_get_tls_native_handle2(conn); crypto_ossl_ctx_read_crypto_data(ossl_ctx, buf, bytes_read); @@ -1116,7 +1116,7 @@ static int ossl_crypto_release_rcd(SSL *ssl, size_t released, void *arg) { } conn = conn_ref->get_conn(conn_ref); - ossl_ctx = ngtcp2_conn_get_tls_native_handle(conn); + ossl_ctx = ngtcp2_conn_get_tls_native_handle2(conn); crypto_ossl_ctx_release_crypto_data(ossl_ctx, released); diff --git a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c index bd29a541277b0f..af934bf10463b0 100644 --- a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c +++ b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c @@ -378,7 +378,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, int ngtcp2_crypto_read_write_crypto_data( ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, const uint8_t *data, size_t datalen) { - ngtcp2_crypto_picotls_ctx *cptls = ngtcp2_conn_get_tls_native_handle(conn); + ngtcp2_crypto_picotls_ctx *cptls = ngtcp2_conn_get_tls_native_handle2(conn); ptls_buffer_t sendbuf; size_t epoch_offsets[5] = {0}; size_t epoch = @@ -402,7 +402,7 @@ int ngtcp2_crypto_read_write_crypto_data( goto fin; } - if (!ngtcp2_conn_is_server(conn) && + if (!ngtcp2_conn_is_server2(conn) && cptls->handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { rv = ngtcp2_conn_tls_early_data_rejected(conn); @@ -540,7 +540,7 @@ static int set_additional_extensions(ptls_handshake_properties_t *hsprops, return -1; } - nwrite = ngtcp2_conn_encode_local_transport_params(conn, buf, buflen); + nwrite = ngtcp2_conn_encode_local_transport_params2(conn, buf, buflen); if (nwrite < 0) { goto fail; } @@ -620,7 +620,7 @@ static int update_traffic_key_server_cb(ptls_update_traffic_key_t *self, * wait for the key to get the correct local transport * parameters from ngtcp2_conn. */ - cptls = ngtcp2_conn_get_tls_native_handle(conn); + cptls = ngtcp2_conn_get_tls_native_handle2(conn); if (set_additional_extensions(&cptls->handshake_properties, conn) != 0) { return -1; diff --git a/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c index 1076d97bfc0e26..64669168d3cf60 100644 --- a/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c +++ b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c @@ -812,7 +812,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, int ngtcp2_crypto_read_write_crypto_data( ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, const uint8_t *data, size_t datalen) { - SSL *ssl = ngtcp2_conn_get_tls_native_handle(conn); + SSL *ssl = ngtcp2_conn_get_tls_native_handle2(conn); int rv; int err; @@ -824,7 +824,7 @@ int ngtcp2_crypto_read_write_crypto_data( return -1; } - if (!ngtcp2_conn_get_handshake_completed(conn)) { + if (!ngtcp2_conn_get_handshake_completed2(conn)) { rv = SSL_do_handshake(ssl); if (rv <= 0) { err = SSL_get_error(ssl, rv); diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.c b/deps/ngtcp2/ngtcp2/crypto/shared.c index f1bb90267213da..925461e239788b 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.c +++ b/deps/ngtcp2/ngtcp2/crypto/shared.c @@ -141,7 +141,7 @@ int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret, size_t ngtcp2_crypto_packet_protection_ivlen(const ngtcp2_crypto_aead *aead) { size_t noncelen = ngtcp2_crypto_aead_noncelen(aead); - return ngtcp2_max_size(8, noncelen); + return ngtcp2_max(8, noncelen); } int ngtcp2_crypto_derive_packet_protection_key( @@ -183,21 +183,30 @@ int ngtcp2_crypto_derive_packet_protection_key( if (ngtcp2_crypto_hkdf_expand_label(key, keylen, md, secret, secretlen, key_label, key_labellen) != 0) { - return -1; + goto cleanup; } if (ngtcp2_crypto_hkdf_expand_label(iv, ivlen, md, secret, secretlen, iv_label, iv_labellen) != 0) { - return -1; + goto cleanup; } if (hp_key != NULL && ngtcp2_crypto_hkdf_expand_label(hp_key, keylen, md, secret, secretlen, hp_key_label, hp_key_labellen) != 0) { - return -1; + goto cleanup; } return 0; + +cleanup: + ngtcp2_secure_clear(key, keylen); + + if (hp_key) { + ngtcp2_secure_clear(hp_key, keylen); + } + + return -1; } int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, uint32_t version, @@ -238,14 +247,15 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, const ngtcp2_crypto_cipher *hp; ngtcp2_crypto_aead_ctx aead_ctx = {0}; ngtcp2_crypto_cipher_ctx hp_ctx = {0}; - void *tls = ngtcp2_conn_get_tls_native_handle(conn); + void *tls = ngtcp2_conn_get_tls_native_handle2(conn); uint8_t keybuf[64], ivbuf[64], hp_keybuf[64]; + size_t keylen; size_t ivlen; int rv; ngtcp2_crypto_ctx cctx; uint32_t version; - if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && !ngtcp2_conn_is_server(conn)) { + if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && !ngtcp2_conn_is_server2(conn)) { return 0; } @@ -266,12 +276,12 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } ngtcp2_conn_set_0rtt_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_0rtt_crypto_ctx(conn); - version = ngtcp2_conn_get_client_chosen_version(conn); + ctx = ngtcp2_conn_get_0rtt_crypto_ctx2(conn); + version = ngtcp2_conn_get_client_chosen_version2(conn); break; case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: - if (ngtcp2_conn_is_server(conn) && - !ngtcp2_conn_get_negotiated_version(conn)) { + if (ngtcp2_conn_is_server2(conn) && + !ngtcp2_conn_get_negotiated_version2(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { return -1; @@ -279,8 +289,8 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } /* fall through */ case NGTCP2_ENCRYPTION_LEVEL_1RTT: - ctx = ngtcp2_conn_get_crypto_ctx(conn); - version = ngtcp2_conn_get_negotiated_version(conn); + ctx = ngtcp2_conn_get_crypto_ctx2(conn); + version = ngtcp2_conn_get_negotiated_version2(conn); if (!ctx->aead.native_handle) { if (ngtcp2_crypto_ctx_tls(&cctx, tls) == NULL) { @@ -288,7 +298,7 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } ngtcp2_conn_set_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_crypto_ctx(conn); + ctx = ngtcp2_conn_get_crypto_ctx2(conn); } break; default: @@ -298,6 +308,7 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, aead = &ctx->aead; md = &ctx->md; hp = &ctx->hp; + keylen = ngtcp2_crypto_aead_keylen(aead); ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, version, aead, @@ -328,7 +339,7 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } break; case NGTCP2_ENCRYPTION_LEVEL_1RTT: - if (!ngtcp2_conn_is_server(conn)) { + if (!ngtcp2_conn_is_server2(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { goto fail; @@ -346,12 +357,21 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, goto fail; } + /* Clear keys in the stack buffers. */ + ngtcp2_secure_clear(keybuf, keylen); + ngtcp2_secure_clear(hp_keybuf, keylen); + return 0; fail: ngtcp2_crypto_cipher_ctx_free(&hp_ctx); ngtcp2_crypto_aead_ctx_free(&aead_ctx); + /* Clear keys from the given buffers as well as the stack buffers if + used. */ + ngtcp2_secure_clear(key, keylen); + ngtcp2_secure_clear(hp_key, keylen); + return -1; } @@ -365,7 +385,7 @@ static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) { ngtcp2_ssize nwrite; uint8_t buf[256]; - nwrite = ngtcp2_conn_encode_local_transport_params(conn, buf, sizeof(buf)); + nwrite = ngtcp2_conn_encode_local_transport_params2(conn, buf, sizeof(buf)); if (nwrite < 0) { return -1; } @@ -388,14 +408,15 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, const ngtcp2_crypto_cipher *hp; ngtcp2_crypto_aead_ctx aead_ctx = {0}; ngtcp2_crypto_cipher_ctx hp_ctx = {0}; - void *tls = ngtcp2_conn_get_tls_native_handle(conn); + void *tls = ngtcp2_conn_get_tls_native_handle2(conn); uint8_t keybuf[64], ivbuf[64], hp_keybuf[64]; + size_t keylen; size_t ivlen; int rv; ngtcp2_crypto_ctx cctx; uint32_t version; - if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && ngtcp2_conn_is_server(conn)) { + if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && ngtcp2_conn_is_server2(conn)) { return 0; } @@ -416,12 +437,12 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } ngtcp2_conn_set_0rtt_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_0rtt_crypto_ctx(conn); - version = ngtcp2_conn_get_client_chosen_version(conn); + ctx = ngtcp2_conn_get_0rtt_crypto_ctx2(conn); + version = ngtcp2_conn_get_client_chosen_version2(conn); break; case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: - if (ngtcp2_conn_is_server(conn) && - !ngtcp2_conn_get_negotiated_version(conn)) { + if (ngtcp2_conn_is_server2(conn) && + !ngtcp2_conn_get_negotiated_version2(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { return -1; @@ -429,8 +450,8 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } /* fall through */ case NGTCP2_ENCRYPTION_LEVEL_1RTT: - ctx = ngtcp2_conn_get_crypto_ctx(conn); - version = ngtcp2_conn_get_negotiated_version(conn); + ctx = ngtcp2_conn_get_crypto_ctx2(conn); + version = ngtcp2_conn_get_negotiated_version2(conn); if (!ctx->aead.native_handle) { if (ngtcp2_crypto_ctx_tls(&cctx, tls) == NULL) { @@ -438,7 +459,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } ngtcp2_conn_set_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_crypto_ctx(conn); + ctx = ngtcp2_conn_get_crypto_ctx2(conn); } break; default: @@ -448,6 +469,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, aead = &ctx->aead; md = &ctx->md; hp = &ctx->hp; + keylen = ngtcp2_crypto_aead_keylen(aead); ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, version, aead, @@ -477,11 +499,11 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, goto fail; } - if (ngtcp2_conn_is_server(conn) && + if (ngtcp2_conn_is_server2(conn) && crypto_set_local_transport_params(conn, tls) != 0) { /* Just return -1 because aead_ctx and hp_ctx are now owned by conn. */ - return -1; + goto fail_cleanup; } break; @@ -497,12 +519,22 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, goto fail; } + /* Clear keys in the stack buffers. */ + ngtcp2_secure_clear(keybuf, keylen); + ngtcp2_secure_clear(hp_keybuf, keylen); + return 0; fail: ngtcp2_crypto_cipher_ctx_free(&hp_ctx); ngtcp2_crypto_aead_ctx_free(&aead_ctx); +fail_cleanup: + /* Clear keys from the given buffers as well as the stack buffers if + used. */ + ngtcp2_secure_clear(key, keylen); + ngtcp2_secure_clear(hp_key, keylen); + return -1; } @@ -528,7 +560,7 @@ int ngtcp2_crypto_derive_and_install_initial_key( ngtcp2_crypto_cipher_ctx tx_hp_ctx = {0}; ngtcp2_crypto_aead_ctx retry_aead_ctx = {0}; int rv; - int server = ngtcp2_conn_is_server(conn); + int server = ngtcp2_conn_is_server2(conn); const uint8_t *retry_key; size_t retry_noncelen; @@ -603,7 +635,7 @@ int ngtcp2_crypto_derive_and_install_initial_key( goto fail; } - if (!server && !ngtcp2_conn_after_retry(conn)) { + if (!server && !ngtcp2_conn_after_retry2(conn)) { ngtcp2_crypto_aead_retry(&retry_aead); switch (version) { @@ -661,13 +693,13 @@ int ngtcp2_crypto_derive_and_install_vneg_initial_key( uint8_t tx_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN]; uint8_t tx_ivbuf[NGTCP2_CRYPTO_INITIAL_IVLEN]; uint8_t tx_hp_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN]; - const ngtcp2_crypto_ctx *ctx = ngtcp2_conn_get_initial_crypto_ctx(conn); + const ngtcp2_crypto_ctx *ctx = ngtcp2_conn_get_initial_crypto_ctx2(conn); ngtcp2_crypto_aead_ctx rx_aead_ctx = {0}; ngtcp2_crypto_cipher_ctx rx_hp_ctx = {0}; ngtcp2_crypto_aead_ctx tx_aead_ctx = {0}; ngtcp2_crypto_cipher_ctx tx_hp_ctx = {0}; int rv; - int server = ngtcp2_conn_is_server(conn); + int server = ngtcp2_conn_is_server2(conn); if (!rx_secret) { rx_secret = rx_secretbuf; @@ -760,45 +792,54 @@ int ngtcp2_crypto_update_key( ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_key, uint8_t *tx_iv, const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, size_t secretlen) { - const ngtcp2_crypto_ctx *ctx = ngtcp2_conn_get_crypto_ctx(conn); + const ngtcp2_crypto_ctx *ctx = ngtcp2_conn_get_crypto_ctx2(conn); const ngtcp2_crypto_aead *aead = &ctx->aead; const ngtcp2_crypto_md *md = &ctx->md; + size_t keylen = ngtcp2_crypto_aead_keylen(aead); size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); - uint32_t version = ngtcp2_conn_get_negotiated_version(conn); + uint32_t version = ngtcp2_conn_get_negotiated_version2(conn); if (ngtcp2_crypto_update_traffic_secret(rx_secret, version, md, current_rx_secret, secretlen) != 0) { - return -1; + goto cleanup; } if (ngtcp2_crypto_derive_packet_protection_key( rx_key, rx_iv, NULL, version, aead, md, rx_secret, secretlen) != 0) { - return -1; + goto cleanup; } if (ngtcp2_crypto_update_traffic_secret(tx_secret, version, md, current_tx_secret, secretlen) != 0) { - return -1; + goto cleanup; } if (ngtcp2_crypto_derive_packet_protection_key( tx_key, tx_iv, NULL, version, aead, md, tx_secret, secretlen) != 0) { - return -1; + goto cleanup; } if (ngtcp2_crypto_aead_ctx_decrypt_init(rx_aead_ctx, aead, rx_key, ivlen) != 0) { - return -1; + goto cleanup; } if (ngtcp2_crypto_aead_ctx_encrypt_init(tx_aead_ctx, aead, tx_key, ivlen) != 0) { ngtcp2_crypto_aead_ctx_free(rx_aead_ctx); rx_aead_ctx->native_handle = NULL; - return -1; + goto cleanup; } return 0; + +cleanup: + ngtcp2_secure_clear(rx_secret, secretlen); + ngtcp2_secure_clear(tx_secret, secretlen); + ngtcp2_secure_clear(rx_key, keylen); + ngtcp2_secure_clear(tx_key, keylen); + + return -1; } int ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, @@ -842,12 +883,18 @@ int ngtcp2_crypto_update_key_cb( size_t secretlen, void *user_data) { uint8_t rx_key[64]; uint8_t tx_key[64]; + int rv; (void)conn; (void)user_data; - if (ngtcp2_crypto_update_key( - conn, rx_secret, tx_secret, rx_aead_ctx, rx_key, rx_iv, tx_aead_ctx, - tx_key, tx_iv, current_rx_secret, current_tx_secret, secretlen) != 0) { + rv = ngtcp2_crypto_update_key( + conn, rx_secret, tx_secret, rx_aead_ctx, rx_key, rx_iv, tx_aead_ctx, tx_key, + tx_iv, current_rx_secret, current_tx_secret, secretlen); + + ngtcp2_secure_clear(rx_key, sizeof(rx_key)); + ngtcp2_secure_clear(tx_key, sizeof(tx_key)); + + if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; @@ -1012,6 +1059,11 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token( return p - token; } +static int crypto_token_expired(ngtcp2_tstamp gen_ts, ngtcp2_duration timeout, + ngtcp2_tstamp ts) { + return ts >= timeout && gen_ts <= ts - timeout; +} + int ngtcp2_crypto_verify_retry_token( ngtcp2_cid *odcid, const uint8_t *token, size_t tokenlen, const uint8_t *secret, size_t secretlen, uint32_t version, @@ -1089,7 +1141,7 @@ int ngtcp2_crypto_verify_retry_token( sizeof(gen_ts)); gen_ts = ngtcp2_ntohl64(gen_ts); - if (gen_ts + timeout <= ts) { + if (crypto_token_expired(gen_ts, timeout, ts)) { return -1; } @@ -1287,7 +1339,7 @@ int ngtcp2_crypto_verify_retry_token2( memcpy(&gen_ts, p + NGTCP2_MAX_CIDLEN, sizeof(gen_ts)); gen_ts = ngtcp2_ntohl64(gen_ts); - if (gen_ts + timeout <= ts) { + if (crypto_token_expired(gen_ts, timeout, ts)) { return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN; } @@ -1481,7 +1533,7 @@ static ngtcp2_ssize crypto_verify_regular_token( memcpy(&gen_ts, plaintext, sizeof(gen_ts)); gen_ts = ngtcp2_ntohl64(gen_ts); - if (gen_ts + timeout <= ts) { + if (crypto_token_expired(gen_ts, timeout, ts)) { return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN; } @@ -1641,13 +1693,13 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, } int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, void *user_data) { - const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(conn); - void *tls = ngtcp2_conn_get_tls_native_handle(conn); + const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid2(conn); + void *tls = ngtcp2_conn_get_tls_native_handle2(conn); (void)user_data; if (ngtcp2_crypto_derive_and_install_initial_key( conn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - ngtcp2_conn_get_client_chosen_version(conn), dcid) != 0) { + ngtcp2_conn_get_client_chosen_version2(conn), dcid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1669,7 +1721,7 @@ int ngtcp2_crypto_recv_retry_cb(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, if (ngtcp2_crypto_derive_and_install_initial_key( conn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - ngtcp2_conn_get_client_chosen_version(conn), &hd->scid) != 0) { + ngtcp2_conn_get_client_chosen_version2(conn), &hd->scid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1683,7 +1735,7 @@ int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn, if (ngtcp2_crypto_derive_and_install_initial_key( conn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - ngtcp2_conn_get_client_chosen_version(conn), dcid) != 0) { + ngtcp2_conn_get_client_chosen_version2(conn), dcid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1744,7 +1796,7 @@ int ngtcp2_crypto_recv_crypto_data_cb(ngtcp2_conn *conn, return 0; } - rv = ngtcp2_conn_get_tls_error(conn); + rv = ngtcp2_conn_get_tls_error2(conn); if (rv) { return rv; } diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.h b/deps/ngtcp2/ngtcp2/crypto/shared.h index c517b7f2249041..e853c8140fea76 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.h +++ b/deps/ngtcp2/ngtcp2/crypto/shared.h @@ -261,7 +261,7 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls); * This function calls `ngtcp2_conn_set_initial_crypto_ctx` to set * initial AEAD and message digest algorithm. After the successful * call of this function, application can use - * `ngtcp2_conn_get_initial_crypto_ctx` to get the object. + * `ngtcp2_conn_get_initial_crypto_ctx2` to get the object. * * This function returns 0 if it succeeds, or -1. */ diff --git a/deps/ngtcp2/ngtcp2/crypto/shared_test.c b/deps/ngtcp2/ngtcp2/crypto/shared_test.c new file mode 100644 index 00000000000000..68e78b0cad0cf0 --- /dev/null +++ b/deps/ngtcp2/ngtcp2/crypto/shared_test.c @@ -0,0 +1,218 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "shared_test.h" + +#include + +#include "shared.h" +#include "ngtcp2_macro.h" + +static const MunitTest tests[] = { + munit_void_test(test_ngtcp2_crypto_verify_retry_token), + munit_void_test(test_ngtcp2_crypto_verify_regular_token), + munit_test_end(), +}; + +const MunitSuite shared_suite = { + .prefix = "/shared", + .tests = tests, +}; + +void test_ngtcp2_crypto_verify_retry_token(void) { + const uint8_t secret[] = "retry-token-secret"; + const ngtcp2_sockaddr_in6 in6addr = { + .sin6_family = NGTCP2_AF_INET6, + .sin6_port = 39918, + }; + const ngtcp2_sockaddr_in inaddr = { + .sin_family = NGTCP2_AF_INET, + .sin_port = 39918, + }; + const ngtcp2_cid retry_scid = { + .datalen = NGTCP2_MAX_CIDLEN, + .data = {0xBA, 0xAD, 0xF0, 0x0D}, + }; + const ngtcp2_cid odcid = { + .datalen = NGTCP2_MAX_CIDLEN, + .data = {0xBA, 0xAD, 0xCA, 0xCE}, + }; + const ngtcp2_cid dcid = { + .datalen = NGTCP2_MAX_CIDLEN, + .data = {0xDE, 0xAD, 0xF1, 0x5b}, + }; + ngtcp2_cid decoded_odcid; + ngtcp2_tstamp t = 3600 * NGTCP2_SECONDS; + uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN2]; + ngtcp2_ssize tokenlen; + int rv; + + tokenlen = ngtcp2_crypto_generate_retry_token2( + token, secret, ngtcp2_strlen_lit(secret), NGTCP2_PROTO_VER_V1, + (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), &retry_scid, &odcid, t); + + assert_ptrdiff(NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN2, ==, tokenlen); + + /* Successful validation */ + rv = ngtcp2_crypto_verify_retry_token2( + &decoded_odcid, token, (size_t)tokenlen, secret, ngtcp2_strlen_lit(secret), + NGTCP2_PROTO_VER_V1, (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), + &retry_scid, 10 * NGTCP2_SECONDS, t); + + assert_int(0, ==, rv); + assert_true(ngtcp2_cid_eq(&odcid, &decoded_odcid)); + + /* Timeout */ + rv = ngtcp2_crypto_verify_retry_token2( + &decoded_odcid, token, (size_t)tokenlen, secret, ngtcp2_strlen_lit(secret), + NGTCP2_PROTO_VER_V1, (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), + &retry_scid, 10 * NGTCP2_SECONDS, t + 10 * NGTCP2_SECONDS); + + assert_int(NGTCP2_CRYPTO_ERR_VERIFY_TOKEN, ==, rv); + + /* Bad DCID */ + rv = ngtcp2_crypto_verify_retry_token2( + &decoded_odcid, token, (size_t)tokenlen, secret, ngtcp2_strlen_lit(secret), + NGTCP2_PROTO_VER_V1, (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), + &dcid, 10 * NGTCP2_SECONDS, t); + + assert_int(NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN, ==, rv); + + /* Bad address */ + rv = ngtcp2_crypto_verify_retry_token2( + &decoded_odcid, token, (size_t)tokenlen, secret, ngtcp2_strlen_lit(secret), + NGTCP2_PROTO_VER_V1, (const ngtcp2_sockaddr *)&inaddr, sizeof(inaddr), + &retry_scid, 10 * NGTCP2_SECONDS, t); + + assert_int(NGTCP2_CRYPTO_ERR_VERIFY_TOKEN, ==, rv); + + /* Truncated token */ + rv = ngtcp2_crypto_verify_retry_token2( + &decoded_odcid, token, (size_t)tokenlen - 1, secret, + ngtcp2_strlen_lit(secret), NGTCP2_PROTO_VER_V1, + (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), &retry_scid, + 10 * NGTCP2_SECONDS, t); + + assert_int(NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN, ==, rv); + + /* Bad magic */ + token[0] = 0; + + rv = ngtcp2_crypto_verify_retry_token2( + &decoded_odcid, token, (size_t)tokenlen, secret, ngtcp2_strlen_lit(secret), + NGTCP2_PROTO_VER_V1, (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), + &retry_scid, 10 * NGTCP2_SECONDS, t); + + assert_int(NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN, ==, rv); +} + +void test_ngtcp2_crypto_verify_regular_token(void) { + const uint8_t secret[] = "regular-token-secret"; + const ngtcp2_sockaddr_in6 in6addr = { + .sin6_family = NGTCP2_AF_INET6, + .sin6_port = 39918, + }; + const ngtcp2_sockaddr_in inaddr = { + .sin_family = NGTCP2_AF_INET, + .sin_port = 39918, + }; + const uint8_t token_data[] = "I am the token data"; + const ngtcp2_tstamp timeout = 10 * NGTCP2_SECONDS; + ngtcp2_tstamp t = 3600 * NGTCP2_SECONDS; + uint8_t token[NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN + 256]; + ngtcp2_ssize tokenlen; + ngtcp2_ssize token_datalen; + uint8_t decoded_token_data[256]; + + tokenlen = ngtcp2_crypto_generate_regular_token2( + token, secret, ngtcp2_strlen_lit(secret), (const ngtcp2_sockaddr *)&in6addr, + sizeof(in6addr), token_data, ngtcp2_strlen_lit(token_data), t); + + assert_ptrdiff(NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN + + ngtcp2_strlen_lit(token_data), + ==, tokenlen); + + /* Successful validation */ + token_datalen = ngtcp2_crypto_verify_regular_token2( + decoded_token_data, sizeof(decoded_token_data), token, (size_t)tokenlen, + secret, ngtcp2_strlen_lit(secret), (const ngtcp2_sockaddr *)&in6addr, + sizeof(in6addr), timeout, t); + + assert_ptrdiff(ngtcp2_strlen_lit(token_data), ==, token_datalen); + assert_memory_equal(ngtcp2_strlen_lit(token_data), token_data, + decoded_token_data); + + /* Timeout */ + token_datalen = ngtcp2_crypto_verify_regular_token2( + decoded_token_data, sizeof(decoded_token_data), token, (size_t)tokenlen, + secret, ngtcp2_strlen_lit(secret), (const ngtcp2_sockaddr *)&in6addr, + sizeof(in6addr), timeout, t + timeout); + + assert_ptrdiff(NGTCP2_CRYPTO_ERR_VERIFY_TOKEN, ==, token_datalen); + + /* Bad address */ + token_datalen = ngtcp2_crypto_verify_regular_token2( + decoded_token_data, sizeof(decoded_token_data), token, (size_t)tokenlen, + secret, ngtcp2_strlen_lit(secret), (const ngtcp2_sockaddr *)&inaddr, + sizeof(inaddr), timeout, t); + + assert_ptrdiff(NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN, ==, token_datalen); + + /* Insufficient data buffer */ + memset(decoded_token_data, 0, sizeof(decoded_token_data)); + + token_datalen = ngtcp2_crypto_verify_regular_token2( + decoded_token_data, ngtcp2_strlen_lit(token_data) - 1, token, + (size_t)tokenlen, secret, ngtcp2_strlen_lit(secret), + (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), timeout, t); + + assert_ptrdiff(0, ==, token_datalen); + + /* NULL buffer */ + memset(decoded_token_data, 0, sizeof(decoded_token_data)); + + token_datalen = ngtcp2_crypto_verify_regular_token2( + NULL, 0, token, (size_t)tokenlen, secret, ngtcp2_strlen_lit(secret), + (const ngtcp2_sockaddr *)&in6addr, sizeof(in6addr), timeout, t); + + assert_ptrdiff(0, ==, token_datalen); + + /* Truncated token */ + token_datalen = ngtcp2_crypto_verify_regular_token2( + decoded_token_data, sizeof(decoded_token_data), token, (size_t)tokenlen - 1, + secret, ngtcp2_strlen_lit(secret), (const ngtcp2_sockaddr *)&in6addr, + sizeof(in6addr), timeout, t); + + assert_ptrdiff(NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN, ==, token_datalen); + + /* Bad magic */ + token[0] = 0; + + token_datalen = ngtcp2_crypto_verify_regular_token2( + decoded_token_data, sizeof(decoded_token_data), token, (size_t)tokenlen, + secret, ngtcp2_strlen_lit(secret), (const ngtcp2_sockaddr *)&in6addr, + sizeof(in6addr), timeout, t); + + assert_ptrdiff(NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN, ==, token_datalen); +} diff --git a/deps/ngtcp2/ngtcp2/crypto/shared_test.h b/deps/ngtcp2/ngtcp2/crypto/shared_test.h new file mode 100644 index 00000000000000..fe3d023cd9efdc --- /dev/null +++ b/deps/ngtcp2/ngtcp2/crypto/shared_test.h @@ -0,0 +1,41 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_SHARED_TEST_H +#define NGTCP2_SHARED_TEST_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* defined(HAVE_CONFIG_H) */ + +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + +extern const MunitSuite shared_suite; + +munit_void_test_decl(test_ngtcp2_crypto_verify_retry_token) +munit_void_test_decl(test_ngtcp2_crypto_verify_regular_token) + +#endif /* !defined(NGTCP2_SHARED_TEST_H) */ diff --git a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c index fa2b147b6ba1be..16161597360c26 100644 --- a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c @@ -339,7 +339,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, int ngtcp2_crypto_read_write_crypto_data( ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, const uint8_t *data, size_t datalen) { - WOLFSSL *ssl = ngtcp2_conn_get_tls_native_handle(conn); + WOLFSSL *ssl = ngtcp2_conn_get_tls_native_handle2(conn); WOLFSSL_ENCRYPTION_LEVEL level = ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level(encryption_level); int rv; @@ -355,7 +355,7 @@ int ngtcp2_crypto_read_write_crypto_data( } } - if (!ngtcp2_conn_get_handshake_completed(conn)) { + if (!ngtcp2_conn_get_handshake_completed2(conn)) { rv = wolfSSL_quic_do_handshake(ssl); if (rv <= 0) { err = wolfSSL_get_error(ssl, rv); diff --git a/deps/ngtcp2/ngtcp2/examples/client.cc b/deps/ngtcp2/ngtcp2/examples/client.cc index 0c10e7bbdc0483..30e078c8e673e6 100644 --- a/deps/ngtcp2/ngtcp2/examples/client.cc +++ b/deps/ngtcp2/ngtcp2/examples/client.cc @@ -58,9 +58,7 @@ namespace { auto randgen = util::make_mt19937(); } // namespace -namespace { -constexpr size_t max_preferred_versionslen = 4; -} // namespace +constexpr auto max_preferred_versionslen = 4UZ; Config config; @@ -89,14 +87,13 @@ std::expected Stream::open_file(std::string_view path) { } } - auto fname = std::string{config.download}; - fname += '/'; - fname += filename; + auto fpath = config.download; + fpath /= filename; - fd = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC, + fd = open(fpath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd == -1) { - std::println(stderr, "open: Could not open file {}: {}", fname, + std::println(stderr, "open: Could not open file {}: {}", fpath.native(), strerror(errno)); return std::unexpected{Error::IO}; } @@ -200,14 +197,7 @@ Client::Client(struct ev_loop *loop, uint32_t client_chosen_version, ev_signal_init(&sigintev_, siginthandler, SIGINT); } -Client::~Client() { - disconnect(); - - if (httpconn_) { - nghttp3_conn_del(httpconn_); - httpconn_ = nullptr; - } -} +Client::~Client() { disconnect(); } void Client::disconnect() { tx_.send_blocked = false; @@ -308,7 +298,7 @@ std::expected Client::handshake_completed() { return std::unexpected{Error::QUIC}; } - if (auto rv = setup_httpconn(); !rv) { + if (auto rv = proto_codec_->setup_codec(); !rv) { return rv; } } @@ -327,17 +317,17 @@ std::expected Client::handshake_completed() { } } - if (config.tp_file) { + if (!config.tp_file.empty()) { std::array data; - auto datalen = - ngtcp2_conn_encode_0rtt_transport_params(conn_, data.data(), data.size()); + auto datalen = ngtcp2_conn_encode_0rtt_transport_params2(conn_, data.data(), + data.size()); if (datalen < 0) { std::println(stderr, "Could not encode 0-RTT transport parameters: {}", ngtcp2_strerror(static_cast(datalen))); } else if (!util::write_transport_params( config.tp_file, {data.data(), static_cast(datalen)})) { std::println(stderr, "Could not write transport parameters to {}", - config.tp_file); + config.tp_file.native()); } } @@ -405,10 +395,6 @@ int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, void *stream_user_data) { auto c = static_cast(user_data); - if (!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) { - app_error_code = NGHTTP3_H3_NO_ERROR; - } - if (!c->on_stream_close(stream_id, app_error_code)) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -592,12 +578,7 @@ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, std::expected Client::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { - if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) { - std::println(stderr, "nghttp3_conn_unblock_stream: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - return {}; + return proto_codec_->extend_max_stream_data(stream_id, max_data); } namespace { @@ -621,7 +602,7 @@ int recv_rx_key(ngtcp2_conn *conn, ngtcp2_encryption_level level, } auto c = static_cast(user_data); - if (!c->setup_httpconn()) { + if (!c->setup_codec()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -640,8 +621,7 @@ int early_data_rejected(ngtcp2_conn *conn, void *user_data) { } // namespace void Client::early_data_rejected() { - nghttp3_conn_del(httpconn_); - httpconn_ = nullptr; + proto_codec_->early_data_rejected(); nstreams_done_ = 0; streams_.clear(); @@ -665,7 +645,7 @@ std::expected Client::init(int fd, const Address &local_addr, addr_ = addr; port_ = port; - auto callbacks = ngtcp2_callbacks{ + static constexpr auto callbacks = ngtcp2_callbacks{ .client_initial = ngtcp2_crypto_client_initial_cb, .recv_crypto_data = ::recv_crypto_data, .handshake_completed = ::handshake_completed, @@ -720,20 +700,19 @@ std::expected Client::init(int fd, const Address &local_addr, ngtcp2_settings settings; ngtcp2_settings_default(&settings); - settings.log_printf = config.quiet ? nullptr : debug::log_printf; + settings.log_write = config.quiet ? nullptr : debug::log_write; if (!config.qlog_file.empty() || !config.qlog_dir.empty()) { - std::string path; + std::filesystem::path path; if (!config.qlog_file.empty()) { path = config.qlog_file; } else { - path = std::string{config.qlog_dir}; - path += '/'; - path += util::format_hex(scid.data, as_signed(scid.datalen)); + path = config.qlog_dir; + path /= util::format_hex(scid.data, as_signed(scid.datalen)); path += ".sqlog"; } qlog_ = fopen(path.c_str(), "w"); if (qlog_ == nullptr) { - std::println(stderr, "Could not open qlog file {}: {}", path, + std::println(stderr, "Could not open qlog file {}: {}", path.native(), strerror(errno)); return std::unexpected{Error::IO}; } @@ -762,7 +741,7 @@ std::expected Client::init(int fd, const Address &local_addr, std::vector token; if (!config.token_file.empty()) { - std::println(stderr, "Reading token file {}", config.token_file); + std::println(stderr, "Reading token file {}", config.token_file.native()); auto t = util::read_token(config.token_file); if (t) { @@ -821,15 +800,17 @@ std::expected Client::init(int fd, const Address &local_addr, return std::unexpected{Error::QUIC}; } + proto_codec_ = std::make_unique(this, last_error_); + if (auto rv = tls_session_.init(early_data_, tls_ctx, addr_, this, - client_chosen_version_, AppProtocol::H3); + client_chosen_version_, ProtoCodec::protocol); !rv) { return rv; } ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle()); - if (early_data_ && config.tp_file) { + if (early_data_ && !config.tp_file.empty()) { auto params = util::read_transport_params(config.tp_file); if (!params) { early_data_ = false; @@ -871,13 +852,14 @@ Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); if (!last_error_.error_code) { if (rv == NGTCP2_ERR_CRYPTO) { - auto alert = ngtcp2_conn_get_tls_alert(conn_); + auto alert = ngtcp2_conn_get_tls_alert2(conn_); ngtcp2_ccerr_set_tls_alert(&last_error_, alert, nullptr, 0); - if (alert == TLS_ALERT_ECH_REQUIRED && config.ech_config_list_file && + if (alert == TLS_ALERT_ECH_REQUIRED && + !config.ech_config_list_file.empty() && !tls_session_.write_ech_config_list(config.ech_config_list_file)) { std::println(stderr, "Could not write ECH retry configs in {}", - config.ech_config_list_file); + config.ech_config_list_file.native()); } } else { ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); @@ -983,8 +965,8 @@ std::expected Client::on_read(const Endpoint &ep) { } if (should_exit()) { - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(0), nullptr, 0); + ngtcp2_ccerr_set_application_error(&last_error_, ProtoCodec::no_error, + nullptr, 0); disconnect(); return std::unexpected{Error::INTERNAL}; } @@ -1022,8 +1004,8 @@ std::expected Client::on_write() { } if (should_exit()) { - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(0), nullptr, 0); + ngtcp2_ccerr_set_application_error(&last_error_, ProtoCodec::no_error, + nullptr, 0); disconnect(); return std::unexpected{Error::INTERNAL}; } @@ -1045,89 +1027,7 @@ ngtcp2_ssize write_pkt(ngtcp2_conn *conn, ngtcp2_path *path, ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts) { - std::array vec; - - for (;;) { - int64_t stream_id = -1; - int fin = 0; - nghttp3_ssize sveccnt = 0; - - if (httpconn_ && ngtcp2_conn_get_max_data_left(conn_)) { - sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin, - vec.data(), vec.size()); - if (sveccnt < 0) { - std::println(stderr, "nghttp3_conn_writev_stream: {}", - nghttp3_strerror(static_cast(sveccnt))); - ngtcp2_ccerr_set_application_error( - &last_error_, - nghttp3_err_infer_quic_app_error_code(static_cast(sveccnt)), - nullptr, 0); - return NGTCP2_ERR_CALLBACK_FAILURE; - } - } - - ngtcp2_ssize ndatalen; - auto v = vec.data(); - auto vcnt = static_cast(sveccnt); - - uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE; - if (fin) { - flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; - } - - auto nwrite = ngtcp2_conn_writev_stream( - conn_, path, pi, dest, destlen, &ndatalen, flags, stream_id, - reinterpret_cast(v), vcnt, ts); - if (nwrite < 0) { - switch (nwrite) { - case NGTCP2_ERR_STREAM_DATA_BLOCKED: - assert(ndatalen == -1); - nghttp3_conn_block_stream(httpconn_, stream_id); - continue; - case NGTCP2_ERR_STREAM_SHUT_WR: - assert(ndatalen == -1); - nghttp3_conn_shutdown_stream_write(httpconn_, stream_id); - continue; - case NGTCP2_ERR_WRITE_MORE: - assert(ndatalen >= 0); - if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, - as_unsigned(ndatalen)); - rv != 0) { - std::println(stderr, "nghttp3_conn_add_write_offset: {}", - nghttp3_strerror(rv)); - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, - 0); - return NGTCP2_ERR_CALLBACK_FAILURE; - } - continue; - } - - assert(ndatalen == -1); - - std::println(stderr, "ngtcp2_conn_writev_stream: {}", - ngtcp2_strerror(static_cast(nwrite))); - ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, - 0); - - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - if (ndatalen >= 0) { - if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, - as_unsigned(ndatalen)); - rv != 0) { - std::println(stderr, "nghttp3_conn_add_write_offset: {}", - nghttp3_strerror(rv)); - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); - - return NGTCP2_ERR_CALLBACK_FAILURE; - } - } - - return nwrite; - } + return proto_codec_->write_pkt(path, pi, dest, destlen, ts); } std::expected Client::write_streams() { @@ -1176,7 +1076,7 @@ Client::send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, } void Client::update_timer() { - auto expiry = ngtcp2_conn_get_expiry(conn_); + auto expiry = ngtcp2_conn_get_expiry2(conn_); auto now = util::timestamp(); if (expiry <= now) { @@ -1348,7 +1248,7 @@ Client::endpoint_for(const Address &remote_addr) { const auto &ia = *maybe_ia; - auto current_path = ngtcp2_conn_get_path(conn_); + auto current_path = ngtcp2_conn_get_path2(conn_); auto current_ep = static_cast(current_path->user_data); if (addreq(current_ep->addr, ia)) { return current_ep; @@ -1480,7 +1380,7 @@ Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, std::println(stderr, "Updating traffic key"); } - auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); + auto crypto_ctx = ngtcp2_conn_get_crypto_ctx2(conn_); auto aead = &crypto_ctx->aead; auto keylen = ngtcp2_crypto_aead_keylen(aead); auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); @@ -1731,8 +1631,8 @@ void Client::send_blocked_packet() { } std::expected Client::handle_error() { - if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || - ngtcp2_conn_in_draining_period(conn_)) { + if (!conn_ || ngtcp2_conn_in_closing_period2(conn_) || + ngtcp2_conn_in_draining_period2(conn_)) { return {}; } @@ -1764,65 +1664,41 @@ std::expected Client::handle_error() { std::expected Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) { - if (httpconn_) { - if (app_error_code == 0) { - app_error_code = NGHTTP3_H3_NO_ERROR; - } - auto rv = nghttp3_conn_close_stream(httpconn_, stream_id, app_error_code); - switch (rv) { - case 0: - http_stream_close(stream_id, app_error_code); - break; - case NGHTTP3_ERR_STREAM_NOT_FOUND: - // We have to handle the case when stream opened but no data is - // transferred. In this case, nghttp3_conn_close_stream might - // return error. - if (!ngtcp2_is_bidi_stream(stream_id)) { - assert(!ngtcp2_conn_is_local_stream(conn_, stream_id)); - ngtcp2_conn_extend_max_streams_uni(conn_, 1); - } - break; - default: - std::println(stderr, "nghttp3_conn_close_stream: {}", - nghttp3_strerror(rv)); - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); - return std::unexpected{Error::HTTP3}; - } + if (!config.quiet) { + std::println(stderr, "QUIC stream {:#x} closed", stream_id); } - return {}; -} + if (auto rv = proto_codec_->on_stream_close(stream_id, app_error_code); !rv) { + return rv; + } -std::expected Client::on_stream_reset(int64_t stream_id) { - if (httpconn_) { - if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; + if (!ngtcp2_conn_is_local_stream2(conn_, stream_id)) { + // TODO We might later add bidi stream extension here. + if (!ngtcp2_is_bidi_stream(stream_id)) { + ngtcp2_conn_extend_max_streams_uni(conn_, 1); } } - return {}; -} -std::expected Client::on_stream_stop_sending(int64_t stream_id) { - if (!httpconn_) { - return {}; - } + auto it = streams_.find(stream_id); + if (it != std::ranges::end(streams_)) { + ++nstreams_closed_; - if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; + streams_.erase(it); } return {}; } +std::expected Client::on_stream_reset(int64_t stream_id) { + return proto_codec_->on_stream_reset(stream_id); +} + +std::expected Client::on_stream_stop_sending(int64_t stream_id) { + return proto_codec_->on_stream_stop_sending(stream_id); +} + std::expected Client::make_stream_early() { - if (auto rv = setup_httpconn(); !rv) { + if (auto rv = setup_codec(); !rv) { return rv; } @@ -1849,106 +1725,36 @@ void Client::on_extend_max_streams() { auto stream = std::make_unique( config.requests[nstreams_done_ % config.requests.size()], stream_id); - if (!submit_http_request(stream.get())) { + if (!proto_codec_->submit_request(stream.get())) { break; } if (!config.download.empty()) { stream->open_file(stream->req.path); } - streams_.emplace(stream_id, std::move(stream)); - } -} - -namespace { -nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, - size_t veccnt, uint32_t *pflags, void *user_data, - void *stream_user_data) { - vec[0].base = config.data; - vec[0].len = config.datalen; - *pflags |= NGHTTP3_DATA_FLAG_EOF; - - return 1; -} -} // namespace - -std::expected Client::submit_http_request(const Stream *stream) { - std::string content_length_str; - - const auto &req = stream->req; - - std::array nva{ - util::make_nv_nn(":method", config.http_method), - util::make_nv_nn(":scheme", req.scheme), - util::make_nv_nn(":authority", req.authority), - util::make_nv_nn(":path", req.path), - util::make_nv_nn("user-agent", "nghttp3/ngtcp2 client"), - }; - size_t nvlen = 5; - if (config.fd != -1) { - content_length_str = util::format_uint(config.datalen); - nva[nvlen++] = util::make_nv_nc("content-length", content_length_str); - } - - if (!config.quiet) { - debug::print_http_request_headers(stream->stream_id, nva.data(), nvlen); - } - - nghttp3_data_reader dr{ - .read_data = read_data, - }; - if (auto rv = nghttp3_conn_submit_request( - httpconn_, stream->stream_id, nva.data(), nvlen, - config.fd == -1 ? nullptr : &dr, nullptr); - rv != 0) { - std::println(stderr, "nghttp3_conn_submit_request: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; + if (auto [_, rv] = streams_.try_emplace(stream_id, std::move(stream)); + !rv) { + assert(0); + } } - - return {}; } std::expected Client::recv_stream_data(uint32_t flags, int64_t stream_id, std::span data) { - auto nconsumed = nghttp3_conn_read_stream2( - httpconn_, stream_id, data.data(), data.size(), - flags & NGTCP2_STREAM_DATA_FLAG_FIN, ngtcp2_conn_get_timestamp(conn_)); - if (nconsumed < 0) { - std::println(stderr, "nghttp3_conn_read_stream2: {}", - nghttp3_strerror(static_cast(nconsumed))); - ngtcp2_ccerr_set_application_error( - &last_error_, - nghttp3_err_infer_quic_app_error_code(static_cast(nconsumed)), - nullptr, 0); - return std::unexpected{Error::HTTP3}; - } - - ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, - static_cast(nconsumed)); - ngtcp2_conn_extend_max_offset(conn_, static_cast(nconsumed)); - - return {}; + return proto_codec_->recv_stream_data(flags, stream_id, data); } std::expected Client::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) { - if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen); - rv != 0) { - std::println(stderr, "nghttp3_conn_add_ack_offset: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - return {}; + return proto_codec_->acked_stream_data_offset(stream_id, datalen); } std::expected Client::select_preferred_address(Address &selected_addr, const ngtcp2_preferred_addr *paddr) { - auto path = ngtcp2_conn_get_path(conn_); + auto path = ngtcp2_conn_get_path2(conn_); switch (path->local.addr->sa_family) { case AF_INET: @@ -1984,329 +1790,25 @@ Client::select_preferred_address(Address &selected_addr, return {}; } -namespace { -int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data, - size_t datalen, void *user_data, void *stream_user_data) { - if (!config.quiet && !config.no_http_dump) { - debug::print_http_data(stream_id, {data, datalen}); - } - auto c = static_cast(user_data); - c->http_consume(stream_id, datalen); - c->http_write_data(stream_id, {data, datalen}); - return 0; -} -} // namespace - -namespace { -int http_deferred_consume(nghttp3_conn *conn, int64_t stream_id, - size_t nconsumed, void *user_data, - void *stream_user_data) { - auto c = static_cast(user_data); - c->http_consume(stream_id, nconsumed); - return 0; -} -} // namespace - -void Client::http_consume(int64_t stream_id, size_t nconsumed) { - ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed); - ngtcp2_conn_extend_max_offset(conn_, nconsumed); -} - -void Client::http_write_data(int64_t stream_id, std::span data) { - auto it = streams_.find(stream_id); - if (it == std::ranges::end(streams_)) { - return; - } - - auto &stream = (*it).second; - - if (stream->fd == -1) { - return; - } - - ssize_t nwrite; - - for (; !data.empty();) { - do { - nwrite = write(stream->fd, data.data(), data.size()); - } while (nwrite == -1 && errno == EINTR); - - if (nwrite < 0) { - std::println(stderr, "Could not write data to file: {}", strerror(errno)); - - return; - } - - data = data.subspan(static_cast(nwrite)); - } -} - -namespace { -int http_begin_headers(nghttp3_conn *conn, int64_t stream_id, void *user_data, - void *stream_user_data) { - if (!config.quiet) { - debug::print_http_begin_response_headers(stream_id); - } - return 0; -} -} // namespace - -namespace { -int http_recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token, - nghttp3_rcbuf *name, nghttp3_rcbuf *value, uint8_t flags, - void *user_data, void *stream_user_data) { - if (!config.quiet) { - debug::print_http_header(stream_id, name, value, flags); - } - return 0; -} -} // namespace - -namespace { -int http_end_headers(nghttp3_conn *conn, int64_t stream_id, int fin, - void *user_data, void *stream_user_data) { - if (!config.quiet) { - debug::print_http_end_headers(stream_id); - } - return 0; -} -} // namespace - -namespace { -int http_begin_trailers(nghttp3_conn *conn, int64_t stream_id, void *user_data, - void *stream_user_data) { - if (!config.quiet) { - debug::print_http_begin_trailers(stream_id); - } - return 0; -} -} // namespace - -namespace { -int http_recv_trailer(nghttp3_conn *conn, int64_t stream_id, int32_t token, - nghttp3_rcbuf *name, nghttp3_rcbuf *value, uint8_t flags, - void *user_data, void *stream_user_data) { - if (!config.quiet) { - debug::print_http_header(stream_id, name, value, flags); - } - return 0; -} -} // namespace - -namespace { -int http_end_trailers(nghttp3_conn *conn, int64_t stream_id, int fin, - void *user_data, void *stream_user_data) { - if (!config.quiet) { - debug::print_http_end_trailers(stream_id); - } - return 0; -} -} // namespace - -namespace { -int http_stop_sending(nghttp3_conn *conn, int64_t stream_id, - uint64_t app_error_code, void *user_data, - void *stream_user_data) { - auto c = static_cast(user_data); - if (!c->stop_sending(stream_id, app_error_code)) { - return NGHTTP3_ERR_CALLBACK_FAILURE; - } - return 0; -} -} // namespace - -std::expected Client::stop_sending(int64_t stream_id, - uint64_t app_error_code) { - if (auto rv = - ngtcp2_conn_shutdown_stream_read(conn_, 0, stream_id, app_error_code); - rv != 0) { - std::println(stderr, "ngtcp2_conn_shutdown_stream_read: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - return {}; -} - -namespace { -int http_reset_stream(nghttp3_conn *conn, int64_t stream_id, - uint64_t app_error_code, void *user_data, - void *stream_user_data) { - auto c = static_cast(user_data); - if (!c->reset_stream(stream_id, app_error_code)) { - return NGHTTP3_ERR_CALLBACK_FAILURE; - } - return 0; +std::expected Client::setup_codec() { + return proto_codec_->setup_codec(); } -} // namespace -std::expected Client::reset_stream(int64_t stream_id, - uint64_t app_error_code) { - if (auto rv = - ngtcp2_conn_shutdown_stream_write(conn_, 0, stream_id, app_error_code); - rv != 0) { - std::println(stderr, "ngtcp2_conn_shutdown_stream_write: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - return {}; +const std::vector &Client::get_offered_versions() const { + return offered_versions_; } -void Client::http_stream_close(int64_t stream_id, uint64_t app_error_code) { - if (!ngtcp2_is_bidi_stream(stream_id)) { - return; - } - - assert(ngtcp2_conn_is_local_stream(conn_, stream_id)); - - ++nstreams_closed_; +bool Client::get_early_data() const { return early_data_; } +Stream *Client::find_stream(int64_t stream_id) const { auto it = streams_.find(stream_id); if (it == std::ranges::end(streams_)) { - return; - } - - if (!config.quiet) { - std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", - stream_id, app_error_code); - } - - streams_.erase(it); -} - -namespace { -int http_recv_settings(nghttp3_conn *conn, - const nghttp3_proto_settings *settings, - void *conn_user_data) { - if (!config.quiet) { - debug::print_http_settings(settings); - } - - return 0; -} -} // namespace - -namespace { -int http_recv_origin(nghttp3_conn *conn, const uint8_t *origin, - size_t originlen, void *conn_user_data) { - if (!config.quiet) { - debug::print_http_origin(origin, originlen); - } - - return 0; -} -} // namespace - -namespace { -int http_end_origin(nghttp3_conn *conn, void *conn_user_data) { - if (!config.quiet) { - debug::print_http_end_origin(); - } - - return 0; -} -} // namespace - -std::expected Client::setup_httpconn() { - if (httpconn_) { - return {}; - } - - if (ngtcp2_conn_get_streams_uni_left(conn_) < 3) { - std::println(stderr, - "peer does not allow at least 3 unidirectional streams."); - return std::unexpected{Error::QUIC}; - } - - nghttp3_callbacks callbacks{ - .recv_data = ::http_recv_data, - .deferred_consume = ::http_deferred_consume, - .begin_headers = ::http_begin_headers, - .recv_header = ::http_recv_header, - .end_headers = ::http_end_headers, - .begin_trailers = ::http_begin_trailers, - .recv_trailer = ::http_recv_trailer, - .end_trailers = ::http_end_trailers, - .stop_sending = ::http_stop_sending, - .reset_stream = ::http_reset_stream, - .recv_origin = ::http_recv_origin, - .end_origin = ::http_end_origin, - .rand = rand_bytes, - .recv_settings2 = ::http_recv_settings, - }; - nghttp3_settings settings; - nghttp3_settings_default(&settings); - settings.qpack_max_dtable_capacity = 4_k; - settings.qpack_blocked_streams = 100; - - auto mem = nghttp3_mem_default(); - - if (auto rv = - nghttp3_conn_client_new(&httpconn_, &callbacks, &settings, mem, this); - rv != 0) { - std::println(stderr, "nghttp3_conn_client_new: {}", nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - int64_t ctrl_stream_id; - - if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr); - rv != 0) { - std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_bind_control_stream: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - if (!config.quiet) { - std::println(stderr, "http: control stream={:#x}", ctrl_stream_id); + return nullptr; } - int64_t qpack_enc_stream_id, qpack_dec_stream_id; - - if (auto rv = - ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr); - rv != 0) { - std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = - ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr); - rv != 0) { - std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id, - qpack_dec_stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_bind_qpack_streams: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - if (!config.quiet) { - std::println(stderr, "http: QPACK streams encoder={:#x} decoder={:#x}", - qpack_enc_stream_id, qpack_dec_stream_id); - } - - return {}; + return (*it).second.get(); } -const std::vector &Client::get_offered_versions() const { - return offered_versions_; -} - -bool Client::get_early_data() const { return early_data_; } - namespace { std::expected run(Client &c, const char *addr, const char *port, TLSClientContext &tls_ctx) { @@ -2684,7 +2186,7 @@ int main(int argc, char **argv) { for (;;) { static int flag = 0; - constexpr static option long_opts[] = { + static constexpr option long_opts[] = { {"help", no_argument, nullptr, 'h'}, {"tx-loss", required_argument, nullptr, 't'}, {"rx-loss", required_argument, nullptr, 'r'}, @@ -2987,22 +2489,24 @@ int main(int argc, char **argv) { // --qlog-dir config.qlog_dir = optarg; break; - case 27: + case 27: { // --cc - if (strcmp("cubic", optarg) == 0) { + auto cc = std::string_view{optarg}; + if (cc == "cubic"sv) { config.cc_algo = NGTCP2_CC_ALGO_CUBIC; break; } - if (strcmp("reno", optarg) == 0) { + if (cc == "reno"sv) { config.cc_algo = NGTCP2_CC_ALGO_RENO; break; } - if (strcmp("bbr", optarg) == 0) { + if (cc == "bbr"sv) { config.cc_algo = NGTCP2_CC_ALGO_BBR; break; } std::println(stderr, "cc: specify cubic, reno, or bbr"); exit(EXIT_FAILURE); + } case 28: // --exit-on-all-streams-close config.exit_on_all_streams_close = true; @@ -3086,70 +2590,80 @@ int main(int argc, char **argv) { config.handshake_timeout = *t; } break; - case 37: { + case 37: // --available-versions if (strlen(optarg) == 0) { config.available_versions.resize(0); + break; } - auto l = util::split_str(optarg); - config.available_versions.resize(l.size()); - auto it = std::ranges::begin(config.available_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "available-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - *it++ = *rv; - } + + config.available_versions = + util::split_str(optarg) | std::ranges::views::transform([](auto &&k) { + if (k == "v1"sv) { + return NGTCP2_PROTO_VER_V1; + } + + if (k == "v2"sv) { + return NGTCP2_PROTO_VER_V2; + } + + auto rv = util::parse_version(k); + if (!rv) { + std::println(stderr, "available-versions: invalid version {}", k); + exit(EXIT_FAILURE); + } + + return *rv; + }) | + std::ranges::to(); + break; - } case 38: // --no-pmtud config.no_pmtud = true; break; - case 39: { + case 39: // --preferred-versions - auto l = util::split_str(optarg); - if (l.size() > max_preferred_versionslen) { + if (strlen(optarg) == 0) { + config.preferred_versions.resize(0); + + break; + } + + config.preferred_versions = + util::split_str(optarg) | std::ranges::views::transform([](auto &&k) { + if (k == "v1"sv) { + return NGTCP2_PROTO_VER_V1; + } + + if (k == "v2"sv) { + return NGTCP2_PROTO_VER_V2; + } + + auto rv = util::parse_version(k); + if (!rv) { + std::println(stderr, "preferred-versions: invalid version {}", k); + exit(EXIT_FAILURE); + } + + if (!ngtcp2_is_supported_version(*rv)) { + std::println(stderr, "preferred-versions: unsupported version {}", + k); + exit(EXIT_FAILURE); + } + + return *rv; + }) | + std::ranges::to(); + + if (config.preferred_versions.size() > max_preferred_versionslen) { std::println(stderr, "preferred-versions: too many versions > {}", max_preferred_versionslen); exit(EXIT_FAILURE); } - config.preferred_versions.resize(l.size()); - auto it = std::ranges::begin(config.preferred_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "preferred-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - if (!ngtcp2_is_supported_version(*rv)) { - std::println(stderr, "preferred-versions: unsupported version {}", - k); - exit(EXIT_FAILURE); - } - *it++ = *rv; - } + break; - } case 40: // --ack-thresh if (auto n = util::parse_uint(optarg); !n) { @@ -3179,25 +2693,36 @@ int main(int argc, char **argv) { config.initial_pkt_num = static_cast(*n); } break; - case 43: { + case 43: // --pmtud-probes - auto l = util::split_str(optarg); - for (auto &s : l) { - if (auto n = util::parse_uint_iec(s); !n) { - std::println(stderr, "pmtud-probes: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE || - *n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { - std::println( - stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", - NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); - exit(EXIT_FAILURE); - } else { - config.pmtud_probes.push_back(static_cast(*n)); - } + if (strlen(optarg) == 0) { + config.pmtud_probes.resize(0); + + break; } + + config.pmtud_probes = + util::split_str(optarg) | std::ranges::views::transform([](auto &&s) { + auto n = util::parse_uint_iec(s); + if (!n) { + std::println(stderr, "pmtud-probes: invalid argument"); + exit(EXIT_FAILURE); + } + + if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE || + *n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { + std::println( + stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", + NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, + NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); + exit(EXIT_FAILURE); + } + + return static_cast(*n); + }) | + std::ranges::to(); + break; - } case 44: // --ech-config-list-file config.ech_config_list_file = optarg; @@ -3252,7 +2777,7 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - if (config.wait_for_ticket && !config.session_file) { + if (config.wait_for_ticket && config.session_file.empty()) { std::println(stderr, "wait-for-ticket: session-file must be specified"); exit(EXIT_FAILURE); } @@ -3283,7 +2808,7 @@ int main(int argc, char **argv) { } } - if (config.ech_config_list_file) { + if (!config.ech_config_list_file.empty()) { auto ech_config = util::read_file(config.ech_config_list_file); if (!ech_config) { std::println(stderr, diff --git a/deps/ngtcp2/ngtcp2/examples/client.h b/deps/ngtcp2/ngtcp2/examples/client.h index 81ec0de6fa4173..f88f3e46664e02 100644 --- a/deps/ngtcp2/ngtcp2/examples/client.h +++ b/deps/ngtcp2/ngtcp2/examples/client.h @@ -38,7 +38,6 @@ #include #include -#include #include @@ -49,6 +48,14 @@ #include "shared.h" #include "template.h" +#ifdef WITH_EXAMPLE_HTTP3_PROTO_CODEC +# include "http3_client_proto_codec.h" +#endif // WITH_EXAMPLE_HTTP3_PROTO_CODEC + +#ifdef WITH_EXAMPLE_HQ_PROTO_CODEC +# include "hq_client_proto_codec.h" +#endif // WITH_EXAMPLE_HQ_PROTO_CODEC + using namespace ngtcp2; struct Stream { @@ -60,6 +67,10 @@ struct Stream { Request req; int64_t stream_id; int fd{-1}; +#ifdef WITH_EXAMPLE_HQ_PROTO_CODEC + std::string rawreqbuf; + std::span reqbuf; +#endif // WITH_EXAMPLE_HQ_PROTO_CODEC }; class Client; @@ -130,23 +141,15 @@ class Client : public ClientBase { void set_remote_addr(const ngtcp2_addr &remote_addr); - std::expected setup_httpconn(); - std::expected submit_http_request(const Stream *stream); + std::expected setup_codec(); std::expected recv_stream_data(uint32_t flags, int64_t stream_id, std::span data); std::expected acked_stream_data_offset(int64_t stream_id, uint64_t datalen); - void http_consume(int64_t stream_id, size_t nconsumed); - void http_write_data(int64_t stream_id, std::span data); std::expected on_stream_reset(int64_t stream_id); std::expected on_stream_stop_sending(int64_t stream_id); std::expected extend_max_stream_data(int64_t stream_id, uint64_t max_data); - std::expected stop_sending(int64_t stream_id, - uint64_t app_error_code); - std::expected reset_stream(int64_t stream_id, - uint64_t app_error_code); - void http_stream_close(int64_t stream_id, uint64_t app_error_code); void on_send_blocked(const ngtcp2_path &path, unsigned int ecn, std::span data, size_t gso_size); @@ -162,6 +165,8 @@ class Client : public ClientBase { bool should_exit() const; + Stream *find_stream(int64_t stream_id) const; + private: std::vector endpoints_; Address remote_addr_; @@ -174,7 +179,7 @@ class Client : public ClientBase { struct ev_loop *loop_; std::unordered_map> streams_; std::vector offered_versions_; - nghttp3_conn *httpconn_{}; + std::unique_ptr proto_codec_; // addr_ is the server host address. const char *addr_{}; // port_ is the server port. diff --git a/deps/ngtcp2/ngtcp2/examples/client_base.cc b/deps/ngtcp2/ngtcp2/examples/client_base.cc index 2a92006eb25557..0f3eb2c9553f63 100644 --- a/deps/ngtcp2/ngtcp2/examples/client_base.cc +++ b/deps/ngtcp2/ngtcp2/examples/client_base.cc @@ -26,7 +26,6 @@ #include #include -#include #include #include "debug.h" diff --git a/deps/ngtcp2/ngtcp2/examples/client_base.h b/deps/ngtcp2/ngtcp2/examples/client_base.h index 329e8ae4735304..88e296cd2b2469 100644 --- a/deps/ngtcp2/ngtcp2/examples/client_base.h +++ b/deps/ngtcp2/ngtcp2/examples/client_base.h @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -79,10 +80,10 @@ struct Config { // timeout is an idle timeout for QUIC connection. ngtcp2_duration timeout{30 * NGTCP2_SECONDS}; // session_file is a path to a file to write, and read TLS session. - const char *session_file{}; + std::filesystem::path session_file; // tp_file is a path to a file to write, and read QUIC transport // parameters. - const char *tp_file{}; + std::filesystem::path tp_file; // show_secret is true if transport secrets should be printed out. bool show_secret{}; // change_local_addr is the duration after which client changes @@ -102,7 +103,7 @@ struct Config { std::string_view http_method{"GET"sv}; // download is a path to a directory where a downloaded file is // saved. If it is empty, no file is saved. - std::string_view download; + std::filesystem::path download; // requests contains URIs to request. std::vector requests; // no_quic_dump is true if hexdump of QUIC STREAM and CRYPTO data @@ -112,10 +113,10 @@ struct Config { // disabled. bool no_http_dump{}; // qlog_file is the path to write qlog. - std::string_view qlog_file; + std::filesystem::path qlog_file; // qlog_dir is the path to directory where qlog is stored. qlog_dir // and qlog_file are mutually exclusive. - std::string_view qlog_dir; + std::filesystem::path qlog_dir; // max_data is the initial connection-level flow control window. uint64_t max_data{24_m}; // max_stream_data_bidi_local is the initial stream-level flow @@ -158,7 +159,7 @@ struct Config { ngtcp2_cc_algo cc_algo{NGTCP2_CC_ALGO_CUBIC}; // token_file is a path to file to read or write token from // NEW_TOKEN frame. - std::string_view token_file; + std::filesystem::path token_file; // sni is the value sent in TLS SNI, overriding DNS name of the // remote host. std::string_view sni; @@ -196,7 +197,7 @@ struct Config { std::vector ech_config_list; // ech_config_list_file is a path to a file to read and write // ECHConfigList. - const char *ech_config_list_file{}; + std::filesystem::path ech_config_list_file; // no_gso disables GSO. bool no_gso{}; // show_stat, if true, displays the connection statistics when the diff --git a/deps/ngtcp2/ngtcp2/examples/debug.cc b/deps/ngtcp2/ngtcp2/examples/debug.cc index 7e96a3ba9fd8c1..495f42cd3cf3d1 100644 --- a/deps/ngtcp2/ngtcp2/examples/debug.cc +++ b/deps/ngtcp2/ngtcp2/examples/debug.cc @@ -28,7 +28,6 @@ #include #include -#include #include #include "util.h" @@ -175,22 +174,10 @@ void print_hp_mask(std::span mask, util::format_hex(sample)); } -void log_printf(void *user_data, const char *fmt, ...) { - va_list ap; - std::array buf; +void log_write(void *user_data, char *msg, size_t len) { + msg[len++] = '\n'; - va_start(ap, fmt); - auto n = vsnprintf(buf.data(), buf.size(), fmt, ap); - va_end(ap); - - if (static_cast(n) >= buf.size()) { - n = buf.size() - 1; - } - - buf[static_cast(n++)] = '\n'; - - while (write(fileno(stderr), buf.data(), static_cast(n)) == -1 && - errno == EINTR) + while (write(fileno(stderr), msg, len) == -1 && errno == EINTR) ; } @@ -322,7 +309,7 @@ std::string_view secret_title(ngtcp2_encryption_level level) { void print_conn_info(ngtcp2_conn *conn) { ngtcp2_conn_info cinfo; - ngtcp2_conn_get_conn_info(conn, &cinfo); + ngtcp2_conn_get_conn_info2(conn, &cinfo); std::println( R"(# Connection Statistics (see ngtcp2_conn_info for details) diff --git a/deps/ngtcp2/ngtcp2/examples/debug.h b/deps/ngtcp2/ngtcp2/examples/debug.h index 0ccf6ac1049298..f880833f8369a0 100644 --- a/deps/ngtcp2/ngtcp2/examples/debug.h +++ b/deps/ngtcp2/ngtcp2/examples/debug.h @@ -90,7 +90,7 @@ void print_secrets(std::span secret, void print_hp_mask(std::span mask, std::span sample); -void log_printf(void *user_data, const char *fmt, ...); +void log_write(void *user_data, char *msg, size_t len); void path_validation(const ngtcp2_path *path, ngtcp2_path_validation_result res); diff --git a/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c b/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c index 56d0802b35e658..955132c3aa84fd 100644 --- a/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c +++ b/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c @@ -421,7 +421,7 @@ static int client_read(struct client *c) { if (!c->last_error.error_code) { if (rv == NGTCP2_ERR_CRYPTO) { ngtcp2_ccerr_set_tls_alert( - &c->last_error, ngtcp2_conn_get_tls_alert(c->conn), NULL, 0); + &c->last_error, ngtcp2_conn_get_tls_alert2(c->conn), NULL, 0); } else { ngtcp2_ccerr_set_liberr(&c->last_error, rv, NULL, 0); } @@ -544,7 +544,7 @@ static int client_write(struct client *c) { return -1; } - expiry = ngtcp2_conn_get_expiry(c->conn); + expiry = ngtcp2_conn_get_expiry2(c->conn); now = timestamp(); t = expiry < now ? 1e-9 : (ev_tstamp)(expiry - now) / NGTCP2_SECONDS; @@ -571,8 +571,8 @@ static void client_close(struct client *c) { ngtcp2_path_storage ps; uint8_t buf[1280]; - if (ngtcp2_conn_in_closing_period(c->conn) || - ngtcp2_conn_in_draining_period(c->conn)) { + if (ngtcp2_conn_in_closing_period2(c->conn) || + ngtcp2_conn_in_draining_period2(c->conn)) { goto fin; } diff --git a/deps/ngtcp2/ngtcp2/examples/h09client.cc b/deps/ngtcp2/ngtcp2/examples/h09client.cc deleted file mode 100644 index 7d2017d68894ab..00000000000000 --- a/deps/ngtcp2/ngtcp2/examples/h09client.cc +++ /dev/null @@ -1,2863 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2017 ngtcp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "h09client.h" -#include "network.h" -#include "debug.h" -#include "util.h" -#include "shared.h" - -using namespace ngtcp2; -using namespace std::literals; - -namespace { -auto randgen = util::make_mt19937(); -} // namespace - -namespace { -constexpr size_t max_preferred_versionslen = 4; -} // namespace - -Config config; - -Stream::Stream(const Request &req, int64_t stream_id) - : req{req}, stream_id{stream_id} { - nghttp3_buf_init(&reqbuf); -} - -Stream::~Stream() { - if (fd != -1) { - close(fd); - } -} - -std::expected Stream::open_file(std::string_view path) { - assert(fd == -1); - - std::string_view filename; - - auto it = std::ranges::find(std::rbegin(path), std::rend(path), '/').base(); - if (it == std::ranges::end(path)) { - filename = "index.html"sv; - } else { - filename = std::string_view{it, std::ranges::end(path)}; - if (filename == ".."sv || filename == "."sv) { - std::println(stderr, "Invalid file name: {}", filename); - return std::unexpected{Error::INVALID_ARGUMENT}; - } - } - - auto fname = std::string{config.download}; - fname += '/'; - fname += filename; - - fd = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (fd == -1) { - std::println(stderr, "open: Could not open file {}: {}", fname, - strerror(errno)); - return std::unexpected{Error::IO}; - } - - return {}; -} - -namespace { -void writecb(struct ev_loop *loop, ev_io *w, int revents) { - auto c = static_cast(w->data); - - c->on_write(); -} -} // namespace - -namespace { -void readcb(struct ev_loop *loop, ev_io *w, int revents) { - auto ep = static_cast(w->data); - auto c = ep->client; - - if (!c->on_read(*ep)) { - return; - } - - c->on_write(); -} -} // namespace - -namespace { -void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { - auto c = static_cast(w->data); - - if (auto rv = c->handle_expiry(); !rv) { - return; - } - - c->on_write(); -} -} // namespace - -namespace { -void change_local_addrcb(struct ev_loop *loop, ev_timer *w, int revents) { - auto c = static_cast(w->data); - - c->change_local_addr(); -} -} // namespace - -namespace { -void key_updatecb(struct ev_loop *loop, ev_timer *w, int revents) { - auto c = static_cast(w->data); - - if (!c->initiate_key_update()) { - c->disconnect(); - } -} -} // namespace - -namespace { -void delay_streamcb(struct ev_loop *loop, ev_timer *w, int revents) { - auto c = static_cast(w->data); - - ev_timer_stop(loop, w); - c->on_extend_max_streams(); - c->on_write(); -} -} // namespace - -namespace { -void siginthandler(struct ev_loop *loop, ev_signal *w, int revents) { - ev_break(loop, EVBREAK_ALL); -} -} // namespace - -Client::Client(struct ev_loop *loop, uint32_t client_chosen_version, - uint32_t original_version) - : loop_{loop}, - client_chosen_version_{client_chosen_version}, - original_version_{original_version}, - no_gso_{ -#ifdef UDP_SEGMENT - config.no_gso -#else // !defined(UDP_SEGMENT) - true -#endif // !defined(UDP_SEGMENT) - } { - ev_io_init(&wev_, writecb, 0, EV_WRITE); - wev_.data = this; - ev_timer_init(&timer_, timeoutcb, 0., 0.); - timer_.data = this; - ev_timer_init(&change_local_addr_timer_, change_local_addrcb, - static_cast(config.change_local_addr) / NGTCP2_SECONDS, - 0.); - change_local_addr_timer_.data = this; - ev_timer_init(&key_update_timer_, key_updatecb, - static_cast(config.key_update) / NGTCP2_SECONDS, 0.); - key_update_timer_.data = this; - ev_timer_init(&delay_stream_timer_, delay_streamcb, - static_cast(config.delay_stream) / NGTCP2_SECONDS, 0.); - delay_stream_timer_.data = this; - ev_signal_init(&sigintev_, siginthandler, SIGINT); -} - -Client::~Client() { disconnect(); } - -void Client::disconnect() { - tx_.send_blocked = false; - - handle_error(); - - config.tx_loss_prob = 0; - - ev_timer_stop(loop_, &delay_stream_timer_); - ev_timer_stop(loop_, &key_update_timer_); - ev_timer_stop(loop_, &change_local_addr_timer_); - ev_timer_stop(loop_, &timer_); - - ev_io_stop(loop_, &wev_); - - for (auto &ep : endpoints_) { - ev_io_stop(loop_, &ep.rev); - close(ep.fd); - } - - endpoints_.clear(); - - ev_signal_stop(loop_, &sigintev_); -} - -namespace { -int recv_crypto_data(ngtcp2_conn *conn, - ngtcp2_encryption_level encryption_level, uint64_t offset, - const uint8_t *data, size_t datalen, void *user_data) { - if (!config.quiet && !config.no_quic_dump) { - debug::print_crypto_data(encryption_level, {data, datalen}); - } - - return ngtcp2_crypto_recv_crypto_data_cb(conn, encryption_level, offset, data, - datalen, user_data); -} -} // namespace - -namespace { -int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, - uint64_t offset, const uint8_t *data, size_t datalen, - void *user_data, void *stream_user_data) { - if (!config.quiet && !config.no_quic_dump) { - debug::print_stream_data(stream_id, {data, datalen}); - } - - auto c = static_cast(user_data); - - c->recv_stream_data(flags, stream_id, {data, datalen}); - - return 0; -} -} // namespace - -namespace { -int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id, - uint64_t offset, uint64_t datalen, void *user_data, - void *stream_user_data) { - auto c = static_cast(user_data); - - c->acked_stream_data_offset(stream_id, offset, datalen); - - return 0; -} -} // namespace - -namespace { -int handshake_completed(ngtcp2_conn *conn, void *user_data) { - auto c = static_cast(user_data); - - if (!config.quiet) { - debug::handshake_completed(conn, user_data); - } - - if (!c->handshake_completed()) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} -} // namespace - -std::expected Client::handshake_completed() { - if (early_data_ && !tls_session_.get_early_data_accepted()) { - if (!config.quiet) { - std::println(stderr, "Early data was rejected by server"); - } - - // Some TLS backends only report early data rejection after - // handshake completion (e.g., OpenSSL). For TLS backends which - // report it early (e.g., BoringSSL and PicoTLS), the following - // functions are noop. - if (auto rv = ngtcp2_conn_tls_early_data_rejected(conn_); rv != 0) { - std::println(stderr, "ngtcp2_conn_tls_early_data_rejected: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - } - - if (!config.quiet) { - std::println(stderr, "Negotiated cipher suite is {}", - tls_session_.get_cipher_name()); - if (auto group = tls_session_.get_negotiated_group(); !group.empty()) { - std::println(stderr, "Negotiated group is {}", group); - } - std::println(stderr, "Negotiated ALPN is {}", - tls_session_.get_selected_alpn()); - - if (!config.ech_config_list.empty() && tls_session_.get_ech_accepted()) { - std::println(stderr, "ECH was accepted"); - } - } - - if (config.tp_file) { - std::array data; - auto datalen = - ngtcp2_conn_encode_0rtt_transport_params(conn_, data.data(), data.size()); - if (datalen < 0) { - std::println(stderr, "Could not encode 0-RTT transport parameters: {}", - ngtcp2_strerror(static_cast(datalen))); - } else if (!util::write_transport_params( - config.tp_file, {data.data(), static_cast(datalen)})) { - std::println(stderr, "Could not write transport parameters to {}", - config.tp_file); - } - } - - return {}; -} - -namespace { -int handshake_confirmed(ngtcp2_conn *conn, void *user_data) { - auto c = static_cast(user_data); - - if (!config.quiet) { - debug::handshake_confirmed(conn, user_data); - } - - c->handshake_confirmed(); - - return 0; -} -} // namespace - -bool Client::should_exit() const { - return handshake_confirmed_ && - (!config.wait_for_ticket || ticket_received_) && - ((config.exit_on_first_stream_close && - (config.nstreams == 0 || nstreams_closed_)) || - (config.exit_on_all_streams_close && - config.nstreams == nstreams_done_ && - nstreams_closed_ == nstreams_done_)); -} - -void Client::handshake_confirmed() { - handshake_confirmed_ = true; - - if (config.change_local_addr) { - start_change_local_addr_timer(); - } - if (config.key_update) { - start_key_update_timer(); - } - if (config.delay_stream) { - start_delay_stream_timer(); - } -} - -namespace { -int recv_version_negotiation(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, - const uint32_t *sv, size_t nsv, void *user_data) { - auto c = static_cast(user_data); - - c->recv_version_negotiation(sv, nsv); - - return 0; -} -} // namespace - -void Client::recv_version_negotiation(const uint32_t *sv, size_t nsv) { - offered_versions_.resize(nsv); - std::ranges::copy_n(sv, as_signed(nsv), - std::ranges::begin(offered_versions_)); -} - -namespace { -int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, - uint64_t app_error_code, void *user_data, - void *stream_user_data) { - auto c = static_cast(user_data); - - c->on_stream_close(stream_id, app_error_code); - - return 0; -} -} // namespace - -namespace { -int extend_max_local_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams, - void *user_data) { - auto c = static_cast(user_data); - - c->on_extend_max_streams(); - - return 0; -} -} // namespace - -namespace { -void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { - if (!util::generate_secure_random({dest, destlen})) { - assert(0); - abort(); - } -} -} // namespace - -namespace { -int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, - ngtcp2_stateless_reset_token *token, size_t cidlen, - void *user_data) { - if (!util::generate_secure_random({cid->data, cidlen})) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - cid->datalen = cidlen; - if (ngtcp2_crypto_generate_stateless_reset_token( - token->data, config.static_secret.data(), config.static_secret.size(), - cid) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} -} // namespace - -namespace { -int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { - if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - if (!config.quiet && config.show_secret) { - debug::print_hp_mask({dest, NGTCP2_HP_MASKLEN}, - {sample, NGTCP2_HP_SAMPLELEN}); - } - - return 0; -} -} // namespace - -namespace { -int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen, - void *user_data) { - auto c = static_cast(user_data); - - if (auto rv = - c->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, - tx_iv, current_rx_secret, current_tx_secret, secretlen); - !rv) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} -} // namespace - -namespace { -int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path, - const ngtcp2_path *old_path, - ngtcp2_path_validation_result res, void *user_data) { - if (!config.quiet) { - debug::path_validation(path, res); - } - - if (flags & NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR) { - auto c = static_cast(user_data); - - c->set_remote_addr(path->remote); - } - - return 0; -} -} // namespace - -void Client::set_remote_addr(const ngtcp2_addr &remote_addr) { - remote_addr_.set(remote_addr.addr); -} - -namespace { -int select_preferred_address(ngtcp2_conn *conn, ngtcp2_path *dest, - const ngtcp2_preferred_addr *paddr, - void *user_data) { - auto c = static_cast(user_data); - Address remote_addr; - - if (config.no_preferred_addr) { - return 0; - } - - if (auto rv = c->select_preferred_address(remote_addr, paddr); !rv) { - return 0; - } - - auto ep = c->endpoint_for(remote_addr); - if (!ep) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - ngtcp2_addr_copy_byte(&dest->local, (*ep)->addr.as_sockaddr(), - (*ep)->addr.size()); - ngtcp2_addr_copy_byte(&dest->remote, remote_addr.as_sockaddr(), - remote_addr.size()); - dest->user_data = *ep; - - return 0; -} -} // namespace - -namespace { -int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, - uint64_t max_data, void *user_data, - void *stream_user_data) { - auto c = static_cast(user_data); - - c->extend_max_stream_data(stream_id, max_data); - - return 0; -} -} // namespace - -void Client::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - - if (nghttp3_buf_len(&stream->reqbuf)) { - sendq_.emplace(stream.get()); - } -} - -namespace { -int recv_new_token(ngtcp2_conn *conn, const uint8_t *token, size_t tokenlen, - void *user_data) { - if (config.token_file.empty()) { - return 0; - } - - util::write_token(config.token_file, {token, tokenlen}); - - return 0; -} -} // namespace - -namespace { -int early_data_rejected(ngtcp2_conn *conn, void *user_data) { - auto c = static_cast(user_data); - - c->early_data_rejected(); - - return 0; -} -} // namespace - -void Client::early_data_rejected() { - nstreams_done_ = 0; - streams_.clear(); -} - -std::expected Client::init(int fd, const Address &local_addr, - const Address &remote_addr, - const char *addr, const char *port, - TLSClientContext &tls_ctx) { - endpoints_.reserve(4); - - endpoints_.emplace_back(); - auto &ep = endpoints_.back(); - ep.addr = local_addr; - ep.client = this; - ep.fd = fd; - ev_io_init(&ep.rev, readcb, fd, EV_READ); - ep.rev.data = &ep; - - remote_addr_ = remote_addr; - addr_ = addr; - port_ = port; - - auto callbacks = ngtcp2_callbacks{ - .client_initial = ngtcp2_crypto_client_initial_cb, - .recv_crypto_data = ::recv_crypto_data, - .handshake_completed = ::handshake_completed, - .recv_version_negotiation = ::recv_version_negotiation, - .encrypt = ngtcp2_crypto_encrypt_cb, - .decrypt = ngtcp2_crypto_decrypt_cb, - .hp_mask = do_hp_mask, - .recv_stream_data = ::recv_stream_data, - .acked_stream_data_offset = ::acked_stream_data_offset, - .stream_close = stream_close, - .recv_retry = ngtcp2_crypto_recv_retry_cb, - .extend_max_local_streams_bidi = extend_max_local_streams_bidi, - .rand = rand, - .update_key = ::update_key, - .path_validation = path_validation, - .select_preferred_addr = ::select_preferred_address, - .extend_max_stream_data = ::extend_max_stream_data, - .handshake_confirmed = ::handshake_confirmed, - .recv_new_token = ::recv_new_token, - .delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb, - .delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb, - .version_negotiation = ngtcp2_crypto_version_negotiation_cb, - .tls_early_data_rejected = ::early_data_rejected, - .get_new_connection_id2 = get_new_connection_id, - .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, - }; - - ngtcp2_cid scid, dcid; - scid.datalen = 17; - if (auto rv = util::generate_secure_random({scid.data, scid.datalen}); !rv) { - std::println(stderr, "Could not generate source connection ID"); - return rv; - } - if (config.dcid.datalen == 0) { - dcid.datalen = 18; - if (auto rv = util::generate_secure_random({dcid.data, dcid.datalen}); - !rv) { - std::println(stderr, "Could not generate destination connection ID"); - return rv; - } - } else { - dcid = config.dcid; - } - - ngtcp2_settings settings; - ngtcp2_settings_default(&settings); - settings.log_printf = config.quiet ? nullptr : debug::log_printf; - if (!config.qlog_file.empty() || !config.qlog_dir.empty()) { - std::string path; - if (!config.qlog_file.empty()) { - path = config.qlog_file; - } else { - path = std::string{config.qlog_dir}; - path += '/'; - path += util::format_hex(scid.data, as_signed(scid.datalen)); - path += ".sqlog"; - } - qlog_ = fopen(path.c_str(), "w"); - if (qlog_ == nullptr) { - std::println(stderr, "Could not open qlog file {}: {}", path, - strerror(errno)); - return std::unexpected{Error::IO}; - } - settings.qlog_write = qlog_write_cb; - } - - settings.cc_algo = config.cc_algo; - settings.initial_ts = util::timestamp(); - settings.initial_rtt = config.initial_rtt; - settings.max_window = config.max_window; - settings.max_stream_window = config.max_stream_window; - if (config.max_udp_payload_size) { - settings.max_tx_udp_payload_size = config.max_udp_payload_size; - settings.no_tx_udp_payload_size_shaping = 1; - } - settings.handshake_timeout = config.handshake_timeout; - settings.no_pmtud = config.no_pmtud; - settings.ack_thresh = config.ack_thresh; - if (config.initial_pkt_num == UINT32_MAX) { - auto dis = std::uniform_int_distribution(0, INT32_MAX); - settings.initial_pkt_num = dis(randgen); - } else { - settings.initial_pkt_num = config.initial_pkt_num; - } - - std::vector token; - - if (!config.token_file.empty()) { - std::println(stderr, "Reading token file {}", config.token_file); - - auto t = util::read_token(config.token_file); - if (t) { - token = std::move(*t); - settings.token = token.data(); - settings.tokenlen = token.size(); - } - } - - if (!config.available_versions.empty()) { - settings.available_versions = config.available_versions.data(); - settings.available_versionslen = config.available_versions.size(); - } - - if (!config.preferred_versions.empty()) { - settings.preferred_versions = config.preferred_versions.data(); - settings.preferred_versionslen = config.preferred_versions.size(); - } - - settings.original_version = original_version_; - - if (!config.pmtud_probes.empty()) { - settings.pmtud_probes = config.pmtud_probes.data(); - settings.pmtud_probeslen = config.pmtud_probes.size(); - - if (!config.max_udp_payload_size) { - settings.max_tx_udp_payload_size = - *std::ranges::max_element(config.pmtud_probes); - } - } - - ngtcp2_transport_params params; - ngtcp2_transport_params_default(¶ms); - params.initial_max_stream_data_bidi_local = config.max_stream_data_bidi_local; - params.initial_max_stream_data_bidi_remote = - config.max_stream_data_bidi_remote; - params.initial_max_stream_data_uni = config.max_stream_data_uni; - params.initial_max_data = config.max_data; - params.initial_max_streams_bidi = config.max_streams_bidi; - params.initial_max_streams_uni = 0; - params.max_idle_timeout = config.timeout; - params.active_connection_id_limit = 7; - params.grease_quic_bit = 1; - - auto path = ngtcp2_path{ - .local = as_ngtcp2_addr(ep.addr), - .remote = as_ngtcp2_addr(remote_addr), - .user_data = &ep, - }; - auto rv = - ngtcp2_conn_client_new(&conn_, &dcid, &scid, &path, client_chosen_version_, - &callbacks, &settings, ¶ms, nullptr, this); - - if (rv != 0) { - std::println(stderr, "ngtcp2_conn_client_new: {}", ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = tls_session_.init(early_data_, tls_ctx, addr_, this, - client_chosen_version_, AppProtocol::HQ); - !rv) { - return rv; - } - - ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle()); - - if (early_data_ && config.tp_file) { - auto params = util::read_transport_params(config.tp_file); - if (!params) { - early_data_ = false; - } else { - auto rv = ngtcp2_conn_decode_and_set_0rtt_transport_params( - conn_, params->data(), params->size()); - if (rv != 0) { - std::println(stderr, - "ngtcp2_conn_decode_and_set_0rtt_transport_params: {}", - ngtcp2_strerror(rv)); - early_data_ = false; - } else { - make_stream_early(); - } - } - } - - ev_io_start(loop_, &ep.rev); - - ev_signal_start(loop_, &sigintev_); - - return {}; -} - -std::expected -Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, - const ngtcp2_pkt_info *pi, std::span data) { - auto path = ngtcp2_path{ - .local = as_ngtcp2_addr(ep.addr), - .remote{ - .addr = const_cast(sa), - .addrlen = salen, - }, - .user_data = const_cast(&ep), - }; - if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(), - util::timestamp()); - rv != 0) { - std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); - if (!last_error_.error_code) { - if (rv == NGTCP2_ERR_CRYPTO) { - auto alert = ngtcp2_conn_get_tls_alert(conn_); - ngtcp2_ccerr_set_tls_alert(&last_error_, alert, nullptr, 0); - - if (alert == TLS_ALERT_ECH_REQUIRED && config.ech_config_list_file && - !tls_session_.write_ech_config_list(config.ech_config_list_file)) { - std::println(stderr, "Could not write ECH retry configs in {}", - config.ech_config_list_file); - } - } else { - ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); - } - } - disconnect(); - return std::unexpected{Error::QUIC}; - } - return {}; -} - -std::expected Client::on_read(const Endpoint &ep) { - std::array buf; - sockaddr_storage ss; - size_t pktcnt = 0; - ngtcp2_pkt_info pi; - - iovec msg_iov{ - .iov_base = buf.data(), - .iov_len = buf.size(), - }; - - uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(int))]; - - msghdr msg{ - .msg_name = &ss, - .msg_iov = &msg_iov, - .msg_iovlen = 1, - .msg_control = msg_ctrl, - }; - - auto start = util::timestamp(); - - for (; pktcnt < MAX_RECV_PKTS;) { - if (util::recv_pkt_time_threshold_exceeded( - config.cc_algo == NGTCP2_CC_ALGO_BBR, start, pktcnt)) { - break; - } - - msg.msg_namelen = sizeof(ss); - msg.msg_controllen = sizeof(msg_ctrl); - - auto nread = recvmsg(ep.fd, &msg, 0); - - if (nread == -1) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - std::println(stderr, "recvmsg: {}", strerror(errno)); - } - break; - } - - // Packets less than 21 bytes never be a valid QUIC packet. - if (nread < 21) { - ++pktcnt; - - continue; - } - - pi.ecn = msghdr_get_ecn(&msg, ss.ss_family); - auto gso_size = msghdr_get_udp_gro(&msg); - if (gso_size == 0) { - gso_size = static_cast(nread); - } - - auto data = std::span{buf.data(), static_cast(nread)}; - - for (;;) { - auto datalen = std::min(data.size(), gso_size); - - ++pktcnt; - - if (!config.quiet) { - std::println(stderr, - "Received packet: local={} remote={} ecn={:#x} {} bytes", - util::straddr(ep.addr), - util::straddr(reinterpret_cast(&ss), - msg.msg_namelen), - pi.ecn, datalen); - } - - // Packets less than 21 bytes never be a valid QUIC packet. - if (datalen < 21) { - break; - } - - if (debug::packet_lost(config.rx_loss_prob)) { - if (!config.quiet) { - std::println(stderr, "** Simulated incoming packet loss **"); - } - } else if (auto rv = - feed_data(ep, reinterpret_cast(&ss), - msg.msg_namelen, &pi, {data.data(), datalen}); - !rv) { - return rv; - } - - data = data.subspan(datalen); - - if (data.empty()) { - break; - } - } - } - - if (should_exit()) { - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(0), nullptr, 0); - disconnect(); - return std::unexpected{Error::INTERNAL}; - } - - update_timer(); - - return {}; -} - -std::expected Client::handle_expiry() { - auto now = util::timestamp(); - if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) { - std::println(stderr, "ngtcp2_conn_handle_expiry: {}", ngtcp2_strerror(rv)); - ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); - disconnect(); - return std::unexpected{Error::QUIC}; - } - - return {}; -} - -std::expected Client::on_write() { - if (tx_.send_blocked) { - send_blocked_packet(); - - if (tx_.send_blocked) { - return {}; - } - } - - ev_io_stop(loop_, &wev_); - - if (auto rv = write_streams(); !rv) { - return rv; - } - - if (should_exit()) { - disconnect(); - return std::unexpected{Error::INTERNAL}; - } - - update_timer(); - return {}; -} - -namespace { -ngtcp2_ssize write_pkt(ngtcp2_conn *conn, ngtcp2_path *path, - ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - ngtcp2_tstamp ts, void *user_data) { - auto c = static_cast(user_data); - - return c->write_pkt(path, pi, dest, destlen, ts); -} -} // namespace - -ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, - uint8_t *dest, size_t destlen, - ngtcp2_tstamp ts) { - ngtcp2_vec vec; - - for (;;) { - int64_t stream_id = -1; - size_t vcnt = 0; - uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE; - Stream *stream = nullptr; - - if (!sendq_.empty() && ngtcp2_conn_get_max_data_left(conn_)) { - stream = *std::ranges::begin(sendq_); - - stream_id = stream->stream_id; - vec.base = stream->reqbuf.pos; - vec.len = nghttp3_buf_len(&stream->reqbuf); - vcnt = 1; - flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; - } - - ngtcp2_ssize ndatalen; - - auto nwrite = - ngtcp2_conn_writev_stream(conn_, path, pi, dest, destlen, &ndatalen, - flags, stream_id, &vec, vcnt, ts); - if (nwrite < 0) { - switch (nwrite) { - case NGTCP2_ERR_STREAM_DATA_BLOCKED: - case NGTCP2_ERR_STREAM_SHUT_WR: - assert(ndatalen == -1); - sendq_.erase(std::ranges::begin(sendq_)); - continue; - case NGTCP2_ERR_WRITE_MORE: - assert(ndatalen >= 0); - stream->reqbuf.pos += ndatalen; - if (nghttp3_buf_len(&stream->reqbuf) == 0) { - sendq_.erase(std::ranges::begin(sendq_)); - } - continue; - } - - assert(ndatalen == -1); - - std::println(stderr, "ngtcp2_conn_writev_stream: {}", - ngtcp2_strerror(static_cast(nwrite))); - ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, - 0); - - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - if (ndatalen >= 0) { - stream->reqbuf.pos += ndatalen; - if (nghttp3_buf_len(&stream->reqbuf) == 0) { - sendq_.erase(std::ranges::begin(sendq_)); - } - } - - return nwrite; - } -} - -std::expected Client::write_streams() { - ngtcp2_path_storage ps; - ngtcp2_pkt_info pi; - size_t gso_size; - auto ts = util::timestamp(); - auto txbuf = std::span{txbuf_}; - auto buflen = util::clamp_buffer_size(conn_, txbuf.size(), config.gso_burst); - - ngtcp2_path_storage_zero(&ps); - - auto nwrite = ngtcp2_conn_write_aggregate_pkt2( - conn_, &ps.path, &pi, txbuf.data(), buflen, &gso_size, ::write_pkt, - config.gso_burst, ts); - if (nwrite < 0) { - disconnect(); - return std::unexpected{Error::QUIC}; - } - - ngtcp2_conn_update_pkt_tx_time(conn_, ts); - - if (nwrite == 0) { - return {}; - } - - send_packet_or_blocked(ps.path, pi.ecn, - txbuf.first(static_cast(nwrite)), gso_size); - - return {}; -} - -std::expected -Client::send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size) { - auto &ep = *static_cast(path.user_data); - - auto rest = send_packet(ep, path.remote, ecn, data, gso_size); - if (!rest.empty()) { - on_send_blocked(path, ecn, rest, gso_size); - - return std::unexpected{Error::SEND_BLOCKED}; - } - - return {}; -} - -void Client::update_timer() { - auto expiry = ngtcp2_conn_get_expiry(conn_); - auto now = util::timestamp(); - - if (expiry <= now) { - if (!config.quiet) { - auto t = static_cast(now - expiry) / NGTCP2_SECONDS; - std::println(stderr, "Timer has already expired: {:.9f}s", t); - } - - ev_feed_event(loop_, &timer_, EV_TIMER); - - return; - } - - auto t = static_cast(expiry - now) / NGTCP2_SECONDS; - if (!config.quiet) { - std::println(stderr, "Set timer={:.9f}s", t); - } - timer_.repeat = t; - ev_timer_again(loop_, &timer_); -} - -#ifdef HAVE_LINUX_RTNETLINK_H -namespace { -std::expected bind_addr(Address &local_addr, int fd, - const InAddr &ia, int family) { - addrinfo hints{ - .ai_flags = AI_PASSIVE, - .ai_family = family, - .ai_socktype = SOCK_DGRAM, - }; - addrinfo *res, *rp; - char *node; - std::array nodebuf; - - if (in_addr_empty(ia)) { - node = nullptr; - } else { - if (inet_ntop(family, in_addr_get_ptr(ia), nodebuf.data(), - nodebuf.size()) == nullptr) { - std::println(stderr, "inet_ntop: {}", strerror(errno)); - return std::unexpected{Error::LIBC}; - } - - node = nodebuf.data(); - } - - if (auto rv = getaddrinfo(node, "0", &hints, &res); rv != 0) { - std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - auto res_d = defer([res] { freeaddrinfo(res); }); - - for (rp = res; rp; rp = rp->ai_next) { - if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1) { - break; - } - } - - if (!rp) { - std::println(stderr, "Could not bind"); - return std::unexpected{Error::SYSCALL}; - } - - sockaddr_storage ss; - socklen_t len = sizeof(ss); - if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::println(stderr, "getsockname: {}", strerror(errno)); - return std::unexpected{Error::SYSCALL}; - } - - local_addr.set(reinterpret_cast(&ss)); - - return {}; -} -} // namespace -#endif // defined(HAVE_LINUX_RTNETLINK_H) - -#ifndef HAVE_LINUX_RTNETLINK_H -namespace { -std::expected connect_sock(Address &local_addr, int fd, - const Address &remote_addr) { - if (connect(fd, remote_addr.as_sockaddr(), remote_addr.size()) != 0) { - std::println(stderr, "connect: {}", strerror(errno)); - return std::unexpected{Error::SYSCALL}; - } - - sockaddr_storage ss; - socklen_t len = sizeof(ss); - if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::println(stderr, "getsockname: {}", strerror(errno)); - return std::unexpected{Error::SYSCALL}; - } - - local_addr.set(reinterpret_cast(&ss)); - - return {}; -} -} // namespace -#endif // !defined(HAVE_LINUX_RTNETLINK_H) - -namespace { -std::expected udp_sock(int family) { - auto maybe_fd = util::create_nonblock_socket(family, SOCK_DGRAM, IPPROTO_UDP); - if (!maybe_fd) { - return maybe_fd; - } - - auto fd = *maybe_fd; - - fd_set_recv_ecn(fd, family); - fd_set_ip_mtu_discover(fd, family); - fd_set_ip_dontfrag(fd, family); - fd_set_udp_gro(fd); - - return fd; -} -} // namespace - -namespace { -std::expected create_sock(Address &remote_addr, const char *addr, - const char *port) { - addrinfo hints{ - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_DGRAM, - }; - addrinfo *res, *rp; - - if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) { - std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - auto res_d = defer([res] { freeaddrinfo(res); }); - - int fd = -1; - - for (rp = res; rp; rp = rp->ai_next) { - auto maybe_fd = udp_sock(rp->ai_family); - if (!maybe_fd) { - continue; - } - - fd = *maybe_fd; - - break; - } - - if (!rp) { - std::println(stderr, "Could not create socket"); - return std::unexpected{Error::SYSCALL}; - } - - remote_addr.set(rp->ai_addr); - - return fd; -} -} // namespace - -std::expected -Client::endpoint_for(const Address &remote_addr) { -#ifdef HAVE_LINUX_RTNETLINK_H - auto maybe_ia = get_local_addr(remote_addr); - if (!maybe_ia) { - std::println( - stderr, "Could not get local address for a selected preferred address"); - return std::unexpected{maybe_ia.error()}; - } - - const auto &ia = *maybe_ia; - - auto current_path = ngtcp2_conn_get_path(conn_); - auto current_ep = static_cast(current_path->user_data); - if (addreq(current_ep->addr, ia)) { - return current_ep; - } -#endif // defined(HAVE_LINUX_RTNETLINK_H) - - auto family = remote_addr.family(); - - auto maybe_fd = udp_sock(family); - if (!maybe_fd) { - return std::unexpected{maybe_fd.error()}; - } - - auto fd = *maybe_fd; - - Address local_addr; - -#ifdef HAVE_LINUX_RTNETLINK_H - if (auto rv = bind_addr(local_addr, fd, ia, family); !rv) { - close(fd); - return std::unexpected{rv.error()}; - } -#else // !defined(HAVE_LINUX_RTNETLINK_H) - if (auto rv = connect_sock(local_addr, fd, remote_addr); !rv) { - close(fd); - return std::unexpected{rv.error()}; - } -#endif // !defined(HAVE_LINUX_RTNETLINK_H) - - endpoints_.emplace_back(); - auto &ep = endpoints_.back(); - ep.addr = local_addr; - ep.client = this; - ep.fd = fd; - ev_io_init(&ep.rev, readcb, fd, EV_READ); - ep.rev.data = &ep; - - ev_io_start(loop_, &ep.rev); - - return &ep; -} - -void Client::start_change_local_addr_timer() { - ev_timer_start(loop_, &change_local_addr_timer_); -} - -std::expected Client::change_local_addr() { - Address local_addr; - - if (!config.quiet) { - std::println(stderr, "Changing local address"); - } - - auto family = remote_addr_.family(); - - auto maybe_nfd = udp_sock(family); - if (!maybe_nfd) { - return std::unexpected{maybe_nfd.error()}; - } - - auto nfd = *maybe_nfd; - -#ifdef HAVE_LINUX_RTNETLINK_H - auto maybe_ia = get_local_addr(remote_addr_); - if (!maybe_ia) { - std::println(stderr, "Could not get local address"); - close(nfd); - return std::unexpected{maybe_ia.error()}; - } - - if (auto rv = bind_addr(local_addr, nfd, *maybe_ia, family); !rv) { - close(nfd); - return rv; - } -#else // !defined(HAVE_LINUX_RTNETLINK_H) - if (auto rv = connect_sock(local_addr, nfd, remote_addr_); !rv) { - close(nfd); - return rv; - } -#endif // !defined(HAVE_LINUX_RTNETLINK_H) - - if (!config.quiet) { - std::println(stderr, "Local address is now {}", util::straddr(local_addr)); - } - - endpoints_.emplace_back(); - auto &ep = endpoints_.back(); - ep.addr = local_addr; - ep.client = this; - ep.fd = nfd; - ev_io_init(&ep.rev, readcb, nfd, EV_READ); - ep.rev.data = &ep; - - auto addr = as_ngtcp2_addr(local_addr); - - if (config.nat_rebinding) { - ngtcp2_conn_set_local_addr(conn_, &addr); - ngtcp2_conn_set_path_user_data(conn_, &ep); - } else { - auto path = ngtcp2_path{ - .local = addr, - .remote = as_ngtcp2_addr(remote_addr_), - .user_data = &ep, - }; - if (auto rv = ngtcp2_conn_initiate_immediate_migration(conn_, &path, - util::timestamp()); - rv != 0) { - std::println(stderr, "ngtcp2_conn_initiate_immediate_migration: {}", - ngtcp2_strerror(rv)); - } - } - - ev_io_start(loop_, &ep.rev); - - return {}; -} - -void Client::start_key_update_timer() { - ev_timer_start(loop_, &key_update_timer_); -} - -std::expected -Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen) { - if (!config.quiet) { - std::println(stderr, "Updating traffic key"); - } - - auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); - auto aead = &crypto_ctx->aead; - auto keylen = ngtcp2_crypto_aead_keylen(aead); - auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); - - ++nkey_update_; - - std::array rx_key, tx_key; - - if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_aead_ctx, - rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), - tx_iv, current_rx_secret, current_tx_secret, - secretlen) != 0) { - return std::unexpected{Error::QUIC}; - } - - if (!config.quiet && config.show_secret) { - std::println(stderr, "application_traffic rx secret {}", nkey_update_); - debug::print_secrets({rx_secret, secretlen}, {rx_key.data(), keylen}, - {rx_iv, ivlen}); - std::println(stderr, "application_traffic tx secret {}", nkey_update_); - debug::print_secrets({tx_secret, secretlen}, {tx_key.data(), keylen}, - {tx_iv, ivlen}); - } - - return {}; -} - -std::expected Client::initiate_key_update() { - if (!config.quiet) { - std::println(stderr, "Initiate key update"); - } - - if (auto rv = ngtcp2_conn_initiate_key_update(conn_, util::timestamp()); - rv != 0) { - std::println(stderr, "ngtcp2_conn_initiate_key_update: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - return {}; -} - -void Client::start_delay_stream_timer() { - ev_timer_start(loop_, &delay_stream_timer_); -} - -std::expected Client::send_packet(const Endpoint &ep, - const ngtcp2_addr &remote_addr, - unsigned int ecn, - std::span data) { - auto rest = send_packet(ep, remote_addr, ecn, data, data.size()); - if (!rest.empty()) { - return std::unexpected{Error::SEND_BLOCKED}; - } - - return {}; -} - -std::span Client::send_packet(const Endpoint &ep, - const ngtcp2_addr &remote_addr, - unsigned int ecn, - std::span data, - size_t gso_size) { - assert(gso_size); - - if (debug::packet_lost(config.tx_loss_prob)) { - if (!config.quiet) { - std::println(stderr, "** Simulated outgoing packet loss **"); - } - return {}; - } - - if (no_gso_ && data.size() > gso_size) { - for (; !data.empty();) { - auto len = std::min(gso_size, data.size()); - - auto rest = send_packet(ep, remote_addr, ecn, data.first(len), len); - if (!rest.empty()) { - assert(rest.size() == len); - - return data; - } - - data = data.subspan(len); - } - - return {}; - } - - iovec msg_iov{ - .iov_base = const_cast(data.data()), - .iov_len = data.size(), - }; - - uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(uint16_t))]{}; - - msghdr msg{ -#ifdef HAVE_LINUX_RTNETLINK_H - .msg_name = const_cast(remote_addr.addr), - .msg_namelen = remote_addr.addrlen, -#endif // defined(HAVE_LINUX_RTNETLINK_H) - .msg_iov = &msg_iov, - .msg_iovlen = 1, - .msg_control = msg_ctrl, - .msg_controllen = sizeof(msg_ctrl), - }; - - size_t controllen = 0; - - auto cm = CMSG_FIRSTHDR(&msg); - controllen += CMSG_SPACE(sizeof(int)); - cm->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cm), &ecn, sizeof(ecn)); - - switch (remote_addr.addr->sa_family) { - case AF_INET: - cm->cmsg_level = IPPROTO_IP; - cm->cmsg_type = IP_TOS; - - break; - case AF_INET6: - cm->cmsg_level = IPPROTO_IPV6; - cm->cmsg_type = IPV6_TCLASS; - - break; - default: - assert(0); - } - -#ifdef UDP_SEGMENT - if (data.size() > gso_size) { - controllen += CMSG_SPACE(sizeof(uint16_t)); - cm = CMSG_NXTHDR(&msg, cm); - cm->cmsg_level = SOL_UDP; - cm->cmsg_type = UDP_SEGMENT; - cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); - auto n = static_cast(gso_size); - memcpy(CMSG_DATA(cm), &n, sizeof(n)); - } -#endif // defined(UDP_SEGMENT) - - msg.msg_controllen = -#ifndef __APPLE__ - controllen -#else // defined(__APPLE__) - static_cast(controllen) -#endif // defined(__APPLE__) - ; - - ssize_t nwrite = 0; - - do { - nwrite = sendmsg(ep.fd, &msg, 0); - } while (nwrite == -1 && errno == EINTR); - - if (nwrite == -1) { - switch (errno) { - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif // EAGAIN != EWOULDBLOCK - return data; -#ifdef UDP_SEGMENT - case EIO: - if (data.size() > gso_size) { - // GSO failure; send each packet in a separate sendmsg call. - std::println(stderr, "sendmsg: disabling GSO due to {}", - strerror(errno)); - - no_gso_ = true; - - return send_packet(ep, remote_addr, ecn, data, gso_size); - } - break; -#endif // defined(UDP_SEGMENT) - } - - std::println(stderr, "sendmsg: {}", strerror(errno)); - - // TODO We have packet which is expected to fail to send (e.g., - // path validation to old path). - return {}; - } - - assert(static_cast(nwrite) == data.size()); - - if (!config.quiet) { - std::println(stderr, "Sent packet: local={} remote={} ecn={:#x} {} bytes", - util::straddr(ep.addr), - util::straddr(remote_addr.addr, remote_addr.addrlen), ecn, - nwrite); - } - - return {}; -} - -void Client::on_send_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size) { - assert(!tx_.send_blocked); - assert(gso_size); - - tx_.send_blocked = true; - - auto &p = tx_.blocked; - - p.remote_addr.set(path.remote.addr); - - auto &ep = *static_cast(path.user_data); - - p.endpoint = &ep; - p.ecn = ecn; - p.data = data; - p.gso_size = gso_size; - - start_wev_endpoint(ep); -} - -void Client::start_wev_endpoint(const Endpoint &ep) { - // We do not close ep.fd, so we can expect that each Endpoint has - // unique fd. - if (ep.fd != wev_.fd) { - if (ev_is_active(&wev_)) { - ev_io_stop(loop_, &wev_); - } - - ev_io_set(&wev_, ep.fd, EV_WRITE); - } - - ev_io_start(loop_, &wev_); -} - -void Client::send_blocked_packet() { - assert(tx_.send_blocked); - - auto &p = tx_.blocked; - - auto rest = send_packet(*p.endpoint, as_ngtcp2_addr(p.remote_addr), p.ecn, - p.data, p.gso_size); - if (!rest.empty()) { - p.data = rest; - - start_wev_endpoint(*p.endpoint); - - return; - } - - tx_.send_blocked = false; -} - -std::expected Client::handle_error() { - if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || - ngtcp2_conn_in_draining_period(conn_)) { - return {}; - } - - std::array buf; - - ngtcp2_path_storage ps; - - ngtcp2_path_storage_zero(&ps); - - ngtcp2_pkt_info pi; - - auto nwrite = ngtcp2_conn_write_connection_close( - conn_, &ps.path, &pi, buf.data(), buf.size(), &last_error_, - util::timestamp()); - if (nwrite < 0) { - std::println(stderr, "ngtcp2_conn_write_connection_close: {}", - ngtcp2_strerror(static_cast(nwrite))); - return std::unexpected{Error::QUIC}; - } - - if (nwrite == 0) { - return {}; - } - - return send_packet(*static_cast(ps.path.user_data), - ps.path.remote, pi.ecn, - {buf.data(), static_cast(nwrite)}); -} - -void Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) { - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - - sendq_.erase(stream.get()); - - ++nstreams_closed_; - - if (!ngtcp2_is_bidi_stream(stream_id)) { - assert(!ngtcp2_conn_is_local_stream(conn_, stream_id)); - ngtcp2_conn_extend_max_streams_uni(conn_, 1); - } - - if (!config.quiet) { - std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", - stream_id, app_error_code); - } - streams_.erase(it); -} - -void Client::make_stream_early() { on_extend_max_streams(); } - -void Client::on_extend_max_streams() { - int64_t stream_id; - - if ((config.delay_stream && !handshake_confirmed_) || - ev_is_active(&delay_stream_timer_)) { - return; - } - - for (; nstreams_done_ < config.nstreams; ++nstreams_done_) { - if (auto rv = ngtcp2_conn_open_bidi_stream(conn_, &stream_id, nullptr); - rv != 0) { - assert(NGTCP2_ERR_STREAM_ID_BLOCKED == rv); - break; - } - - auto stream = std::make_unique( - config.requests[nstreams_done_ % config.requests.size()], stream_id); - - submit_http_request(stream.get()); - - if (!config.download.empty()) { - stream->open_file(stream->req.path); - } - streams_.emplace(stream_id, std::move(stream)); - } -} - -void Client::submit_http_request(Stream *stream) { - const auto &req = stream->req; - - stream->rawreqbuf = config.http_method; - stream->rawreqbuf += ' '; - stream->rawreqbuf += req.path; - stream->rawreqbuf += "\r\n"; - - nghttp3_buf_init(&stream->reqbuf); - stream->reqbuf.begin = reinterpret_cast(stream->rawreqbuf.data()); - stream->reqbuf.pos = stream->reqbuf.begin; - stream->reqbuf.end = stream->reqbuf.last = - stream->reqbuf.begin + stream->rawreqbuf.size(); - - if (!config.quiet) { - auto nva = std::to_array({ - util::make_nv_nn(":method", config.http_method), - util::make_nv_nn(":path", req.path), - }); - debug::print_http_request_headers(stream->stream_id, nva.data(), - nva.size()); - } - - sendq_.emplace(stream); -} - -void Client::recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data) { - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - - ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, data.size()); - ngtcp2_conn_extend_max_offset(conn_, data.size()); - - if (stream->fd == -1) { - return; - } - - ssize_t nwrite; - - for (; !data.empty();) { - do { - nwrite = write(stream->fd, data.data(), data.size()); - } while (nwrite == -1 && errno == EINTR); - - if (nwrite < 0) { - std::println(stderr, "Could not write data to file: {}", strerror(errno)); - - return; - } - - data = data.subspan(static_cast(nwrite)); - } -} - -void Client::acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen) { - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - (void)stream; - assert(static_cast(stream->reqbuf.end - stream->reqbuf.begin) >= - offset + datalen); -} - -std::expected -Client::select_preferred_address(Address &selected_addr, - const ngtcp2_preferred_addr *paddr) { - auto path = ngtcp2_conn_get_path(conn_); - - switch (path->local.addr->sa_family) { - case AF_INET: - if (!paddr->ipv4_present) { - return std::unexpected{Error::INTERNAL}; - } - selected_addr.skaddr.emplace(paddr->ipv4); - break; - case AF_INET6: - if (!paddr->ipv6_present) { - return std::unexpected{Error::INTERNAL}; - } - selected_addr.skaddr.emplace(paddr->ipv6); - break; - default: - return std::unexpected{Error::INTERNAL}; - } - - if (!config.quiet) { - char host[NI_MAXHOST], service[NI_MAXSERV]; - if (auto rv = getnameinfo(selected_addr.as_sockaddr(), selected_addr.size(), - host, sizeof(host), service, sizeof(service), - NI_NUMERICHOST | NI_NUMERICSERV); - rv != 0) { - std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - std::println(stderr, "selected server preferred_address is [{}]:{}", host, - service); - } - - return {}; -} - -const std::vector &Client::get_offered_versions() const { - return offered_versions_; -} - -namespace { -std::expected run(Client &c, const char *addr, const char *port, - TLSClientContext &tls_ctx) { - Address remote_addr, local_addr; - - auto maybe_fd = create_sock(remote_addr, addr, port); - if (!maybe_fd) { - return std::unexpected{maybe_fd.error()}; - } - - auto fd = *maybe_fd; - -#ifdef HAVE_LINUX_RTNETLINK_H - auto maybe_ia = get_local_addr(remote_addr); - if (!maybe_ia) { - std::println(stderr, "Could not get local address"); - close(fd); - return std::unexpected{maybe_ia.error()}; - } - - if (auto rv = bind_addr(local_addr, fd, *maybe_ia, remote_addr.family()); - !rv) { - close(fd); - return rv; - } -#else // !defined(HAVE_LINUX_RTNETLINK_H) - if (auto rv = connect_sock(local_addr, fd, remote_addr); !rv) { - close(fd); - return rv; - } -#endif // !defined(HAVE_LINUX_RTNETLINK_H) - - if (auto rv = c.init(fd, local_addr, remote_addr, addr, port, tls_ctx); !rv) { - return rv; - } - - // TODO Do we need this ? - if (auto rv = c.on_write(); !rv) { - return rv; - } - - ev_run(EV_DEFAULT, 0); - - return {}; -} -} // namespace - -namespace { -std::expected parse_uri(std::string_view uri) { - urlparse_url u; - - if (urlparse_parse_url(uri.data(), uri.size(), /* is_connect = */ 0, &u) != - 0) { - return std::unexpected{Error::INVALID_ARGUMENT}; - } - - if (!(u.field_set & (1 << URLPARSE_SCHEMA)) || - !(u.field_set & (1 << URLPARSE_HOST))) { - return std::unexpected{Error::INVALID_ARGUMENT}; - } - - Request req; - - req.scheme = util::get_string(uri, u, URLPARSE_SCHEMA); - - auto host = std::string(util::get_string(uri, u, URLPARSE_HOST)); - if (util::numeric_host(host.c_str(), AF_INET6)) { - req.authority = '['; - req.authority += host; - req.authority += ']'; - } else { - req.authority = std::move(host); - } - - if (u.field_set & (1 << URLPARSE_PORT)) { - req.authority += ':'; - req.authority += util::get_string(uri, u, URLPARSE_PORT); - } - - if (u.field_set & (1 << URLPARSE_PATH)) { - req.path = util::get_string(uri, u, URLPARSE_PATH); - } else { - req.path = "/"; - } - - if (u.field_set & (1 << URLPARSE_QUERY)) { - req.path += '?'; - req.path += util::get_string(uri, u, URLPARSE_QUERY); - } - - return req; -} -} // namespace - -namespace { -std::expected parse_requests(char **argv, size_t argvlen) { - for (size_t i = 0; i < argvlen; ++i) { - auto uri = std::string_view{argv[i]}; - auto maybe_req = parse_uri(uri); - if (!maybe_req) { - std::println(stderr, "Could not parse URI: {}", uri); - return std::unexpected{maybe_req.error()}; - } - config.requests.emplace_back(std::move(*maybe_req)); - } - return {}; -} -} // namespace - -std::ofstream keylog_file; - -namespace { -const char *prog = "h09client"; -} // namespace - -namespace { -void print_usage(FILE *out) { - std::println(out, "Usage: {} [OPTIONS] [...]", prog); -} -} // namespace - -namespace { -void print_help() { - print_usage(stdout); - - Config config; - - std::cout << R"( - Remote server host (DNS name or IP address). In case of - DNS name, it will be sent in TLS SNI extension. - Remote server port - Remote URI -Options: - -t, --tx-loss=

- The probability of losing outgoing packets.

must be - [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0 - means 100% packet loss. - -r, --rx-loss=

- The probability of losing incoming packets.

must be - [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0 - means 100% packet loss. - -d, --data= - Read data from , and send them as STREAM data. - -n, --nstreams= - The number of requests. s are used in the order of - appearance in the command-line. If the number of - list is less than , list is wrapped. It - defaults to 0 which means the number of specified. - -v, --version= - Specify QUIC version to use in hex string. If the given - version is not supported by libngtcp2, client will use - QUIC v1 long packet types. Instead of specifying hex - string, there are special aliases available: "v1" - indicates QUIC v1, and "v2" indicates QUIC v2. - Default: )" - << std::hex << "0x" << config.version << std::dec << R"( - --preferred-versions=[[,]...] - Specify QUIC versions in hex string in the order of - preference. Client chooses one of those versions if - client received Version Negotiation packet from server. - These versions must be supported by libngtcp2. Instead - of specifying hex string, there are special aliases - available: "v1" indicates QUIC v1, and "v2" indicates - QUIC v2. - --available-versions=[[,]...] - Specify QUIC versions in hex string that are sent in - available_versions field of version_information - transport parameter. This list can include a version - which is not supported by libngtcp2. Instead of - specifying hex string, there are special aliases - available: "v1" indicates QUIC v1, and "v2" indicates - QUIC v2. - -q, --quiet Suppress debug output. - -s, --show-secret - Print out secrets unless --quiet is used. - --timeout= - Specify idle timeout. - Default: )" - << util::format_duration(config.timeout) << R"( - --ciphers= - Specify the cipher suite list to enable. - Default: )" - << config.ciphers << R"( - --groups= - Specify the supported groups. - Default: )" - << config.groups << R"( - --session-file= - Read/write TLS session from/to . To resume a - session, the previous session must be supplied with this - option. - --tp-file= - Read/write QUIC transport parameters from/to . To - send 0-RTT data, the transport parameters received from - the previous session must be supplied with this option. - --dcid= - Specify initial DCID. is hex string. After - decoded as binary, it should be at least 8 bytes and at - most 20 bytes long. - --change-local-addr= - Client changes local address when elapse - after handshake completes. - --nat-rebinding - When used with --change-local-addr, simulate NAT - rebinding. In other words, client changes local - address, but it does not start path validation. - --key-update= - Client initiates key update when elapse after - handshake completes. - -m, --http-method= - Specify HTTP method. Default: )" - << config.http_method << R"( - --delay-stream= - Delay sending STREAM data in 1-RTT for after - handshake completes. - --no-preferred-addr - Do not try to use preferred address offered by server. - --key= - The path to client private key PEM file. - --cert= - The path to client certificate PEM file. - --download= - The path to the directory to save a downloaded content. - It is undefined if 2 concurrent requests write to the - same file. If a request path does not contain a path - component usable as a file name, it defaults to - "index.html". - --no-quic-dump - Disables printing QUIC STREAM and CRYPTO frame data out. - --no-http-dump - Disables printing HTTP response body out. - --qlog-file= - The path to write qlog. This option and --qlog-dir are - mutually exclusive. - --qlog-dir= - Path to the directory where qlog file is stored. The - file name of each qlog is the Source Connection ID of - client. This option and --qlog-file are mutually - exclusive. - --max-data= - The initial connection-level flow control window. - Default: )" - << util::format_uint_iec(config.max_data) << R"( - --max-stream-data-bidi-local= - The initial stream-level flow control window for a - bidirectional stream that the local endpoint initiates. - Default: )" - << util::format_uint_iec(config.max_stream_data_bidi_local) << R"( - --max-stream-data-bidi-remote= - The initial stream-level flow control window for a - bidirectional stream that the remote endpoint initiates. - Default: )" - << util::format_uint_iec(config.max_stream_data_bidi_remote) << R"( - --max-stream-data-uni= - The initial stream-level flow control window for a - unidirectional stream. - Default: )" - << util::format_uint_iec(config.max_stream_data_uni) << R"( - --max-streams-bidi= - The number of the concurrent bidirectional streams that - the remote endpoint initiates. - Default: )" - << config.max_streams_bidi << R"( - --max-streams-uni= - The number of the concurrent unidirectional streams that - the remote endpoint initiates. - Default: )" - << config.max_streams_uni << R"( - --exit-on-first-stream-close - Exit when a first client initiated HTTP stream is - closed. - --exit-on-all-streams-close - Exit when all client initiated HTTP streams are closed. - --wait-for-ticket - Wait for a ticket to be received before exiting on - --exit-on-first-stream-close or - --exit-on-all-streams-close. --session-file must be - specified. - --disable-early-data - Disable early data. - --cc=(cubic|reno|bbr) - The name of congestion controller algorithm. - Default: )" - << util::strccalgo(config.cc_algo) << R"( - --token-file= - Read/write token from/to . Token is obtained from - NEW_TOKEN frame from server. - --sni= - Send in TLS SNI, overriding the DNS name - specified in . - --initial-rtt= - Set an initial RTT. - Default: )" - << util::format_duration(config.initial_rtt) << R"( - --max-window= - Maximum connection-level flow control window size. The - window auto-tuning is enabled if nonzero value is given, - and window size is scaled up to this value. - Default: )" - << util::format_uint_iec(config.max_window) << R"( - --max-stream-window= - Maximum stream-level flow control window size. The - window auto-tuning is enabled if nonzero value is given, - and window size is scaled up to this value. - Default: )" - << util::format_uint_iec(config.max_stream_window) << R"( - --max-udp-payload-size= - Override maximum UDP payload size that client transmits. - With this option, client assumes that a path supports - byte of UDP datagram payload, without performing - Path MTU Discovery. - --handshake-timeout= - Set the QUIC handshake timeout. It defaults to no - timeout. - --no-pmtud Disables Path MTU Discovery. - --ack-thresh= - The minimum number of the received ACK eliciting packets - that triggers immediate acknowledgement. - Default: )" - << config.ack_thresh << R"( - --initial-pkt-num= - The initial packet number that is used for each packet - number space. It must be in range [0, (1 << 31) - 1], - inclusive. By default, the initial packet number is - chosen randomly. - --pmtud-probes=[[,]...] - Specify UDP datagram payload sizes to probe in Path MTU - Discovery. must be strictly larger than 1200. - --ech-config-list-file= - Read/write ECHConfigList from/to . ECH is only - attempted if an underlying TLS stack supports it. If - the handshake fails with ech_required alert, ECH retry - configs, if provided by server, will be written to - . - --no-gso Disables GSO. - --show-stat Print the connection statistics when the connection is - closed. - --gso-burst= - The maximum number of packets to aggregate for GSO. If - GSO is disabled, this is the maximum number of packets - to send per an event loop in a single connection. It - defaults to 0, which means it is not limited by the - configuration. - -h, --help Display this help and exit. - ---- - - The argument is an integer and an optional unit (e.g., 10K is - 10 * 1024). Units are K, M and G (powers of 1024). - - The argument is an integer and an optional unit (e.g., 1s - is 1 second and 500ms is 500 milliseconds). Units are h, m, s, ms, - us, or ns (hours, minutes, seconds, milliseconds, microseconds, and - nanoseconds respectively). If a unit is omitted, a second is used - as unit. - - The argument is an hex string which must start with "0x" - (e.g., 0x00000001).)" - << std::endl; -} -} // namespace - -int main(int argc, char **argv) { - char *data_path = nullptr; - const char *private_key_file = nullptr; - const char *cert_file = nullptr; - - if (argc) { - prog = basename(argv[0]); - } - - for (;;) { - static int flag = 0; - constexpr static option long_opts[] = { - {"help", no_argument, nullptr, 'h'}, - {"tx-loss", required_argument, nullptr, 't'}, - {"rx-loss", required_argument, nullptr, 'r'}, - {"data", required_argument, nullptr, 'd'}, - {"http-method", required_argument, nullptr, 'm'}, - {"nstreams", required_argument, nullptr, 'n'}, - {"version", required_argument, nullptr, 'v'}, - {"quiet", no_argument, nullptr, 'q'}, - {"show-secret", no_argument, nullptr, 's'}, - {"ciphers", required_argument, &flag, 1}, - {"groups", required_argument, &flag, 2}, - {"timeout", required_argument, &flag, 3}, - {"session-file", required_argument, &flag, 4}, - {"tp-file", required_argument, &flag, 5}, - {"dcid", required_argument, &flag, 6}, - {"change-local-addr", required_argument, &flag, 7}, - {"key-update", required_argument, &flag, 8}, - {"nat-rebinding", no_argument, &flag, 9}, - {"delay-stream", required_argument, &flag, 10}, - {"no-preferred-addr", no_argument, &flag, 11}, - {"key", required_argument, &flag, 12}, - {"cert", required_argument, &flag, 13}, - {"download", required_argument, &flag, 14}, - {"no-quic-dump", no_argument, &flag, 15}, - {"no-http-dump", no_argument, &flag, 16}, - {"qlog-file", required_argument, &flag, 17}, - {"max-data", required_argument, &flag, 18}, - {"max-stream-data-bidi-local", required_argument, &flag, 19}, - {"max-stream-data-bidi-remote", required_argument, &flag, 20}, - {"max-stream-data-uni", required_argument, &flag, 21}, - {"max-streams-bidi", required_argument, &flag, 22}, - {"max-streams-uni", required_argument, &flag, 23}, - {"exit-on-first-stream-close", no_argument, &flag, 24}, - {"disable-early-data", no_argument, &flag, 25}, - {"qlog-dir", required_argument, &flag, 26}, - {"cc", required_argument, &flag, 27}, - {"exit-on-all-streams-close", no_argument, &flag, 28}, - {"token-file", required_argument, &flag, 29}, - {"sni", required_argument, &flag, 30}, - {"initial-rtt", required_argument, &flag, 31}, - {"max-window", required_argument, &flag, 32}, - {"max-stream-window", required_argument, &flag, 33}, - {"max-udp-payload-size", required_argument, &flag, 35}, - {"handshake-timeout", required_argument, &flag, 36}, - {"available-versions", required_argument, &flag, 37}, - {"no-pmtud", no_argument, &flag, 38}, - {"preferred-versions", required_argument, &flag, 39}, - {"ack-thresh", required_argument, &flag, 40}, - {"wait-for-ticket", no_argument, &flag, 41}, - {"initial-pkt-num", required_argument, &flag, 42}, - {"pmtud-probes", required_argument, &flag, 43}, - {"ech-config-list-file", required_argument, &flag, 44}, - {"no-gso", no_argument, &flag, 45}, - {"show-stat", no_argument, &flag, 46}, - {"gso-burst", required_argument, &flag, 47}, - {}, - }; - - auto optidx = 0; - auto c = getopt_long(argc, argv, "d:him:n:qr:st:v:", long_opts, &optidx); - if (c == -1) { - break; - } - switch (c) { - case 'd': - // --data - data_path = optarg; - break; - case 'h': - // --help - print_help(); - exit(EXIT_SUCCESS); - case 'm': - // --http-method - config.http_method = optarg; - break; - case 'n': - // --streams - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "streams: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n > NGTCP2_MAX_VARINT) { - std::println(stderr, "streams: must not exceed {}", NGTCP2_MAX_VARINT); - exit(EXIT_FAILURE); - } else { - config.nstreams = *n; - } - break; - case 'q': - // --quiet - config.quiet = true; - break; - case 'r': - // --rx-loss - config.rx_loss_prob = strtod(optarg, nullptr); - break; - case 's': - // --show-secret - config.show_secret = true; - break; - case 't': - // --tx-loss - config.tx_loss_prob = strtod(optarg, nullptr); - break; - case 'v': { - // --version - if (optarg == "v1"sv) { - config.version = NGTCP2_PROTO_VER_V1; - break; - } - if (optarg == "v2"sv) { - config.version = NGTCP2_PROTO_VER_V2; - break; - } - auto rv = util::parse_version(optarg); - if (!rv) { - std::println(stderr, "version: invalid version {}", optarg); - exit(EXIT_FAILURE); - } - config.version = *rv; - break; - } - case '?': - print_usage(stderr); - exit(EXIT_FAILURE); - case 0: - switch (flag) { - case 1: - // --ciphers - if (util::crypto_default_ciphers()[0] == '\0') { - std::println(stderr, "ciphers: not supported"); - exit(EXIT_FAILURE); - } - config.ciphers = optarg; - break; - case 2: - // --groups - config.groups = optarg; - break; - case 3: - // --timeout - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "timeout: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.timeout = *t; - } - break; - case 4: - // --session-file - config.session_file = optarg; - break; - case 5: - // --tp-file - config.tp_file = optarg; - break; - case 6: { - // --dcid - auto hexcid = std::string_view{optarg}; - if (hexcid.size() < NGTCP2_MIN_INITIAL_DCIDLEN * 2 || - hexcid.size() > NGTCP2_MAX_CIDLEN * 2) { - std::println(stderr, "dcid: wrong length"); - exit(EXIT_FAILURE); - } - - if (!util::is_hex_string(hexcid)) { - std::println(stderr, "dcid: not hex string"); - exit(EXIT_FAILURE); - } - - auto dcid = util::decode_hex(hexcid); - ngtcp2_cid_init(&config.dcid, - reinterpret_cast(dcid.c_str()), - dcid.size()); - break; - } - case 7: - // --change-local-addr - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "change-local-addr: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.change_local_addr = *t; - } - break; - case 8: - // --key-update - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "key-update: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.key_update = *t; - } - break; - case 9: - // --nat-rebinding - config.nat_rebinding = true; - break; - case 10: - // --delay-stream - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "delay-stream: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.delay_stream = *t; - } - break; - case 11: - // --no-preferred-addr - config.no_preferred_addr = true; - break; - case 12: - // --key - private_key_file = optarg; - break; - case 13: - // --cert - cert_file = optarg; - break; - case 14: - // --download - config.download = optarg; - break; - case 15: - // --no-quic-dump - config.no_quic_dump = true; - break; - case 16: - // --no-http-dump - config.no_http_dump = true; - break; - case 17: - // --qlog-file - config.qlog_file = optarg; - break; - case 18: - // --max-data - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-data: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_data = *n; - } - break; - case 19: - // --max-stream-data-bidi-local - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-data-bidi-local: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_data_bidi_local = *n; - } - break; - case 20: - // --max-stream-data-bidi-remote - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-data-bidi-remote: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_data_bidi_remote = *n; - } - break; - case 21: - // --max-stream-data-uni - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-data-uni: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_data_uni = *n; - } - break; - case 22: - // --max-streams-bidi - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "max-streams-bidi: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_streams_bidi = *n; - } - break; - case 23: - // --max-streams-uni - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "max-streams-uni: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_streams_uni = *n; - } - break; - case 24: - // --exit-on-first-stream-close - config.exit_on_first_stream_close = true; - break; - case 25: - // --disable-early-data - config.disable_early_data = true; - break; - case 26: - // --qlog-dir - config.qlog_dir = optarg; - break; - case 27: - // --cc - if (strcmp("cubic", optarg) == 0) { - config.cc_algo = NGTCP2_CC_ALGO_CUBIC; - break; - } - if (strcmp("reno", optarg) == 0) { - config.cc_algo = NGTCP2_CC_ALGO_RENO; - break; - } - if (strcmp("bbr", optarg) == 0) { - config.cc_algo = NGTCP2_CC_ALGO_BBR; - break; - } - std::println(stderr, "cc: specify cubic, reno, or bbr"); - exit(EXIT_FAILURE); - case 28: - // --exit-on-all-streams-close - config.exit_on_all_streams_close = true; - break; - case 29: - // --token-file - config.token_file = optarg; - break; - case 30: - // --sni - config.sni = optarg; - break; - case 31: - // --initial-rtt - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "initial-rtt: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.initial_rtt = *t; - } - break; - case 32: - // --max-window - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-window: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_window = *n; - } - break; - case 33: - // --max-stream-window - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-window: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_window = *n; - } - break; - case 35: - // --max-udp-payload-size - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-udp-payload-size: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { - std::println(stderr, "max-udp-payload-size: must not exceed {}", - NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); - exit(EXIT_FAILURE); - } else if (*n == 0) { - std::println(stderr, "max-udp-payload-size: must not be 0"); - } else { - config.max_udp_payload_size = *n; - } - break; - case 36: - // --handshake-timeout - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "handshake-timeout: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.handshake_timeout = *t; - } - break; - case 37: { - // --available-versions - if (strlen(optarg) == 0) { - config.available_versions.resize(0); - break; - } - auto l = util::split_str(optarg); - config.available_versions.resize(l.size()); - auto it = std::ranges::begin(config.available_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "available-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - *it++ = *rv; - } - break; - } - case 38: - // --no-pmtud - config.no_pmtud = true; - break; - case 39: { - // --preferred-versions - auto l = util::split_str(optarg); - if (l.size() > max_preferred_versionslen) { - std::println(stderr, "preferred-versions: too many versions > {}", - max_preferred_versionslen); - exit(EXIT_FAILURE); - } - config.preferred_versions.resize(l.size()); - auto it = std::ranges::begin(config.preferred_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "preferred-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - if (!ngtcp2_is_supported_version(*rv)) { - std::println(stderr, "preferred-versions: unsupported version {}", - k); - exit(EXIT_FAILURE); - } - *it++ = *rv; - } - break; - } - case 40: - // --ack-thresh - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "ack-thresh: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n > 100) { - std::println(stderr, "ack-thresh: must not exceed 100"); - exit(EXIT_FAILURE); - } else { - config.ack_thresh = *n; - } - break; - case 41: - // --wait-for-ticket - config.wait_for_ticket = true; - break; - case 42: - // --initial-pkt-num - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "initial-pkt-num: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n > INT32_MAX) { - std::println(stderr, - "initial-pkt-num: must not exceed (1 << 31) - 1"); - exit(EXIT_FAILURE); - } else { - config.initial_pkt_num = static_cast(*n); - } - break; - case 43: { - // --pmtud-probes - auto l = util::split_str(optarg); - for (auto &s : l) { - if (auto n = util::parse_uint_iec(s); !n) { - std::println(stderr, "pmtud-probes: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE || - *n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { - std::println( - stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", - NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); - exit(EXIT_FAILURE); - } else { - config.pmtud_probes.push_back(static_cast(*n)); - } - } - break; - } - case 44: - // --ech-config-list-file - config.ech_config_list_file = optarg; - break; - case 45: - // --no-gso - config.no_gso = true; - break; - case 46: - // --show-stat - config.show_stat = true; - break; - case 47: { - // --gso-burst - auto n = util::parse_uint(optarg); - if (!n) { - std::println(stderr, "gso-burst: invalid argument"); - exit(EXIT_FAILURE); - } - - if (*n > 64) { - std::println(stderr, - "gso-burst: must be in range [0, 64], inclusive."); - exit(EXIT_FAILURE); - } - - config.gso_burst = static_cast(*n); - - break; - } - } - break; - default: - break; - } - } - - if (argc - optind < 2) { - std::println(stderr, "Too few arguments"); - print_usage(stderr); - exit(EXIT_FAILURE); - } - - if (!config.qlog_file.empty() && !config.qlog_dir.empty()) { - std::println(stderr, "qlog-file and qlog-dir are mutually exclusive"); - exit(EXIT_FAILURE); - } - - if (config.exit_on_first_stream_close && config.exit_on_all_streams_close) { - std::println(stderr, "exit-on-first-stream-close and " - "exit-on-all-streams-close are mutually exclusive"); - exit(EXIT_FAILURE); - } - - if (config.wait_for_ticket && !config.session_file) { - std::println(stderr, "wait-for-ticket: session-file must be specified"); - exit(EXIT_FAILURE); - } - - if (data_path) { - auto fd = open(data_path, O_RDONLY); - if (fd == -1) { - std::println(stderr, "data: Could not open file {}: {}", data_path, - strerror(errno)); - exit(EXIT_FAILURE); - } - struct stat st; - if (fstat(fd, &st) != 0) { - std::println(stderr, "data: Could not stat file {}: {}", data_path, - strerror(errno)); - exit(EXIT_FAILURE); - } - config.fd = fd; - config.datalen = static_cast(st.st_size); - if (config.datalen) { - auto addr = mmap(nullptr, config.datalen, PROT_READ, MAP_SHARED, fd, 0); - if (addr == MAP_FAILED) { - std::println(stderr, "data: Could not mmap file {}: {}", data_path, - strerror(errno)); - exit(EXIT_FAILURE); - } - config.data = static_cast(addr); - } - } - - if (config.ech_config_list_file) { - auto ech_config = util::read_file(config.ech_config_list_file); - if (!ech_config) { - std::println(stderr, - "ech-config-list-file: Could not read ECHConfigList"); - } else { - config.ech_config_list = std::move(*ech_config); - } - } - - auto addr = argv[optind++]; - auto port = argv[optind++]; - - if (!parse_requests(&argv[optind], static_cast(argc - optind))) { - exit(EXIT_FAILURE); - } - - if (!ngtcp2_is_reserved_version(config.version)) { - if (!config.preferred_versions.empty() && - std::ranges::find(config.preferred_versions, config.version) == - std::ranges::end(config.preferred_versions)) { - std::println(stderr, "preferred-version: must include version {:#x}", - config.version); - exit(EXIT_FAILURE); - } - - if (!config.available_versions.empty() && - std::ranges::find(config.available_versions, config.version) == - std::ranges::end(config.available_versions)) { - std::println(stderr, "available-versions: must include version {:#x}", - config.version); - exit(EXIT_FAILURE); - } - } - - if (config.nstreams == 0) { - config.nstreams = config.requests.size(); - } - - TLSClientContext tls_ctx; - if (!tls_ctx.init(private_key_file, cert_file)) { - exit(EXIT_FAILURE); - } - - auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); }); - - auto keylog_filename = getenv("SSLKEYLOGFILE"); - if (keylog_filename) { - keylog_file.open(keylog_filename, std::ios_base::app); - if (keylog_file) { - tls_ctx.enable_keylog(); - } - } - - if (!util::generate_secure_random(config.static_secret)) { - std::println(stderr, "Unable to generate static secret"); - exit(EXIT_FAILURE); - } - - auto client_chosen_version = config.version; - - for (;;) { - Client c(EV_DEFAULT, client_chosen_version, config.version); - - if (!run(c, addr, port, tls_ctx)) { - exit(EXIT_FAILURE); - } - - if (config.preferred_versions.empty()) { - break; - } - - auto &offered_versions = c.get_offered_versions(); - if (offered_versions.empty()) { - break; - } - - client_chosen_version = ngtcp2_select_version( - config.preferred_versions.data(), config.preferred_versions.size(), - offered_versions.data(), offered_versions.size()); - - if (client_chosen_version == 0) { - std::println(stderr, "Unable to select a version"); - exit(EXIT_FAILURE); - } - - if (!config.quiet) { - std::println(stderr, "Client selected version {:#x}", - client_chosen_version); - } - } - - return EXIT_SUCCESS; -} diff --git a/deps/ngtcp2/ngtcp2/examples/h09client.h b/deps/ngtcp2/ngtcp2/examples/h09client.h deleted file mode 100644 index 7e0afee3050083..00000000000000 --- a/deps/ngtcp2/ngtcp2/examples/h09client.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2017 ngtcp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef H09CLIENT_H -#define H09CLIENT_H - -#ifdef HAVE_CONFIG_H -# include -#endif // defined(HAVE_CONFIG_H) - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include "client_base.h" -#include "tls_client_context.h" -#include "tls_client_session.h" -#include "network.h" -#include "shared.h" -#include "template.h" - -using namespace ngtcp2; - -struct Stream { - Stream(const Request &req, int64_t stream_id); - ~Stream(); - - std::expected open_file(std::string_view path); - - Request req; - int64_t stream_id; - int fd{-1}; - std::string rawreqbuf; - nghttp3_buf reqbuf; -}; - -struct StreamIDLess { - constexpr bool operator()(const Stream *lhs, const Stream *rhs) const { - return lhs->stream_id < rhs->stream_id; - } -}; - -class Client; - -struct Endpoint { - Address addr; - ev_io rev; - Client *client{}; - int fd{}; -}; - -class Client : public ClientBase { -public: - Client(struct ev_loop *loop, uint32_t client_chosen_version, - uint32_t original_version); - ~Client(); - - std::expected init(int fd, const Address &local_addr, - const Address &remote_addr, const char *addr, - const char *port, TLSClientContext &tls_ctx); - void disconnect(); - - std::expected on_read(const Endpoint &ep); - std::expected on_write(); - std::expected write_streams(); - std::expected feed_data(const Endpoint &ep, const sockaddr *sa, - socklen_t salen, - const ngtcp2_pkt_info *pi, - std::span data); - std::expected handle_expiry(); - void update_timer(); - std::expected handshake_completed(); - void handshake_confirmed(); - void recv_version_negotiation(const uint32_t *sv, size_t nsv); - - std::expected send_packet(const Endpoint &ep, - const ngtcp2_addr &remote_addr, - unsigned int ecn, - std::span data); - std::span - send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, - unsigned int ecn, std::span data, size_t gso_size); - std::expected - send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size); - void on_stream_close(int64_t stream_id, uint64_t app_error_code); - void on_extend_max_streams(); - std::expected handle_error(); - void make_stream_early(); - std::expected change_local_addr(); - void start_change_local_addr_timer(); - std::expected - update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, - size_t secretlen); - std::expected initiate_key_update(); - void start_key_update_timer(); - void start_delay_stream_timer(); - - std::expected - select_preferred_address(Address &selected_addr, - const ngtcp2_preferred_addr *paddr); - - std::expected endpoint_for(const Address &remote_addr); - - void set_remote_addr(const ngtcp2_addr &remote_addr); - - void submit_http_request(Stream *stream); - void recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data); - void acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen); - void extend_max_stream_data(int64_t stream_id, uint64_t max_data); - - void write_qlog(const void *data, size_t datalen); - - void on_send_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size); - void start_wev_endpoint(const Endpoint &ep); - void send_blocked_packet(); - ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, - size_t destlen, ngtcp2_tstamp ts); - - const std::vector &get_offered_versions() const; - - void early_data_rejected(); - - bool should_exit() const; - -private: - std::vector endpoints_; - Address remote_addr_; - ev_io wev_; - ev_timer timer_; - ev_timer change_local_addr_timer_; - ev_timer key_update_timer_; - ev_timer delay_stream_timer_; - ev_signal sigintev_; - struct ev_loop *loop_; - std::unordered_map> streams_; - std::set sendq_; - std::vector offered_versions_; - // addr_ is the server host address. - const char *addr_{}; - // port_ is the server port. - const char *port_{}; - // nstreams_done_ is the number of streams opened. - size_t nstreams_done_{}; - // nstreams_closed_ is the number of streams get closed. - size_t nstreams_closed_{}; - // nkey_update_ is the number of key update occurred. - size_t nkey_update_{}; - uint32_t client_chosen_version_; - uint32_t original_version_; - // early_data_ is true if client attempts to do 0RTT data transfer. - bool early_data_{}; - // handshake_confirmed_ gets true after handshake has been - // confirmed. - bool handshake_confirmed_{}; - bool no_gso_; - - struct { - bool send_blocked; - // blocked field is effective only when send_blocked is true. - struct { - const Endpoint *endpoint; - Address remote_addr; - unsigned int ecn; - std::span data; - size_t gso_size; - } blocked; - } tx_{}; - std::array txbuf_; -}; - -#endif // !defined(H09CLIENT_H) diff --git a/deps/ngtcp2/ngtcp2/examples/h09server.cc b/deps/ngtcp2/ngtcp2/examples/h09server.cc deleted file mode 100644 index 3636d4e064dfc6..00000000000000 --- a/deps/ngtcp2/ngtcp2/examples/h09server.cc +++ /dev/null @@ -1,3220 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2017 ngtcp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "h09server.h" -#include "network.h" -#include "debug.h" -#include "util.h" -#include "shared.h" -#include "http.h" -#include "template.h" - -using namespace ngtcp2; -using namespace std::literals; - -namespace { -constexpr size_t NGTCP2_SV_SCIDLEN = 18; -} // namespace - -namespace { -constexpr size_t max_preferred_versionslen = 4; -} // namespace - -namespace { -auto randgen = util::make_mt19937(); -} // namespace - -Config config; - -Stream::Stream(int64_t stream_id, Handler *handler) - : stream_id{stream_id}, handler{handler} { - nghttp3_buf_init(&respbuf); - htp.data = this; - http_parser_init(&htp, HTTP_REQUEST); -} - -namespace { -constexpr auto NGTCP2_SERVER = "ngtcp2 server"sv; -} // namespace - -namespace { -std::string make_status_body(unsigned int status_code) { - auto status_string = util::format_uint(status_code); - auto reason_phrase = http::get_reason_phrase(status_code); - - std::string body; - body = ""; - body += status_string; - body += ' '; - body += reason_phrase; - body += "

"; - body += status_string; - body += ' '; - body += reason_phrase; - body += "


"; - body += NGTCP2_SERVER; - body += " at port "; - body += util::format_uint(config.port); - body += "
"; - body += ""; - return body; -} -} // namespace - -struct Request { - std::string path; -}; - -namespace { -Request request_path(std::string_view uri) { - urlparse_url u; - Request req; - - if (auto rv = urlparse_parse_url(uri.data(), uri.size(), - /* is_connect = */ 0, &u); - rv != 0) { - return {}; - } - - if (u.field_set & (1 << URLPARSE_PATH)) { - req.path = util::get_string(uri, u, URLPARSE_PATH); - if (req.path.find('%') != std::string::npos) { - req.path = util::percent_decode(req.path); - } - - assert(!req.path.empty()); - - if (req.path[0] != '/') { - return {}; - } - - if (req.path.back() == '/') { - req.path += "index.html"; - } - - auto maybe_norm_path = util::normalize_path(req.path); - if (!maybe_norm_path) { - return {}; - } - - req.path = std::move(*maybe_norm_path); - } else { - req.path = "/index.html"; - } - - return req; -} -} // namespace - -enum FileEntryFlag { - FILE_ENTRY_TYPE_DIR = 0x1, -}; - -struct FileEntry { - uint64_t len{}; - void *map{}; - int fd{}; - uint8_t flags{}; -}; - -namespace { -std::unordered_map file_cache; -} // namespace - -std::expected Stream::open_file(const std::string &path) { - auto it = file_cache.find(path); - if (it != std::ranges::end(file_cache)) { - return (*it).second; - } - - auto fd = open(path.c_str(), O_RDONLY); - if (fd == -1) { - return std::unexpected{Error::SYSCALL}; - } - - struct stat st{}; - if (fstat(fd, &st) != 0) { - close(fd); - return std::unexpected{Error::SYSCALL}; - } - - FileEntry fe; - if (st.st_mode & S_IFDIR) { - fe.flags |= FILE_ENTRY_TYPE_DIR; - fe.fd = -1; - close(fd); - } else { - fe.fd = fd; - fe.len = static_cast(st.st_size); - if (fe.len) { - fe.map = mmap(nullptr, fe.len, PROT_READ, MAP_SHARED, fd, 0); - if (fe.map == MAP_FAILED) { - std::println(stderr, "mmap: {}", strerror(errno)); - close(fd); - return std::unexpected{Error::SYSCALL}; - } - } - } - - file_cache.emplace(path, fe); - - return fe; -} - -void Stream::map_file(const FileEntry &fe) { - respbuf.begin = respbuf.pos = static_cast(fe.map); - respbuf.end = respbuf.last = respbuf.begin + fe.len; -} - -void Stream::send_status_response(unsigned int status_code) { - status_resp_body = make_status_body(status_code); - - respbuf.begin = respbuf.pos = - reinterpret_cast(status_resp_body.data()); - respbuf.end = respbuf.last = respbuf.begin + status_resp_body.size(); - - handler->add_sendq(this); - handler->shutdown_read(stream_id, 0); -} - -void Stream::start_response() { - if (uri.empty()) { - send_status_response(400); - return; - } - - auto req = request_path(uri); - if (req.path.empty()) { - send_status_response(400); - return; - } - - auto path = config.htdocs + req.path; - auto maybe_fe = open_file(path); - if (!maybe_fe) { - send_status_response(404); - return; - } - - const auto &fe = *maybe_fe; - - if (fe.flags & FILE_ENTRY_TYPE_DIR) { - send_status_response(308); - return; - } - - map_file(fe); - - if (!config.quiet) { - auto nva = std::to_array({ - util::make_nv_nn(":status", "200"), - }); - - debug::print_http_response_headers(stream_id, nva.data(), nva.size()); - } - - handler->add_sendq(this); -} - -namespace { -void writecb(struct ev_loop *loop, ev_io *w, int revents) { - auto h = static_cast(w->data); - auto s = h->server(); - - if (auto rv = h->on_write(); !rv && rv.error() != Error::CLOSE_WAIT) { - s->remove(h); - } -} -} // namespace - -namespace { -void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { - auto h = static_cast(w->data); - auto s = h->server(); - auto conn = h->conn(); - - if (ngtcp2_conn_in_closing_period(conn)) { - if (!config.quiet) { - std::println(stderr, "Closing Period is over"); - } - - s->remove(h); - return; - } - if (ngtcp2_conn_in_draining_period(conn)) { - if (!config.quiet) { - std::println(stderr, "Draining Period is over"); - } - - s->remove(h); - return; - } - - assert(0); -} -} // namespace - -namespace { -void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { - auto h = static_cast(w->data); - auto s = h->server(); - - if (!config.quiet) { - std::println(stderr, "Timer expired"); - } - - if (auto rv = h->handle_expiry(); !rv) { - if (rv.error() == Error::CLOSE_WAIT) { - ev_timer_stop(loop, w); - } else { - s->remove(h); - } - - return; - } - - h->signal_write(); -} -} // namespace - -Handler::Handler(struct ev_loop *loop, Server *server) - : loop_{loop}, - server_{server}, - no_gso_{ -#ifdef UDP_SEGMENT - config.no_gso -#else // !defined(UDP_SEGMENT) - true -#endif // !defined(UDP_SEGMENT) - } { - ev_io_init(&wev_, writecb, 0, EV_WRITE); - wev_.data = this; - ev_timer_init(&timer_, timeoutcb, 0., 0.); - timer_.data = this; -} - -Handler::~Handler() { - if (!config.quiet) { - std::println(stderr, "{} Closing QUIC connection", scid_); - } - - ev_timer_stop(loop_, &timer_); - ev_io_stop(loop_, &wev_); - - if (qlog_) { - fclose(qlog_); - } -} - -namespace { -int handshake_completed(ngtcp2_conn *conn, void *user_data) { - auto h = static_cast(user_data); - - if (!config.quiet) { - debug::handshake_completed(conn, user_data); - } - - if (!h->handshake_completed()) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} -} // namespace - -std::expected Handler::handshake_completed() { - if (!config.quiet) { - std::println(stderr, "Negotiated cipher suite is {}", - tls_session_.get_cipher_name()); - if (auto group = tls_session_.get_negotiated_group(); !group.empty()) { - std::println(stderr, "Negotiated group is {}", group); - } - std::println(stderr, "Negotiated ALPN is {}", - tls_session_.get_selected_alpn()); - } - - if (!tls_session_.send_session_ticket()) { - std::println(stderr, "Unable to send session ticket"); - } - - std::array token; - - auto path = ngtcp2_conn_get_path(conn_); - auto t = util::system_clock_now(); - - auto tokenlen = ngtcp2_crypto_generate_regular_token( - token.data(), config.static_secret.data(), config.static_secret.size(), - path->remote.addr, path->remote.addrlen, t); - if (tokenlen < 0) { - std::println(stderr, "Unable to generate token"); - - return std::unexpected{Error::QUIC}; - } - - if (auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(), - as_unsigned(tokenlen)); - rv != 0) { - std::println(stderr, "ngtcp2_conn_submit_new_token: {}", - ngtcp2_strerror(rv)); - - return std::unexpected{Error::QUIC}; - } - - return {}; -} - -namespace { -int do_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, - const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { - if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - if (!config.quiet && config.show_secret) { - debug::print_hp_mask({dest, NGTCP2_HP_MASKLEN}, - {sample, NGTCP2_HP_SAMPLELEN}); - } - - return 0; -} -} // namespace - -namespace { -int recv_crypto_data(ngtcp2_conn *conn, - ngtcp2_encryption_level encryption_level, uint64_t offset, - const uint8_t *data, size_t datalen, void *user_data) { - if (!config.quiet && !config.no_quic_dump) { - debug::print_crypto_data(encryption_level, {data, datalen}); - } - - return ngtcp2_crypto_recv_crypto_data_cb(conn, encryption_level, offset, data, - datalen, user_data); -} -} // namespace - -namespace { -int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, - uint64_t offset, const uint8_t *data, size_t datalen, - void *user_data, void *stream_user_data) { - auto h = static_cast(user_data); - - if (!h->recv_stream_data(flags, stream_id, {data, datalen})) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} -} // namespace - -namespace { -int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id, - uint64_t offset, uint64_t datalen, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - - h->acked_stream_data_offset(stream_id, offset, datalen); - - return 0; -} -} // namespace - -void Handler::acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen) { - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - (void)stream; - - assert(static_cast(stream->respbuf.end - stream->respbuf.begin) >= - offset + datalen); -} - -namespace { -int stream_open(ngtcp2_conn *conn, int64_t stream_id, void *user_data) { - auto h = static_cast(user_data); - h->on_stream_open(stream_id); - return 0; -} -} // namespace - -void Handler::on_stream_open(int64_t stream_id) { - if (!ngtcp2_is_bidi_stream(stream_id)) { - return; - } - - assert(!streams_.contains(stream_id)); - - streams_.emplace(stream_id, std::make_unique(stream_id, this)); -} - -namespace { -int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, - uint64_t app_error_code, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - - h->on_stream_close(stream_id, app_error_code); - - return 0; -} -} // namespace - -namespace { -void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { - if (!util::generate_secure_random({dest, destlen})) { - assert(0); - abort(); - } -} -} // namespace - -namespace { -int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, - ngtcp2_stateless_reset_token *token, size_t cidlen, - void *user_data) { - if (!util::generate_secure_random({cid->data, cidlen})) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - cid->datalen = cidlen; - if (ngtcp2_crypto_generate_stateless_reset_token( - token->data, config.static_secret.data(), config.static_secret.size(), - cid) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - auto h = static_cast(user_data); - h->server()->associate_cid(cid, h); - - return 0; -} -} // namespace - -namespace { -int remove_connection_id(ngtcp2_conn *conn, const ngtcp2_cid *cid, - void *user_data) { - auto h = static_cast(user_data); - h->server()->dissociate_cid(cid); - return 0; -} -} // namespace - -namespace { -int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen, - void *user_data) { - auto h = static_cast(user_data); - if (!h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, - tx_iv, current_rx_secret, current_tx_secret, secretlen)) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } - return 0; -} -} // namespace - -namespace { -int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path, - const ngtcp2_path *old_path, - ngtcp2_path_validation_result res, void *user_data) { - if (!config.quiet) { - debug::path_validation(path, res); - } - - if (res != NGTCP2_PATH_VALIDATION_RESULT_SUCCESS || - !(flags & NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN)) { - return 0; - } - - std::array token; - auto t = util::system_clock_now(); - - auto tokenlen = ngtcp2_crypto_generate_regular_token( - token.data(), config.static_secret.data(), config.static_secret.size(), - path->remote.addr, path->remote.addrlen, t); - if (tokenlen < 0) { - std::println(stderr, "Unable to generate token"); - - return 0; - } - - if (auto rv = - ngtcp2_conn_submit_new_token(conn, token.data(), as_unsigned(tokenlen)); - rv != 0) { - std::println(stderr, "ngtcp2_conn_submit_new_token: {}", - ngtcp2_strerror(rv)); - - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} -} // namespace - -namespace { -int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, - uint64_t max_data, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - - h->extend_max_stream_data(stream_id, max_data); - - return 0; -} -} // namespace - -void Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - - if (nghttp3_buf_len(&stream->respbuf)) { - sendq_.emplace(stream.get()); - } -} - -namespace { -void write_qlog(void *user_data, uint32_t flags, const void *data, - size_t datalen) { - auto h = static_cast(user_data); - h->write_qlog(data, datalen); -} -} // namespace - -void Handler::write_qlog(const void *data, size_t datalen) { - assert(qlog_); - fwrite(data, 1, datalen, qlog_); -} - -std::expected -Handler::init(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_cid *dcid, - const ngtcp2_cid *scid, const ngtcp2_cid *ocid, - std::span token, ngtcp2_token_type token_type, - uint32_t version, TLSServerContext &tls_ctx) { - auto callbacks = ngtcp2_callbacks{ - .recv_client_initial = ngtcp2_crypto_recv_client_initial_cb, - .recv_crypto_data = ::recv_crypto_data, - .handshake_completed = ::handshake_completed, - .encrypt = ngtcp2_crypto_encrypt_cb, - .decrypt = ngtcp2_crypto_decrypt_cb, - .hp_mask = do_hp_mask, - .recv_stream_data = ::recv_stream_data, - .acked_stream_data_offset = ::acked_stream_data_offset, - .stream_open = stream_open, - .stream_close = stream_close, - .rand = rand, - .remove_connection_id = remove_connection_id, - .update_key = ::update_key, - .path_validation = path_validation, - .extend_max_stream_data = ::extend_max_stream_data, - .delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb, - .delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb, - .version_negotiation = ngtcp2_crypto_version_negotiation_cb, - .get_new_connection_id2 = get_new_connection_id, - .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, - }; - - scid_.datalen = NGTCP2_SV_SCIDLEN; - if (auto rv = util::generate_secure_random({scid_.data, scid_.datalen}); - !rv) { - std::println(stderr, "Could not generate connection ID"); - return rv; - } - - ngtcp2_settings settings; - ngtcp2_settings_default(&settings); - settings.log_printf = config.quiet ? nullptr : debug::log_printf; - settings.initial_ts = util::timestamp(); - settings.token = token.data(); - settings.tokenlen = token.size(); - settings.token_type = token_type; - settings.cc_algo = config.cc_algo; - settings.initial_rtt = config.initial_rtt; - settings.max_window = config.max_window; - settings.max_stream_window = config.max_stream_window; - settings.handshake_timeout = config.handshake_timeout; - settings.no_pmtud = config.no_pmtud; - settings.ack_thresh = config.ack_thresh; - if (config.max_udp_payload_size) { - settings.max_tx_udp_payload_size = config.max_udp_payload_size; - settings.no_tx_udp_payload_size_shaping = 1; - } - if (!config.qlog_dir.empty()) { - auto path = std::string{config.qlog_dir}; - path += '/'; - path += util::format_hex(scid_.data, as_signed(scid_.datalen)); - path += ".sqlog"; - qlog_ = fopen(path.c_str(), "w"); - if (qlog_ == nullptr) { - std::println(stderr, "Could not open qlog file {}: {}", path, - strerror(errno)); - return std::unexpected{Error::IO}; - } - settings.qlog_write = ::write_qlog; - } - if (!config.preferred_versions.empty()) { - settings.preferred_versions = config.preferred_versions.data(); - settings.preferred_versionslen = config.preferred_versions.size(); - } - if (!config.available_versions.empty()) { - settings.available_versions = config.available_versions.data(); - settings.available_versionslen = config.available_versions.size(); - } - if (config.initial_pkt_num == UINT32_MAX) { - auto dis = std::uniform_int_distribution(0, INT32_MAX); - settings.initial_pkt_num = dis(randgen); - } else { - settings.initial_pkt_num = config.initial_pkt_num; - } - - if (!config.pmtud_probes.empty()) { - settings.pmtud_probes = config.pmtud_probes.data(); - settings.pmtud_probeslen = config.pmtud_probes.size(); - - if (!config.max_udp_payload_size) { - settings.max_tx_udp_payload_size = - *std::ranges::max_element(config.pmtud_probes); - } - } - - ngtcp2_transport_params params; - ngtcp2_transport_params_default(¶ms); - params.initial_max_stream_data_bidi_local = config.max_stream_data_bidi_local; - params.initial_max_stream_data_bidi_remote = - config.max_stream_data_bidi_remote; - params.initial_max_stream_data_uni = config.max_stream_data_uni; - params.initial_max_data = config.max_data; - params.initial_max_streams_bidi = config.max_streams_bidi; - params.initial_max_streams_uni = 0; - params.max_idle_timeout = config.timeout; - params.stateless_reset_token_present = 1; - params.active_connection_id_limit = 7; - params.grease_quic_bit = 1; - - if (ocid) { - params.original_dcid = *ocid; - params.retry_scid = *scid; - params.retry_scid_present = 1; - } else { - params.original_dcid = *scid; - } - - params.original_dcid_present = 1; - - if (ngtcp2_crypto_generate_stateless_reset_token( - params.stateless_reset_token, config.static_secret.data(), - config.static_secret.size(), &scid_) != 0) { - return std::unexpected{Error::QUIC}; - } - - if (!config.preferred_ipv4_addr.empty() || - !config.preferred_ipv6_addr.empty()) { - params.preferred_addr_present = 1; - - if (!config.preferred_ipv4_addr.empty()) { - params.preferred_addr.ipv4 = - std::get(config.preferred_ipv4_addr.skaddr); - params.preferred_addr.ipv4_present = 1; - } - - if (!config.preferred_ipv6_addr.empty()) { - params.preferred_addr.ipv6 = - std::get(config.preferred_ipv6_addr.skaddr); - params.preferred_addr.ipv6_present = 1; - } - - if (auto rv = util::generate_secure_random( - params.preferred_addr.stateless_reset_token); - !rv) { - std::println( - stderr, "Could not generate preferred address stateless reset token"); - return rv; - } - - params.preferred_addr.cid.datalen = NGTCP2_SV_SCIDLEN; - if (auto rv = util::generate_secure_random( - {params.preferred_addr.cid.data, params.preferred_addr.cid.datalen}); - !rv) { - std::println(stderr, - "Could not generate preferred address connection ID"); - return rv; - } - } - - auto path = ngtcp2_path{ - .local = as_ngtcp2_addr(local_addr), - .remote = as_ngtcp2_addr(remote_addr), - .user_data = const_cast(&ep), - }; - if (auto rv = - ngtcp2_conn_server_new(&conn_, dcid, &scid_, &path, version, &callbacks, - &settings, ¶ms, nullptr, this); - rv != 0) { - std::println(stderr, "ngtcp2_conn_server_new: {}", ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = tls_session_.init(tls_ctx, this); !rv) { - return rv; - } - - tls_session_.enable_keylog(); - - ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle()); - - ev_io_set(&wev_, ep.fd, EV_WRITE); - - return {}; -} - -std::expected Handler::feed_data(const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr, - const ngtcp2_pkt_info *pi, - std::span data) { - auto path = ngtcp2_path{ - .local = as_ngtcp2_addr(local_addr), - .remote = as_ngtcp2_addr(remote_addr), - .user_data = const_cast(&ep), - }; - - if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(), - util::timestamp()); - rv != 0) { - std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); - switch (rv) { - case NGTCP2_ERR_DRAINING: - start_draining_period(); - return std::unexpected{Error::CLOSE_WAIT}; - case NGTCP2_ERR_RETRY: - return std::unexpected{Error::RETRY_CONN}; - case NGTCP2_ERR_DROP_CONN: - return std::unexpected{Error::DROP_CONN}; - case NGTCP2_ERR_CRYPTO: - if (!last_error_.error_code) { - ngtcp2_ccerr_set_tls_alert( - &last_error_, ngtcp2_conn_get_tls_alert(conn_), nullptr, 0); - } - break; - default: - if (!last_error_.error_code) { - ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); - } - } - return handle_error(); - } - - return {}; -} - -std::expected Handler::on_read(const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr, - const ngtcp2_pkt_info *pi, - std::span data) { - if (auto rv = feed_data(ep, local_addr, remote_addr, pi, data); !rv) { - return rv; - } - - update_timer(); - - return {}; -} - -std::expected Handler::handle_expiry() { - auto now = util::timestamp(); - if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) { - std::println(stderr, "ngtcp2_conn_handle_expiry: {}", ngtcp2_strerror(rv)); - ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); - return handle_error(); - } - - return {}; -} - -std::expected Handler::on_write() { - if (ngtcp2_conn_in_closing_period(conn_) || - ngtcp2_conn_in_draining_period(conn_)) { - return {}; - } - - if (tx_.send_blocked) { - send_blocked_packet(); - - if (tx_.send_blocked) { - return {}; - } - } - - ev_io_stop(loop_, &wev_); - - if (auto rv = write_streams(); !rv) { - return rv; - } - - update_timer(); - - return {}; -} - -namespace { -ngtcp2_ssize write_pkt(ngtcp2_conn *conn, ngtcp2_path *path, - ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - ngtcp2_tstamp ts, void *user_data) { - auto h = static_cast(user_data); - - return h->write_pkt(path, pi, dest, destlen, ts); -} -} // namespace - -ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, - uint8_t *dest, size_t destlen, - ngtcp2_tstamp ts) { - ngtcp2_vec vec; - - for (;;) { - int64_t stream_id = -1; - size_t vcnt = 0; - uint32_t flags = - NGTCP2_WRITE_STREAM_FLAG_MORE | NGTCP2_WRITE_STREAM_FLAG_PADDING; - Stream *stream = nullptr; - - if (!sendq_.empty() && ngtcp2_conn_get_max_data_left(conn_)) { - stream = *std::ranges::begin(sendq_); - - stream_id = stream->stream_id; - vec.base = stream->respbuf.pos; - vec.len = nghttp3_buf_len(&stream->respbuf); - vcnt = 1; - flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; - } - - ngtcp2_ssize ndatalen; - - auto nwrite = - ngtcp2_conn_writev_stream(conn_, path, pi, dest, destlen, &ndatalen, - flags, stream_id, &vec, vcnt, ts); - if (nwrite < 0) { - switch (nwrite) { - case NGTCP2_ERR_STREAM_DATA_BLOCKED: - case NGTCP2_ERR_STREAM_SHUT_WR: - assert(ndatalen == -1); - sendq_.erase(std::ranges::begin(sendq_)); - continue; - case NGTCP2_ERR_WRITE_MORE: - assert(ndatalen >= 0); - stream->respbuf.pos += ndatalen; - if (nghttp3_buf_len(&stream->respbuf) == 0) { - sendq_.erase(std::ranges::begin(sendq_)); - } - continue; - } - - assert(ndatalen == -1); - - std::println(stderr, "ngtcp2_conn_writev_stream: {}", - ngtcp2_strerror(static_cast(nwrite))); - ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, - 0); - - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - if (ndatalen >= 0) { - stream->respbuf.pos += ndatalen; - if (nghttp3_buf_len(&stream->respbuf) == 0) { - sendq_.erase(std::ranges::begin(sendq_)); - } - } - - return nwrite; - } -} - -std::expected Handler::write_streams() { - ngtcp2_path_storage ps; - ngtcp2_pkt_info pi; - size_t gso_size; - auto ts = util::timestamp(); - auto txbuf = std::span{txbuf_}; - auto buflen = util::clamp_buffer_size(conn_, txbuf.size(), config.gso_burst); - - ngtcp2_path_storage_zero(&ps); - - auto nwrite = ngtcp2_conn_write_aggregate_pkt2( - conn_, &ps.path, &pi, txbuf.data(), buflen, &gso_size, ::write_pkt, - config.gso_burst, ts); - if (nwrite < 0) { - return handle_error(); - } - - ngtcp2_conn_update_pkt_tx_time(conn_, ts); - - if (nwrite == 0) { - return {}; - } - - send_packet(ps.path, pi.ecn, txbuf.first(static_cast(nwrite)), - gso_size); - - return {}; -} - -std::expected Handler::send_packet(const ngtcp2_path &path, - unsigned int ecn, - std::span data, - size_t gso_size) { - auto &ep = *static_cast(path.user_data); - auto rest = server_->send_packet(ep, no_gso_, path.local, path.remote, ecn, - data, gso_size); - if (!rest.empty()) { - on_send_blocked(path, ecn, rest, gso_size); - - start_wev_endpoint(ep); - - return std::unexpected{Error::SEND_BLOCKED}; - } - - return {}; -} - -void Handler::on_send_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size) { - assert(!tx_.send_blocked); - assert(gso_size); - - tx_.send_blocked = true; - - auto &p = tx_.blocked; - - p.local_addr.set(path.local.addr); - p.remote_addr.set(path.remote.addr); - - p.endpoint = static_cast(path.user_data); - p.ecn = ecn; - p.data = data; - p.gso_size = gso_size; -} - -void Handler::start_wev_endpoint(const Endpoint &ep) { - // We do not close ep.fd, so we can expect that each Endpoint has - // unique fd. - if (ep.fd != wev_.fd) { - if (ev_is_active(&wev_)) { - ev_io_stop(loop_, &wev_); - } - - ev_io_set(&wev_, ep.fd, EV_WRITE); - } - - ev_io_start(loop_, &wev_); -} - -void Handler::send_blocked_packet() { - assert(tx_.send_blocked); - - auto &p = tx_.blocked; - - auto rest = server_->send_packet( - *p.endpoint, no_gso_, as_ngtcp2_addr(p.local_addr), - as_ngtcp2_addr(p.remote_addr), p.ecn, p.data, p.gso_size); - if (!rest.empty()) { - p.data = rest; - - start_wev_endpoint(*p.endpoint); - - return; - } - - tx_.send_blocked = false; -} - -void Handler::signal_write() { ev_io_start(loop_, &wev_); } - -void Handler::start_draining_period() { - ev_io_stop(loop_, &wev_); - - ev_set_cb(&timer_, close_waitcb); - timer_.repeat = - static_cast(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3; - ev_timer_again(loop_, &timer_); - - if (!config.quiet) { - std::println(stderr, "Draining period has started ({:.9f} seconds)", - timer_.repeat); - } -} - -std::expected Handler::start_closing_period() { - if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || - ngtcp2_conn_in_draining_period(conn_)) { - return {}; - } - - ev_io_stop(loop_, &wev_); - - ev_set_cb(&timer_, close_waitcb); - timer_.repeat = - static_cast(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3; - ev_timer_again(loop_, &timer_); - - if (!config.quiet) { - std::println(stderr, "Closing period has started ({:.9f} seconds)", - timer_.repeat); - } - - conn_closebuf_ = std::make_unique(NGTCP2_MAX_UDP_PAYLOAD_SIZE); - - ngtcp2_path_storage ps; - - ngtcp2_path_storage_zero(&ps); - - ngtcp2_pkt_info pi; - auto n = ngtcp2_conn_write_connection_close( - conn_, &ps.path, &pi, conn_closebuf_->wpos(), conn_closebuf_->left(), - &last_error_, util::timestamp()); - if (n < 0) { - std::println(stderr, "ngtcp2_conn_write_connection_close: {}", - ngtcp2_strerror(static_cast(n))); - return std::unexpected{Error::QUIC}; - } - - if (n == 0) { - return {}; - } - - conn_closebuf_->push(as_unsigned(n)); - - return {}; -} - -std::expected Handler::handle_error() { - if (last_error_.type == NGTCP2_CCERR_TYPE_IDLE_CLOSE) { - return std::unexpected{Error::INTERNAL}; - } - - if (auto rv = start_closing_period(); !rv) { - return rv; - } - - if (ngtcp2_conn_in_draining_period(conn_)) { - return std::unexpected{Error::CLOSE_WAIT}; - } - - if (auto rv = send_conn_close(); !rv) { - return rv; - } - - return std::unexpected{Error::CLOSE_WAIT}; -} - -std::expected Handler::send_conn_close() { - if (!config.quiet) { - std::println(stderr, "Closing Period: TX CONNECTION_CLOSE"); - } - - assert(conn_closebuf_ && conn_closebuf_->size()); - assert(conn_); - assert(!ngtcp2_conn_in_draining_period(conn_)); - - auto path = ngtcp2_conn_get_path(conn_); - - return server_->send_packet(*static_cast(path->user_data), - path->local, path->remote, - /* ecn = */ 0, conn_closebuf_->data()); -} - -std::expected -Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data) { - assert(conn_closebuf_ && conn_closebuf_->size()); - - close_wait_.bytes_recv += data.size(); - ++close_wait_.num_pkts_recv; - - if (close_wait_.num_pkts_recv < close_wait_.next_pkts_recv || - close_wait_.bytes_recv * 3 < - close_wait_.bytes_sent + conn_closebuf_->size()) { - return {}; - } - - if (auto rv = server_->send_packet(ep, as_ngtcp2_addr(local_addr), - as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, conn_closebuf_->data()); - !rv) { - return rv; - } - - close_wait_.bytes_sent += conn_closebuf_->size(); - close_wait_.next_pkts_recv *= 2; - - return {}; -} - -void Handler::update_timer() { - auto expiry = ngtcp2_conn_get_expiry(conn_); - auto now = util::timestamp(); - - if (expiry <= now) { - if (!config.quiet) { - auto t = static_cast(now - expiry) / NGTCP2_SECONDS; - std::println(stderr, "Timer has already expired: {:.9f}s", t); - } - - ev_feed_event(loop_, &timer_, EV_TIMER); - - return; - } - - auto t = static_cast(expiry - now) / NGTCP2_SECONDS; - if (!config.quiet) { - std::println(stderr, "Set timer={:.9f}s", t); - } - timer_.repeat = t; - ev_timer_again(loop_, &timer_); -} - -namespace { -int on_msg_begin(http_parser *htp) { - auto s = static_cast(htp->data); - if (s->eos) { - return -1; - } - return 0; -} -} // namespace - -namespace { -int on_url_cb(http_parser *htp, const char *data, size_t datalen) { - auto s = static_cast(htp->data); - s->uri.append(data, datalen); - return 0; -} -} // namespace - -namespace { -int on_msg_complete(http_parser *htp) { - auto s = static_cast(htp->data); - s->eos = true; - s->start_response(); - return 0; -} -} // namespace - -auto htp_settings = http_parser_settings{ - .on_message_begin = on_msg_begin, - .on_url = on_url_cb, - .on_message_complete = on_msg_complete, -}; - -std::expected -Handler::recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data) { - if (!config.quiet && !config.no_quic_dump) { - debug::print_stream_data(stream_id, data); - } - - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - - if (!stream->eos) { - auto nread = http_parser_execute( - &stream->htp, &htp_settings, reinterpret_cast(data.data()), - data.size()); - if (nread != data.size()) { - if (auto rv = ngtcp2_conn_shutdown_stream(conn_, 0, stream_id, - /* app error code */ 1); - rv != 0) { - std::println(stderr, "ngtcp2_conn_shutdown_stream: {}", - ngtcp2_strerror(rv)); - ngtcp2_ccerr_set_liberr(&last_error_, NGTCP2_ERR_INTERNAL, nullptr, 0); - return std::unexpected{Error::QUIC}; - } - } - } - - ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, data.size()); - ngtcp2_conn_extend_max_offset(conn_, data.size()); - - return {}; -} - -std::expected -Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen) { - auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); - auto aead = &crypto_ctx->aead; - auto keylen = ngtcp2_crypto_aead_keylen(aead); - auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); - - ++nkey_update_; - - std::array rx_key, tx_key; - - if (ngtcp2_crypto_update_key(conn_, rx_secret, tx_secret, rx_aead_ctx, - rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), - tx_iv, current_rx_secret, current_tx_secret, - secretlen) != 0) { - return std::unexpected{Error::QUIC}; - } - - if (!config.quiet && config.show_secret) { - std::println(stderr, "application_traffic rx secret {}", nkey_update_); - debug::print_secrets({rx_secret, secretlen}, {rx_key.data(), keylen}, - {rx_iv, ivlen}); - std::println(stderr, "application_traffic tx secret {}", nkey_update_); - debug::print_secrets({tx_secret, secretlen}, {tx_key.data(), keylen}, - {tx_iv, ivlen}); - } - - return {}; -} - -Server *Handler::server() const { return server_; } - -void Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) { - if (!config.quiet) { - std::println(stderr, "QUIC stream {:#x} closed", stream_id); - } - - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - - sendq_.erase(stream.get()); - - if (!config.quiet) { - std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", - stream_id, app_error_code); - } - - streams_.erase(it); - - if (ngtcp2_is_bidi_stream(stream_id)) { - assert(!ngtcp2_conn_is_local_stream(conn_, stream_id)); - ngtcp2_conn_extend_max_streams_bidi(conn_, 1); - } -} - -void Handler::shutdown_read(int64_t stream_id, uint64_t app_error_code) { - ngtcp2_conn_shutdown_stream_read(conn_, 0, stream_id, app_error_code); -} - -void Handler::add_sendq(Stream *stream) { sendq_.emplace(stream); } - -namespace { -void sreadcb(struct ev_loop *loop, ev_io *w, int revents) { - auto ep = static_cast(w->data); - - ep->server->on_read(*ep); -} -} // namespace - -namespace { -void siginthandler(struct ev_loop *loop, ev_signal *watcher, int revents) { - ev_break(loop, EVBREAK_ALL); -} -} // namespace - -Server::Server(struct ev_loop *loop, TLSServerContext &tls_ctx) - : loop_{loop}, tls_ctx_{tls_ctx} { - ev_signal_init(&sigintev_, siginthandler, SIGINT); - - ev_timer_init( - &stateless_reset_regen_timer_, - [](struct ev_loop *loop, ev_timer *w, int revents) { - auto server = static_cast(w->data); - - server->on_stateless_reset_regen(); - }, - 0., 1.); - stateless_reset_regen_timer_.data = this; -} - -Server::~Server() { - disconnect(); - close(); -} - -void Server::disconnect() { - config.tx_loss_prob = 0; - - for (auto &ep : endpoints_) { - ev_io_stop(loop_, &ep.rev); - } - - ev_timer_stop(loop_, &stateless_reset_regen_timer_); - ev_signal_stop(loop_, &sigintev_); - - while (!handlers_.empty()) { - auto it = std::ranges::begin(handlers_); - auto &h = (*it).second; - - h->handle_error(); - - remove(h); - } -} - -void Server::close() { - for (auto &ep : endpoints_) { - ::close(ep.fd); - } - - endpoints_.clear(); -} - -namespace { -std::expected create_sock(Address &local_addr, const char *addr, - const char *port, int family) { - addrinfo hints{ - .ai_flags = AI_PASSIVE, - .ai_family = family, - .ai_socktype = SOCK_DGRAM, - }; - addrinfo *res, *rp; - int val = 1; - - if (strcmp(addr, "*") == 0) { - addr = nullptr; - } - - if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) { - std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - auto res_d = defer([res] { freeaddrinfo(res); }); - - int fd = -1; - - for (rp = res; rp; rp = rp->ai_next) { - auto maybe_fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (!maybe_fd) { - continue; - } - - fd = *maybe_fd; - - if (rp->ai_family == AF_INET6) { - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, - static_cast(sizeof(val))) == -1) { - close(fd); - continue; - } - - if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, - static_cast(sizeof(val))) == -1) { - close(fd); - continue; - } - } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val, - static_cast(sizeof(val))) == -1) { - close(fd); - continue; - } - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, - static_cast(sizeof(val))) == -1) { - close(fd); - continue; - } - - fd_set_recv_ecn(fd, rp->ai_family); - fd_set_ip_mtu_discover(fd, rp->ai_family); - fd_set_ip_dontfrag(fd, family); - fd_set_udp_gro(fd); - - if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1) { - break; - } - - close(fd); - } - - if (!rp) { - std::println(stderr, "Could not bind"); - return std::unexpected{Error::SYSCALL}; - } - - sockaddr_storage ss; - socklen_t len = sizeof(ss); - if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::println(stderr, "getsockname: {}", strerror(errno)); - close(fd); - return std::unexpected{Error::SYSCALL}; - } - - local_addr.set(reinterpret_cast(&ss)); - - return fd; -} - -} // namespace - -namespace { -std::expected add_endpoint(std::vector &endpoints, - const char *addr, const char *port, - int af) { - Address dest; - auto maybe_fd = create_sock(dest, addr, port, af); - if (!maybe_fd) { - return std::unexpected{maybe_fd.error()}; - } - - endpoints.emplace_back(); - auto &ep = endpoints.back(); - ep.addr = dest; - ep.fd = *maybe_fd; - ev_io_init(&ep.rev, sreadcb, 0, EV_READ); - ev_set_priority(&ep.rev, EV_MAXPRI); - - return {}; -} -} // namespace - -namespace { -std::expected add_endpoint(std::vector &endpoints, - const Address &addr) { - auto family = addr.family(); - - auto maybe_fd = util::create_nonblock_socket(family, SOCK_DGRAM, 0); - if (!maybe_fd) { - std::println(stderr, "socket: {}", strerror(errno)); - return std::unexpected{maybe_fd.error()}; - } - - auto fd = *maybe_fd; - - int val = 1; - if (family == AF_INET6) { - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, - static_cast(sizeof(val))) == -1) { - std::println(stderr, "setsockopt: {}", strerror(errno)); - close(fd); - return std::unexpected{Error::SYSCALL}; - } - - if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, - static_cast(sizeof(val))) == -1) { - std::println(stderr, "setsockopt: {}", strerror(errno)); - close(fd); - return std::unexpected{Error::SYSCALL}; - } - } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val, - static_cast(sizeof(val))) == -1) { - std::println(stderr, "setsockopt: {}", strerror(errno)); - close(fd); - return std::unexpected{Error::SYSCALL}; - } - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, - static_cast(sizeof(val))) == -1) { - close(fd); - return std::unexpected{Error::SYSCALL}; - } - - fd_set_recv_ecn(fd, family); - fd_set_ip_mtu_discover(fd, family); - fd_set_ip_dontfrag(fd, family); - fd_set_udp_gro(fd); - - if (bind(fd, addr.as_sockaddr(), addr.size()) == -1) { - std::println(stderr, "bind: {}", strerror(errno)); - close(fd); - return std::unexpected{Error::SYSCALL}; - } - - endpoints.emplace_back(Endpoint{}); - auto &ep = endpoints.back(); - ep.addr = addr; - ep.fd = fd; - ev_io_init(&ep.rev, sreadcb, 0, EV_READ); - ev_set_priority(&ep.rev, EV_MAXPRI); - - return {}; -} -} // namespace - -std::expected Server::init(const char *addr, const char *port) { - endpoints_.reserve(4); - - auto ready = false; - auto error = Error::INTERNAL; - - if (!util::numeric_host(addr, AF_INET6)) { - if (auto rv = add_endpoint(endpoints_, addr, port, AF_INET); !rv) { - error = rv.error(); - } else { - ready = true; - } - } - if (!util::numeric_host(addr, AF_INET)) { - if (auto rv = add_endpoint(endpoints_, addr, port, AF_INET6); !rv) { - error = rv.error(); - } else { - ready = true; - } - } - if (!ready) { - return std::unexpected{error}; - } - - if (!config.preferred_ipv4_addr.empty()) { - if (auto rv = add_endpoint(endpoints_, config.preferred_ipv4_addr); !rv) { - return rv; - } - } - - if (!config.preferred_ipv6_addr.empty()) { - if (auto rv = add_endpoint(endpoints_, config.preferred_ipv6_addr); !rv) { - return rv; - } - } - - for (auto &ep : endpoints_) { - ep.server = this; - ep.rev.data = &ep; - - ev_io_set(&ep.rev, ep.fd, EV_READ); - - ev_io_start(loop_, &ep.rev); - } - - ev_signal_start(loop_, &sigintev_); - - return {}; -} - -void Server::on_read(const Endpoint &ep) { - sockaddr_storage ss; - std::array buf; - size_t pktcnt = 0; - ngtcp2_pkt_info pi; - - iovec msg_iov{ - .iov_base = buf.data(), - .iov_len = buf.size(), - }; - - uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo)) + - CMSG_SPACE(sizeof(int))]; - - msghdr msg{ - .msg_name = &ss, - .msg_iov = &msg_iov, - .msg_iovlen = 1, - .msg_control = msg_ctrl, - }; - - auto start = util::timestamp(); - - for (; pktcnt < MAX_RECV_PKTS;) { - if (util::recv_pkt_time_threshold_exceeded( - config.cc_algo == NGTCP2_CC_ALGO_BBR, start, pktcnt)) { - return; - } - - msg.msg_namelen = sizeof(ss); - msg.msg_controllen = sizeof(msg_ctrl); - - auto nread = recvmsg(ep.fd, &msg, 0); - if (nread == -1) { - if (!(errno == EAGAIN || errno == ENOTCONN)) { - std::println(stderr, "recvmsg: {}", strerror(errno)); - } - return; - } - - // Packets less than 21 bytes never be a valid QUIC packet. - if (nread < 21) { - ++pktcnt; - - continue; - } - - Address remote_addr; - remote_addr.set(reinterpret_cast(&ss)); - - if (util::prohibited_port(remote_addr.port())) { - ++pktcnt; - - continue; - } - - pi.ecn = msghdr_get_ecn(&msg, ss.ss_family); - auto local_addr = msghdr_get_local_addr(&msg, ss.ss_family); - if (!local_addr) { - ++pktcnt; - std::println(stderr, "Unable to obtain local address"); - continue; - } - - auto gso_size = msghdr_get_udp_gro(&msg); - if (gso_size == 0) { - gso_size = static_cast(nread); - } - - local_addr->port(ep.addr.port()); - - auto data = std::span{buf.data(), static_cast(nread)}; - - for (; !data.empty();) { - auto datalen = std::min(data.size(), gso_size); - - ++pktcnt; - - if (!config.quiet) { - std::array ifname; - std::println( - stderr, - "Received packet: local={} remote={} if={} ecn={:#x} {} bytes", - util::straddr(*local_addr), util::straddr(remote_addr), - if_indextoname(local_addr->ifindex, ifname.data()), pi.ecn, datalen); - } - - // Packets less than 21 bytes never be a valid QUIC packet. - if (datalen < 21) { - break; - } - - if (debug::packet_lost(config.rx_loss_prob)) { - if (!config.quiet) { - std::println(stderr, "** Simulated incoming packet loss **"); - } - } else { - read_pkt(ep, *local_addr, remote_addr, &pi, {data.data(), datalen}); - } - - data = data.subspan(datalen); - } - } -} - -void Server::read_pkt(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data) { - ngtcp2_version_cid vc; - - switch (auto rv = ngtcp2_pkt_decode_version_cid(&vc, data.data(), data.size(), - NGTCP2_SV_SCIDLEN); - rv) { - case 0: - break; - case NGTCP2_ERR_VERSION_NEGOTIATION: - send_version_negotiation(vc.version, {vc.scid, vc.scidlen}, - {vc.dcid, vc.dcidlen}, ep, local_addr, - remote_addr); - return; - default: - std::println(stderr, - "Could not decode version and CID from QUIC packet header: {}", - ngtcp2_strerror(rv)); - return; - } - - auto dcid_key = util::make_cid_key({vc.dcid, vc.dcidlen}); - - auto handler_it = handlers_.find(dcid_key); - if (handler_it == std::ranges::end(handlers_)) { - ngtcp2_pkt_hd hd; - - if (auto rv = ngtcp2_accept(&hd, data.data(), data.size()); rv != 0) { - if (!config.quiet) { - std::println(stderr, "Unexpected packet received: length={}", - data.size()); - } - - if (!(data[0] & 0x80) && data.size() >= NGTCP2_SV_SCIDLEN + 21) { - send_stateless_reset(data.size(), {vc.dcid, vc.dcidlen}, ep, local_addr, - remote_addr); - } - - return; - } - - ngtcp2_cid ocid; - ngtcp2_cid *pocid = nullptr; - ngtcp2_token_type token_type = NGTCP2_TOKEN_TYPE_UNKNOWN; - - assert(hd.type == NGTCP2_PKT_INITIAL); - - if (config.validate_addr || hd.tokenlen) { - std::println(stderr, "Perform stateless address validation"); - if (hd.tokenlen == 0) { - send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); - return; - } - - if (hd.token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 && - hd.dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN) { - send_stateless_connection_close(&hd, ep, local_addr, remote_addr); - return; - } - - switch (hd.token[0]) { - case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2: - if (auto rv = verify_retry_token(&ocid, &hd, remote_addr); !rv) { - if (rv.error() != Error::UNREADABLE_TOKEN) { - send_stateless_connection_close(&hd, ep, local_addr, remote_addr); - - return; - } - - hd.token = nullptr; - hd.tokenlen = 0; - } else { - pocid = &ocid; - token_type = NGTCP2_TOKEN_TYPE_RETRY; - } - - break; - case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR: - if (!verify_token(&hd, remote_addr)) { - if (config.validate_addr) { - send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); - return; - } - - hd.token = nullptr; - hd.tokenlen = 0; - } else { - token_type = NGTCP2_TOKEN_TYPE_NEW_TOKEN; - } - break; - default: - if (!config.quiet) { - std::println(stderr, "Ignore unrecognized token"); - } - if (config.validate_addr) { - send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); - return; - } - - hd.token = nullptr; - hd.tokenlen = 0; - break; - } - } - - auto h = std::make_unique(loop_, this); - if (!h->init(ep, local_addr, remote_addr, &hd.scid, &hd.dcid, pocid, - {hd.token, hd.tokenlen}, token_type, hd.version, tls_ctx_)) { - return; - } - - if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); !rv) { - if (rv.error() == Error::RETRY_CONN) { - send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); - } - - return; - } - - if (!h->on_write()) { - return; - } - - std::array scids; - auto conn = h->conn(); - - auto num_scid = ngtcp2_conn_get_scid(conn, nullptr); - - assert(num_scid <= scids.size()); - - ngtcp2_conn_get_scid(conn, scids.data()); - - for (size_t i = 0; i < num_scid; ++i) { - associate_cid(&scids[i], h.get()); - } - - handlers_.emplace(dcid_key, h.release()); - - return; - } - - auto h = (*handler_it).second; - auto conn = h->conn(); - if (ngtcp2_conn_in_closing_period(conn)) { - if (!h->send_conn_close(ep, local_addr, remote_addr, pi, data)) { - remove(h); - } - return; - } - if (ngtcp2_conn_in_draining_period(conn)) { - return; - } - - if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); !rv) { - if (rv.error() != Error::CLOSE_WAIT) { - remove(h); - } - return; - } - - h->signal_write(); -} - -namespace { -uint32_t generate_reserved_version(const Address &addr, uint32_t version) { - uint32_t h = 0x811C9DC5U; - const uint8_t *p = reinterpret_cast(addr.as_sockaddr()); - const uint8_t *ep = p + addr.size(); - for (; p != ep; ++p) { - h ^= *p; - h *= 0x01000193U; - } - version = htonl(version); - p = (const uint8_t *)&version; - ep = p + sizeof(version); - for (; p != ep; ++p) { - h ^= *p; - h *= 0x01000193U; - } - h &= 0xF0F0F0F0U; - h |= 0x0A0A0A0AU; - return h; -} -} // namespace - -std::expected Server::send_version_negotiation( - uint32_t version, std::span dcid, - std::span scid, const Endpoint &ep, const Address &local_addr, - const Address &remote_addr) { - Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; - std::array sv; - - auto p = std::ranges::begin(sv); - - *p++ = generate_reserved_version(remote_addr, version); - - if (config.preferred_versions.empty()) { - *p++ = NGTCP2_PROTO_VER_V1; - } else { - for (auto v : config.preferred_versions) { - *p++ = v; - } - } - - auto nwrite = ngtcp2_pkt_write_version_negotiation( - buf.wpos(), buf.left(), std::uniform_int_distribution()(randgen), - dcid.data(), dcid.size(), scid.data(), scid.size(), sv.data(), - as_unsigned(p - std::ranges::begin(sv))); - if (nwrite < 0) { - std::println(stderr, "ngtcp2_pkt_write_version_negotiation: {}", - ngtcp2_strerror(static_cast(nwrite))); - return std::unexpected{Error::QUIC}; - } - - buf.push(as_unsigned(nwrite)); - - return send_packet(ep, as_ngtcp2_addr(local_addr), - as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()); -} - -std::expected Server::send_retry(const ngtcp2_pkt_hd *chd, - const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr, - size_t max_pktlen) { - std::array host; - std::array port; - - if (auto rv = getnameinfo(remote_addr.as_sockaddr(), remote_addr.size(), - host.data(), host.size(), port.data(), port.size(), - NI_NUMERICHOST | NI_NUMERICSERV); - rv != 0) { - std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - if (!config.quiet) { - std::println(stderr, "Sending Retry packet to [{}]:{}", host.data(), - port.data()); - } - - ngtcp2_cid scid; - - scid.datalen = NGTCP2_SV_SCIDLEN; - if (auto rv = util::generate_secure_random({scid.data, scid.datalen}); !rv) { - return rv; - } - - std::array tokenbuf; - - auto t = util::system_clock_now(); - - auto tokenlen = ngtcp2_crypto_generate_retry_token2( - tokenbuf.data(), config.static_secret.data(), config.static_secret.size(), - chd->version, remote_addr.as_sockaddr(), remote_addr.size(), &scid, - &chd->dcid, t); - if (tokenlen < 0) { - return std::unexpected{Error::QUIC}; - } - - auto token = std::span{tokenbuf}.first(as_unsigned(tokenlen)); - - if (!config.quiet) { - std::println(stderr, "Generated address validation token:"); - util::hexdump(stderr, token); - } - - Buffer buf{ - std::min(static_cast(NGTCP2_MAX_UDP_PAYLOAD_SIZE), max_pktlen)}; - - auto nwrite = - ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version, &chd->scid, - &scid, &chd->dcid, token.data(), token.size()); - if (nwrite < 0) { - std::println(stderr, "ngtcp2_crypto_write_retry failed"); - return std::unexpected{Error::QUIC}; - } - - buf.push(as_unsigned(nwrite)); - - return send_packet(ep, as_ngtcp2_addr(local_addr), - as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()); -} - -std::expected Server::send_stateless_connection_close( - const ngtcp2_pkt_hd *chd, const Endpoint &ep, const Address &local_addr, - const Address &remote_addr) { - Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; - - auto nwrite = ngtcp2_crypto_write_connection_close( - buf.wpos(), buf.left(), chd->version, &chd->scid, &chd->dcid, - NGTCP2_INVALID_TOKEN, nullptr, 0); - if (nwrite < 0) { - std::println(stderr, "ngtcp2_crypto_write_connection_close failed"); - return std::unexpected{Error::QUIC}; - } - - buf.push(as_unsigned(nwrite)); - - return send_packet(ep, as_ngtcp2_addr(local_addr), - as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()); -} - -std::expected -Server::send_stateless_reset(size_t pktlen, std::span dcid, - const Endpoint &ep, const Address &local_addr, - const Address &remote_addr) { - if (stateless_reset_bucket_ == 0) { - return {}; - } - - --stateless_reset_bucket_; - - if (!ev_is_active(&stateless_reset_regen_timer_)) { - ev_timer_again(loop_, &stateless_reset_regen_timer_); - } - - ngtcp2_cid cid; - - ngtcp2_cid_init(&cid, dcid.data(), dcid.size()); - - ngtcp2_stateless_reset_token token; - - if (ngtcp2_crypto_generate_stateless_reset_token( - token.data, config.static_secret.data(), config.static_secret.size(), - &cid) != 0) { - return std::unexpected{Error::QUIC}; - } - - // SCID + minimum expansion - NGTCP2_STATELESS_RESET_TOKENLEN - constexpr size_t max_rand_byteslen = - NGTCP2_MAX_CIDLEN + 22 - NGTCP2_STATELESS_RESET_TOKENLEN; - - size_t rand_byteslen; - - if (pktlen <= 43) { - // As per - // https://datatracker.ietf.org/doc/html/rfc9000#section-10.3 - rand_byteslen = pktlen - NGTCP2_STATELESS_RESET_TOKENLEN - 1; - } else { - rand_byteslen = max_rand_byteslen; - } - - std::array rand_bytes; - - if (auto rv = - util::generate_secure_random({rand_bytes.data(), rand_byteslen}); - !rv) { - return rv; - } - - Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; - - auto nwrite = ngtcp2_pkt_write_stateless_reset2( - buf.wpos(), buf.left(), &token, rand_bytes.data(), rand_byteslen); - if (nwrite < 0) { - std::println(stderr, "ngtcp2_pkt_write_stateless_reset2: {}", - ngtcp2_strerror(static_cast(nwrite))); - - return std::unexpected{Error::QUIC}; - } - - buf.push(as_unsigned(nwrite)); - - return send_packet(ep, as_ngtcp2_addr(local_addr), - as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()); -} - -std::expected -Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, - const Address &remote_addr) { - int rv; - - if (!config.quiet) { - std::array host; - std::array port; - - if (auto rv = getnameinfo(remote_addr.as_sockaddr(), remote_addr.size(), - host.data(), host.size(), port.data(), - port.size(), NI_NUMERICHOST | NI_NUMERICSERV); - rv != 0) { - std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - std::println(stderr, "Verifying Retry token from [{}]:{}", host.data(), - port.data()); - util::hexdump(stderr, {hd->token, hd->tokenlen}); - } - - auto t = util::system_clock_now(); - - rv = ngtcp2_crypto_verify_retry_token2( - ocid, hd->token, hd->tokenlen, config.static_secret.data(), - config.static_secret.size(), hd->version, remote_addr.as_sockaddr(), - remote_addr.size(), &hd->dcid, 10 * NGTCP2_SECONDS, t); - switch (rv) { - case 0: - break; - case NGTCP2_CRYPTO_ERR_VERIFY_TOKEN: - std::println(stderr, "Could not verify Retry token"); - - return std::unexpected{Error::QUIC}; - default: - std::println(stderr, - "Could not read Retry token. Continue without the token"); - - return std::unexpected{Error::UNREADABLE_TOKEN}; - } - - if (!config.quiet) { - std::println(stderr, "Token was successfully validated"); - } - - return {}; -} - -std::expected Server::verify_token(const ngtcp2_pkt_hd *hd, - const Address &remote_addr) { - std::array host; - std::array port; - - if (auto rv = getnameinfo(remote_addr.as_sockaddr(), remote_addr.size(), - host.data(), host.size(), port.data(), port.size(), - NI_NUMERICHOST | NI_NUMERICSERV); - rv != 0) { - std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - if (!config.quiet) { - std::println(stderr, "Verifying token from [{}]:{}", host.data(), - port.data()); - util::hexdump(stderr, {hd->token, hd->tokenlen}); - } - - auto t = util::system_clock_now(); - - if (ngtcp2_crypto_verify_regular_token( - hd->token, hd->tokenlen, config.static_secret.data(), - config.static_secret.size(), remote_addr.as_sockaddr(), - remote_addr.size(), 3600 * NGTCP2_SECONDS, t) != 0) { - std::println(stderr, "Could not verify token"); - - return std::unexpected{Error::QUIC}; - } - - if (!config.quiet) { - std::println(stderr, "Token was successfully validated"); - } - - return {}; -} - -std::expected Server::send_packet(const Endpoint &ep, - const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, - unsigned int ecn, - std::span data) { - auto no_gso = false; - auto rest = - send_packet(ep, no_gso, local_addr, remote_addr, ecn, data, data.size()); - if (!rest.empty()) { - return std::unexpected{Error::SEND_BLOCKED}; - } - - return {}; -} - -std::span Server::send_packet(const Endpoint &ep, bool &no_gso, - const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, - unsigned int ecn, - std::span data, - size_t gso_size) { - assert(gso_size); - - if (debug::packet_lost(config.tx_loss_prob)) { - if (!config.quiet) { - std::println(stderr, "** Simulated outgoing packet loss **"); - } - return {}; - } - - if (no_gso && data.size() > gso_size) { - for (; !data.empty();) { - auto len = std::min(gso_size, data.size()); - - auto rest = send_packet(ep, no_gso, local_addr, remote_addr, ecn, - data.first(len), len); - if (!rest.empty()) { - assert(rest.size() == len); - - return data; - } - - data = data.subspan(len); - } - - return {}; - } - - iovec msg_iov{ - .iov_base = const_cast(data.data()), - .iov_len = data.size(), - }; - - uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(uint16_t)) + - CMSG_SPACE(sizeof(in6_pktinfo))]{}; - - msghdr msg{ - .msg_name = const_cast(remote_addr.addr), - .msg_namelen = remote_addr.addrlen, - .msg_iov = &msg_iov, - .msg_iovlen = 1, - .msg_control = msg_ctrl, - .msg_controllen = sizeof(msg_ctrl), - }; - - size_t controllen = 0; - - auto cm = CMSG_FIRSTHDR(&msg); - - switch (local_addr.addr->sa_family) { - case AF_INET: { - controllen += CMSG_SPACE(sizeof(in_pktinfo)); - cm->cmsg_level = IPPROTO_IP; - cm->cmsg_type = IP_PKTINFO; - cm->cmsg_len = CMSG_LEN(sizeof(in_pktinfo)); - auto addrin = reinterpret_cast(local_addr.addr); - in_pktinfo pktinfo{ - .ipi_spec_dst = addrin->sin_addr, - }; - memcpy(CMSG_DATA(cm), &pktinfo, sizeof(pktinfo)); - - break; - } - case AF_INET6: { - controllen += CMSG_SPACE(sizeof(in6_pktinfo)); - cm->cmsg_level = IPPROTO_IPV6; - cm->cmsg_type = IPV6_PKTINFO; - cm->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo)); - auto addrin = reinterpret_cast(local_addr.addr); - in6_pktinfo pktinfo{ - .ipi6_addr = addrin->sin6_addr, - }; - memcpy(CMSG_DATA(cm), &pktinfo, sizeof(pktinfo)); - - break; - } - default: - assert(0); - } - -#ifdef UDP_SEGMENT - if (data.size() > gso_size) { - controllen += CMSG_SPACE(sizeof(uint16_t)); - cm = CMSG_NXTHDR(&msg, cm); - cm->cmsg_level = SOL_UDP; - cm->cmsg_type = UDP_SEGMENT; - cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); - auto n = static_cast(gso_size); - memcpy(CMSG_DATA(cm), &n, sizeof(n)); - } -#endif // defined(UDP_SEGMENT) - - controllen += CMSG_SPACE(sizeof(int)); - cm = CMSG_NXTHDR(&msg, cm); - cm->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cm), &ecn, sizeof(ecn)); - - switch (local_addr.addr->sa_family) { - case AF_INET: - cm->cmsg_level = IPPROTO_IP; - cm->cmsg_type = IP_TOS; - - break; - case AF_INET6: - cm->cmsg_level = IPPROTO_IPV6; - cm->cmsg_type = IPV6_TCLASS; - - break; - default: - assert(0); - } - - msg.msg_controllen = -#ifndef __APPLE__ - controllen -#else // defined(__APPLE__) - static_cast(controllen) -#endif // defined(__APPLE__) - ; - - ssize_t nwrite = 0; - - do { - nwrite = sendmsg(ep.fd, &msg, 0); - } while (nwrite == -1 && errno == EINTR); - - if (nwrite == -1) { - switch (errno) { - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif // EAGAIN != EWOULDBLOCK - return data; -#ifdef UDP_SEGMENT - case EIO: - if (data.size() > gso_size) { - // GSO failure; send each packet in a separate sendmsg call. - std::println(stderr, "sendmsg: disabling GSO due to {}", - strerror(errno)); - - no_gso = true; - - return send_packet(ep, no_gso, local_addr, remote_addr, ecn, data, - gso_size); - } - break; -#endif // defined(UDP_SEGMENT) - } - - std::println(stderr, "sendmsg: {}", strerror(errno)); - // TODO We have packet which is expected to fail to send (e.g., - // path validation to old path). - return {}; - } - - if (!config.quiet) { - std::println(stderr, "Sent packet: local={} remote={} ecn={:#x} {} bytes", - util::straddr(local_addr.addr, local_addr.addrlen), - util::straddr(remote_addr.addr, remote_addr.addrlen), ecn, - nwrite); - } - - return {}; -} - -void Server::associate_cid(const ngtcp2_cid *cid, Handler *h) { - handlers_.emplace(*cid, h); -} - -void Server::dissociate_cid(const ngtcp2_cid *cid) { handlers_.erase(*cid); } - -void Server::remove(const Handler *h) { - auto conn = h->conn(); - - dissociate_cid(ngtcp2_conn_get_client_initial_dcid(conn)); - - std::vector cids(ngtcp2_conn_get_scid(conn, nullptr)); - ngtcp2_conn_get_scid(conn, cids.data()); - - for (auto &cid : cids) { - dissociate_cid(&cid); - } - - delete h; -} - -void Server::on_stateless_reset_regen() { - assert(stateless_reset_bucket_ < NGTCP2_STATELESS_RESET_BURST); - - if (++stateless_reset_bucket_ == NGTCP2_STATELESS_RESET_BURST) { - ev_timer_stop(loop_, &stateless_reset_regen_timer_); - } -} - -namespace { -std::expected parse_host_port(int af, - std::string_view host_port) { - if (host_port.empty()) { - return std::unexpected{Error::INVALID_ARGUMENT}; - } - - auto first = std::ranges::begin(host_port); - auto last = std::ranges::end(host_port); - - std::string_view hostv; - - if (*first == '[') { - ++first; - - auto it = std::ranges::find(first, last, ']'); - if (it == last) { - return std::unexpected{Error::INVALID_ARGUMENT}; - } - - hostv = std::string_view{first, it}; - first = it + 1; - - if (first == last || *first != ':') { - return std::unexpected{Error::INVALID_ARGUMENT}; - } - } else { - auto it = std::ranges::find(first, last, ':'); - if (it == last) { - return std::unexpected{Error::INVALID_ARGUMENT}; - } - - hostv = std::string_view{first, it}; - first = it; - } - - if (++first == last) { - return std::unexpected{Error::INVALID_ARGUMENT}; - } - - std::array host; - *std::ranges::copy(hostv, std::ranges::begin(host)).out = '\0'; - - addrinfo hints{ - .ai_family = af, - .ai_socktype = SOCK_DGRAM, - }; - addrinfo *res; - auto svc = first; - - if (auto rv = getaddrinfo(host.data(), svc, &hints, &res); rv != 0) { - std::println(stderr, "getaddrinfo: [{}]:{}: {}", host.data(), svc, - gai_strerror(rv)); - return std::unexpected{Error::LIBC}; - } - - Address dest; - dest.set(res->ai_addr); - - freeaddrinfo(res); - - return dest; -} -} // namespace - -namespace { -const char *prog = "h09server"; -} // namespace - -namespace { -void print_usage(FILE *out) { - std::println( - out, - "Usage: {} [OPTIONS] ", - prog); -} -} // namespace - -namespace { -void print_help() { - print_usage(stdout); - - Config config; - - std::cout << R"( - Address to listen to. '*' binds to any address. - Port - - Path to private key file - - Path to certificate file -Options: - -t, --tx-loss=

- The probability of losing outgoing packets.

must be - [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0 - means 100% packet loss. - -r, --rx-loss=

- The probability of losing incoming packets.

must be - [0.0, 1.0], inclusive. 0.0 means no packet loss. 1.0 - means 100% packet loss. - --ciphers= - Specify the cipher suite list to enable. - Default: )" - << config.ciphers << R"( - --groups= - Specify the supported groups. - Default: )" - << config.groups << R"( - -d, --htdocs= - Specify document root. If this option is not specified, - the document root is the current working directory. - -q, --quiet Suppress debug output. - -s, --show-secret - Print out secrets unless --quiet is used. - --timeout= - Specify idle timeout. - Default: )" - << util::format_duration(config.timeout) << R"( - -V, --validate-addr - Perform address validation. - --preferred-ipv4-addr=: - Specify preferred IPv4 address and port. - --preferred-ipv6-addr=: - Specify preferred IPv6 address and port. A numeric IPv6 - address must be enclosed by '[' and ']' (e.g., - [::1]:8443) - --mime-types-file= - Path to file that contains MIME media types and the - extensions. - Default: )" - << config.mime_types_file << R"( - --early-response - Start sending response when it receives HTTP header - fields without waiting for request body. If HTTP - response data is written before receiving request body, - STOP_SENDING is sent. - --verify-client - Request a client certificate. At the moment, we just - request a certificate and no verification is done. - --qlog-dir= - Path to the directory where qlog file is stored. The - file name of each qlog is the Source Connection ID of - server. - --no-quic-dump - Disables printing QUIC STREAM and CRYPTO frame data out. - --no-http-dump - Disables printing HTTP response body out. - --max-data= - The initial connection-level flow control window. - Default: )" - << util::format_uint_iec(config.max_data) << R"( - --max-stream-data-bidi-local= - The initial stream-level flow control window for a - bidirectional stream that the local endpoint initiates. - Default: )" - << util::format_uint_iec(config.max_stream_data_bidi_local) << R"( - --max-stream-data-bidi-remote= - The initial stream-level flow control window for a - bidirectional stream that the remote endpoint initiates. - Default: )" - << util::format_uint_iec(config.max_stream_data_bidi_remote) << R"( - --max-stream-data-uni= - The initial stream-level flow control window for a - unidirectional stream. - Default: )" - << util::format_uint_iec(config.max_stream_data_uni) << R"( - --max-streams-bidi= - The number of the concurrent bidirectional streams that - the remote endpoint initiates. - Default: )" - << config.max_streams_bidi << R"( - --max-streams-uni= - The number of the concurrent unidirectional streams that - the remote endpoint initiates. - Default: )" - << config.max_streams_uni << R"( - --max-dyn-length= - The maximum length of a dynamically generated content. - Default: )" - << util::format_uint_iec(config.max_dyn_length) << R"( - --cc=(cubic|reno|bbr) - The name of congestion controller algorithm. - Default: )" - << util::strccalgo(config.cc_algo) << R"( - --initial-rtt= - Set an initial RTT. - Default: )" - << util::format_duration(config.initial_rtt) << R"( - --max-udp-payload-size= - Override maximum UDP payload size that server transmits. - With this option, server assumes that a path supports - byte of UDP datagram payload, without performing - Path MTU Discovery. - --max-window= - Maximum connection-level flow control window size. The - window auto-tuning is enabled if nonzero value is given, - and window size is scaled up to this value. - Default: )" - << util::format_uint_iec(config.max_window) << R"( - --max-stream-window= - Maximum stream-level flow control window size. The - window auto-tuning is enabled if nonzero value is given, - and window size is scaled up to this value. - Default: )" - << util::format_uint_iec(config.max_stream_window) << R"( - --send-trailers - Send trailer fields. - --handshake-timeout= - Set the QUIC handshake timeout. It defaults to no - timeout. - --preferred-versions=[[,]...] - Specify QUIC versions in hex string in the order of - preference. Server negotiates one of those versions if - client initially selects a less preferred version. - These versions must be supported by libngtcp2. Instead - of specifying hex string, there are special aliases - available: "v1" indicates QUIC v1, and "v2" indicates - QUIC v2. - --available-versions=[[,]...] - Specify QUIC versions in hex string that are sent in - available_versions field of version_information - transport parameter. This list can include a version - which is not supported by libngtcp2. Instead of - specifying hex string, there are special aliases - available: "v1" indicates QUIC v1, and "v2" indicates - QUIC v2. - --no-pmtud Disables Path MTU Discovery. - --ack-thresh= - The minimum number of the received ACK eliciting packets - that triggers immediate acknowledgement. - Default: )" - << config.ack_thresh << R"( - --initial-pkt-num= - The initial packet number that is used for each packet - number space. It must be in range [0, (1 << 31) - 1], - inclusive. By default, the initial packet number is - chosen randomly. - --pmtud-probes=[[,]...] - Specify UDP datagram payload sizes to probe in Path MTU - Discovery. must be strictly larger than 1200. - --ech-config-file= - Read private key and ECHConfig from . The file - denoted by must contain private key and ECHConfig - as described in - https://datatracker.ietf.org/doc/html/draft-farrell-tls-pemesni. - ECH configuration is only applied if an underlying TLS - stack supports it. - --no-gso Disables GSO. - --show-stat Print the connection statistics when the connection is - closed. - --gso-burst= - The maximum number of packets to aggregate for GSO. If - GSO is disabled, this is the maximum number of packets - to send per an event loop in a single connection. It - defaults to 0, which means it is not limited by the - configuration. - -h, --help Display this help and exit. - ---- - - The argument is an integer and an optional unit (e.g., 10K is - 10 * 1024). Units are K, M and G (powers of 1024). - - The argument is an integer and an optional unit (e.g., 1s - is 1 second and 500ms is 500 milliseconds). Units are h, m, s, ms, - us, or ns (hours, minutes, seconds, milliseconds, microseconds, and - nanoseconds respectively). If a unit is omitted, a second is used - as unit. - - The argument is an hex string which must start with "0x" - (e.g., 0x00000001).)" - << std::endl; -} -} // namespace - -std::ofstream keylog_file; - -int main(int argc, char **argv) { - if (argc) { - prog = basename(argv[0]); - } - - std::string_view ech_config_file; - - for (;;) { - static int flag = 0; - constexpr static option long_opts[] = { - {"help", no_argument, nullptr, 'h'}, - {"tx-loss", required_argument, nullptr, 't'}, - {"rx-loss", required_argument, nullptr, 'r'}, - {"htdocs", required_argument, nullptr, 'd'}, - {"quiet", no_argument, nullptr, 'q'}, - {"show-secret", no_argument, nullptr, 's'}, - {"validate-addr", no_argument, nullptr, 'V'}, - {"ciphers", required_argument, &flag, 1}, - {"groups", required_argument, &flag, 2}, - {"timeout", required_argument, &flag, 3}, - {"preferred-ipv4-addr", required_argument, &flag, 4}, - {"preferred-ipv6-addr", required_argument, &flag, 5}, - {"mime-types-file", required_argument, &flag, 6}, - {"early-response", no_argument, &flag, 7}, - {"verify-client", no_argument, &flag, 8}, - {"qlog-dir", required_argument, &flag, 9}, - {"no-quic-dump", no_argument, &flag, 10}, - {"no-http-dump", no_argument, &flag, 11}, - {"max-data", required_argument, &flag, 12}, - {"max-stream-data-bidi-local", required_argument, &flag, 13}, - {"max-stream-data-bidi-remote", required_argument, &flag, 14}, - {"max-stream-data-uni", required_argument, &flag, 15}, - {"max-streams-bidi", required_argument, &flag, 16}, - {"max-streams-uni", required_argument, &flag, 17}, - {"max-dyn-length", required_argument, &flag, 18}, - {"cc", required_argument, &flag, 19}, - {"initial-rtt", required_argument, &flag, 20}, - {"max-udp-payload-size", required_argument, &flag, 21}, - {"send-trailers", no_argument, &flag, 22}, - {"max-window", required_argument, &flag, 23}, - {"max-stream-window", required_argument, &flag, 24}, - {"handshake-timeout", required_argument, &flag, 26}, - {"preferred-versions", required_argument, &flag, 27}, - {"available-versions", required_argument, &flag, 28}, - {"no-pmtud", no_argument, &flag, 29}, - {"ack-thresh", required_argument, &flag, 30}, - {"initial-pkt-num", required_argument, &flag, 31}, - {"pmtud-probes", required_argument, &flag, 32}, - {"ech-config-file", required_argument, &flag, 33}, - {"no-gso", no_argument, &flag, 35}, - {"show-stat", no_argument, &flag, 36}, - {"gso-burst", required_argument, &flag, 37}, - {}, - }; - - auto optidx = 0; - auto c = getopt_long(argc, argv, "d:hqr:st:V", long_opts, &optidx); - if (c == -1) { - break; - } - switch (c) { - case 'd': { - // --htdocs - auto path = realpath(optarg, nullptr); - if (path == nullptr) { - std::println(stderr, "path: invalid path {}", optarg); - exit(EXIT_FAILURE); - } - config.htdocs = path; - free(path); - break; - } - case 'h': - // --help - print_help(); - exit(EXIT_SUCCESS); - case 'q': - // --quiet - config.quiet = true; - break; - case 'r': - // --rx-loss - config.rx_loss_prob = strtod(optarg, nullptr); - break; - case 's': - // --show-secret - config.show_secret = true; - break; - case 't': - // --tx-loss - config.tx_loss_prob = strtod(optarg, nullptr); - break; - case 'V': - // --validate-addr - config.validate_addr = true; - break; - case '?': - print_usage(stderr); - exit(EXIT_FAILURE); - case 0: - switch (flag) { - case 1: - // --ciphers - if (util::crypto_default_ciphers()[0] == '\0') { - std::println(stderr, "ciphers: not supported"); - exit(EXIT_FAILURE); - } - config.ciphers = optarg; - break; - case 2: - // --groups - config.groups = optarg; - break; - case 3: - // --timeout - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "timeout: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.timeout = *t; - } - break; - case 4: { - // --preferred-ipv4-addr - auto maybe_addr = parse_host_port(AF_INET, optarg); - if (!maybe_addr) { - std::println(stderr, "preferred-ipv4-addr: could not use {}", optarg); - exit(EXIT_FAILURE); - } - - config.preferred_ipv4_addr = *maybe_addr; - - break; - } - case 5: { - // --preferred-ipv6-addr - auto maybe_addr = parse_host_port(AF_INET6, optarg); - if (!maybe_addr) { - std::println(stderr, "preferred-ipv6-addr: could not use {}", optarg); - exit(EXIT_FAILURE); - } - - config.preferred_ipv6_addr = *maybe_addr; - - break; - } - case 6: - // --mime-types-file - config.mime_types_file = optarg; - break; - case 7: - // --early-response - config.early_response = true; - break; - case 8: - // --verify-client - config.verify_client = true; - break; - case 9: - // --qlog-dir - config.qlog_dir = optarg; - break; - case 10: - // --no-quic-dump - config.no_quic_dump = true; - break; - case 11: - // --no-http-dump - config.no_http_dump = true; - break; - case 12: - // --max-data - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-data: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_data = *n; - } - break; - case 13: - // --max-stream-data-bidi-local - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-data-bidi-local: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_data_bidi_local = *n; - } - break; - case 14: - // --max-stream-data-bidi-remote - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-data-bidi-remote: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_data_bidi_remote = *n; - } - break; - case 15: - // --max-stream-data-uni - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-data-uni: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_data_uni = *n; - } - break; - case 16: - // --max-streams-bidi - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "max-streams-bidi: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_streams_bidi = *n; - } - break; - case 17: - // --max-streams-uni - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "max-streams-uni: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_streams_uni = *n; - } - break; - case 18: - // --max-dyn-length - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-dyn-length: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_dyn_length = *n; - } - break; - case 19: - // --cc - if (strcmp("cubic", optarg) == 0) { - config.cc_algo = NGTCP2_CC_ALGO_CUBIC; - break; - } - if (strcmp("reno", optarg) == 0) { - config.cc_algo = NGTCP2_CC_ALGO_RENO; - break; - } - if (strcmp("bbr", optarg) == 0) { - config.cc_algo = NGTCP2_CC_ALGO_BBR; - break; - } - std::println(stderr, "cc: specify cubic, reno, or bbr"); - exit(EXIT_FAILURE); - case 20: - // --initial-rtt - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "initial-rtt: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.initial_rtt = *t; - } - break; - case 21: - // --max-udp-payload-size - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-udp-payload-size: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { - std::println(stderr, "max-udp-payload-size: must not exceed {}", - NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); - exit(EXIT_FAILURE); - } else { - config.max_udp_payload_size = *n; - } - break; - case 22: - // --send-trailers - config.send_trailers = true; - break; - case 23: - // --max-window - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-window: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_window = *n; - } - break; - case 24: - // --max-stream-window - if (auto n = util::parse_uint_iec(optarg); !n) { - std::println(stderr, "max-stream-window: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.max_stream_window = *n; - } - break; - case 26: - // --handshake-timeout - if (auto t = util::parse_duration(optarg); !t) { - std::println(stderr, "handshake-timeout: invalid argument"); - exit(EXIT_FAILURE); - } else { - config.handshake_timeout = *t; - } - break; - case 27: { - // --preferred-versions - auto l = util::split_str(optarg); - if (l.size() > max_preferred_versionslen) { - std::println(stderr, "preferred-versions: too many versions > {}", - max_preferred_versionslen); - exit(EXIT_FAILURE); - } - config.preferred_versions.resize(l.size()); - auto it = std::ranges::begin(config.preferred_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "preferred-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - if (!ngtcp2_is_supported_version(*rv)) { - std::println(stderr, "preferred-versions: unsupported version {}", - k); - exit(EXIT_FAILURE); - } - *it++ = *rv; - } - break; - } - case 28: { - // --available-versions - auto l = util::split_str(optarg); - config.available_versions.resize(l.size()); - auto it = std::ranges::begin(config.available_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "available-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - *it++ = *rv; - } - break; - } - case 29: - // --no-pmtud - config.no_pmtud = true; - break; - case 30: - // --ack-thresh - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "ack-thresh: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n > 100) { - std::println(stderr, "ack-thresh: must not exceed 100"); - exit(EXIT_FAILURE); - } else { - config.ack_thresh = *n; - } - break; - case 31: - // --initial-pkt-num - if (auto n = util::parse_uint(optarg); !n) { - std::println(stderr, "initial-pkt-num: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n > INT32_MAX) { - std::println(stderr, - "initial-pkt-num: must not exceed (1 << 31) - 1"); - exit(EXIT_FAILURE); - } else { - config.initial_pkt_num = static_cast(*n); - } - break; - case 32: { - // --pmtud-probes - auto l = util::split_str(optarg); - for (auto &s : l) { - if (auto n = util::parse_uint_iec(s); !n) { - std::println(stderr, "pmtud-probes: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE || - *n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { - std::println( - stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", - NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); - exit(EXIT_FAILURE); - } else { - config.pmtud_probes.push_back(static_cast(*n)); - } - } - break; - } - case 33: - // --ech-config-file - ech_config_file = optarg; - break; - case 35: - // --no-gso - config.no_gso = true; - break; - case 36: - // --show-stat - config.show_stat = true; - break; - case 37: { - // --gso-burst - auto n = util::parse_uint(optarg); - if (!n) { - std::println(stderr, "gso-burst: invalid argument"); - exit(EXIT_FAILURE); - } - - if (*n > 64) { - std::println(stderr, - "gso-burst: must be in range [0, 64], inclusive."); - exit(EXIT_FAILURE); - } - - config.gso_burst = static_cast(*n); - - break; - } - } - break; - default: - break; - } - } - - if (argc - optind < 4) { - std::println(stderr, "Too few arguments"); - print_usage(stderr); - exit(EXIT_FAILURE); - } - - auto addr = argv[optind++]; - auto port = argv[optind++]; - auto private_key_file = argv[optind++]; - auto cert_file = argv[optind++]; - - if (auto n = util::parse_uint(port); !n) { - std::println(stderr, "port: invalid port number"); - exit(EXIT_FAILURE); - } else if (*n > 65535) { - std::println(stderr, "port: must not exceed 65535"); - exit(EXIT_FAILURE); - } else { - config.port = static_cast(*n); - } - - if (auto mt = util::read_mime_types(config.mime_types_file); !mt) { - std::println(stderr, - "mime-types-file: Could not read MIME media types file {}", - config.mime_types_file); - } else { - config.mime_types = std::move(*mt); - } - - if (!ech_config_file.empty()) { - auto ech_config = util::read_ech_server_config(ech_config_file); - if (!ech_config) { - std::println(stderr, - "ech-config-file: Could not read private key and ECHConfig"); - exit(EXIT_FAILURE); - } - - config.ech_config = std::move(*ech_config); - } - - TLSServerContext tls_ctx; - - if (!tls_ctx.init(private_key_file, cert_file, AppProtocol::HQ)) { - exit(EXIT_FAILURE); - } - - if (config.htdocs.back() != '/') { - config.htdocs += '/'; - } - - std::println(stderr, "Using document root {}", config.htdocs); - - auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); }); - - auto keylog_filename = getenv("SSLKEYLOGFILE"); - if (keylog_filename) { - keylog_file.open(keylog_filename, std::ios_base::app); - if (keylog_file) { - tls_ctx.enable_keylog(); - } - } - - if (!util::generate_secure_random(config.static_secret)) { - std::println(stderr, "Unable to generate static secret"); - exit(EXIT_FAILURE); - } - - Server s(EV_DEFAULT, tls_ctx); - if (!s.init(addr, port)) { - exit(EXIT_FAILURE); - } - - ev_run(EV_DEFAULT, 0); - - s.disconnect(); - s.close(); - - return EXIT_SUCCESS; -} diff --git a/deps/ngtcp2/ngtcp2/examples/h09server.h b/deps/ngtcp2/ngtcp2/examples/h09server.h deleted file mode 100644 index b02557fcd5ddf3..00000000000000 --- a/deps/ngtcp2/ngtcp2/examples/h09server.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2017 ngtcp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef H09SERVER_H -#define H09SERVER_H - -#ifdef HAVE_CONFIG_H -# include -#endif // defined(HAVE_CONFIG_H) - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "server_base.h" -#include "tls_server_context.h" -#include "network.h" -#include "shared.h" -#include "util.h" - -using namespace ngtcp2; - -class Handler; -struct FileEntry; - -struct Stream { - Stream(int64_t stream_id, Handler *handler); - - void start_response(); - std::expected open_file(const std::string &path); - void map_file(const FileEntry &fe); - void send_status_response(unsigned int status_code); - - int64_t stream_id; - Handler *handler; - // uri is request uri/path. - std::string uri; - std::string status_resp_body; - nghttp3_buf respbuf; - http_parser htp; - // eos gets true when one HTTP request message is seen. - bool eos{}; -}; - -struct StreamIDLess { - constexpr bool operator()(const Stream *lhs, const Stream *rhs) const { - return lhs->stream_id < rhs->stream_id; - } -}; - -class Server; - -// Endpoint is a local endpoint. -struct Endpoint { - Address addr; - ev_io rev; - Server *server{}; - int fd{}; -}; - -class Handler : public HandlerBase { -public: - Handler(struct ev_loop *loop, Server *server); - ~Handler(); - - std::expected - init(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_cid *dcid, - const ngtcp2_cid *scid, const ngtcp2_cid *ocid, - std::span token, ngtcp2_token_type token_type, - uint32_t version, TLSServerContext &tls_ctx); - - std::expected on_read(const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr, - const ngtcp2_pkt_info *pi, - std::span data); - std::expected on_write(); - std::expected write_streams(); - std::expected feed_data(const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr, - const ngtcp2_pkt_info *pi, - std::span data); - void update_timer(); - std::expected handle_expiry(); - void signal_write(); - std::expected handshake_completed(); - - Server *server() const; - std::expected recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data); - void acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen); - uint32_t version() const; - void on_stream_open(int64_t stream_id); - void on_stream_close(int64_t stream_id, uint64_t app_error_code); - void start_draining_period(); - std::expected start_closing_period(); - std::expected handle_error(); - std::expected send_conn_close(); - std::expected send_conn_close(const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr, - const ngtcp2_pkt_info *pi, - std::span data); - - std::expected - update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, - size_t secretlen); - - Stream *find_stream(int64_t stream_id); - void extend_max_stream_data(int64_t stream_id, uint64_t max_data); - void shutdown_read(int64_t stream_id, uint64_t app_error_code); - - void write_qlog(const void *data, size_t datalen); - void add_sendq(Stream *stream); - - void on_send_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size); - void start_wev_endpoint(const Endpoint &ep); - std::expected send_packet(const ngtcp2_path &path, - unsigned int ecn, - std::span data, - size_t gso_size); - void send_blocked_packet(); - - ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, - size_t destlen, ngtcp2_tstamp ts); - -private: - struct ev_loop *loop_; - Server *server_; - ev_io wev_; - ev_timer timer_; - FILE *qlog_{}; - ngtcp2_cid scid_{}; - std::unordered_map> streams_; - std::set sendq_; - // conn_closebuf_ contains a packet which contains CONNECTION_CLOSE. - // This packet is repeatedly sent as a response to the incoming - // packet in draining period. - std::unique_ptr conn_closebuf_; - // nkey_update_ is the number of key update occurred. - size_t nkey_update_{}; - bool no_gso_; - struct { - size_t bytes_recv; - size_t bytes_sent; - size_t num_pkts_recv; - size_t next_pkts_recv = 1; - } close_wait_{}; - - struct { - bool send_blocked; - // blocked field is effective only when send_blocked is true. - struct { - const Endpoint *endpoint; - Address local_addr; - Address remote_addr; - unsigned int ecn; - std::span data; - size_t gso_size; - } blocked; - } tx_{}; - std::array txbuf_; -}; - -class Server { -public: - Server(struct ev_loop *loop, TLSServerContext &tls_ctx); - ~Server(); - - std::expected init(const char *addr, const char *port); - void disconnect(); - void close(); - - void on_read(const Endpoint &ep); - void read_pkt(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data); - std::expected - send_version_negotiation(uint32_t version, std::span dcid, - std::span scid, const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr); - std::expected send_retry(const ngtcp2_pkt_hd *chd, - const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr, - size_t max_pktlen); - std::expected - send_stateless_connection_close(const ngtcp2_pkt_hd *chd, const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr); - std::expected send_stateless_reset(size_t pktlen, - std::span dcid, - const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr); - std::expected verify_retry_token(ngtcp2_cid *ocid, - const ngtcp2_pkt_hd *hd, - const Address &remote_addr); - std::expected verify_token(const ngtcp2_pkt_hd *hd, - const Address &remote_addr); - std::expected send_packet(const Endpoint &ep, - const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, - unsigned int ecn, - std::span data); - std::span - send_packet(const Endpoint &ep, bool &no_gso, const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, unsigned int ecn, - std::span data, size_t gso_size); - void remove(const Handler *h); - - void associate_cid(const ngtcp2_cid *cid, Handler *h); - void dissociate_cid(const ngtcp2_cid *cid); - - void on_stateless_reset_regen(); - -private: - std::unordered_map handlers_; - struct ev_loop *loop_; - std::vector endpoints_; - TLSServerContext &tls_ctx_; - ev_signal sigintev_; - ev_timer stateless_reset_regen_timer_; - size_t stateless_reset_bucket_{NGTCP2_STATELESS_RESET_BURST}; -}; - -#endif // !defined(H09SERVER_H) diff --git a/deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.cc b/deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.cc new file mode 100644 index 00000000000000..9537f862dad64e --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.cc @@ -0,0 +1,192 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "hq_client_proto_codec.h" + +#include + +#include "client.h" +#include "debug.h" + +extern Config config; + +namespace ngtcp2 { + +bool StreamIDLess::operator()(const Stream *lhs, const Stream *rhs) const { + return lhs->stream_id < rhs->stream_id; +} + +ProtoCodec::ProtoCodec(Client *c, ngtcp2_ccerr &last_error) + : client_{c}, conn_{client_->conn()}, last_error_{last_error} {} + +std::expected +ProtoCodec::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { + auto stream = client_->find_stream(stream_id); + if (!stream) { + return {}; + } + + ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, data.size()); + ngtcp2_conn_extend_max_offset(conn_, data.size()); + + if (stream->fd == -1) { + return {}; + } + + ssize_t nwrite; + + for (; !data.empty();) { + do { + nwrite = write(stream->fd, data.data(), data.size()); + } while (nwrite == -1 && errno == EINTR); + + if (nwrite < 0) { + std::println(stderr, "Could not write data to file: {}", strerror(errno)); + + return {}; + } + + data = data.subspan(static_cast(nwrite)); + } + + return {}; +} + +std::expected +ProtoCodec::on_stream_close(int64_t stream_id, uint64_t app_error_code) { + if (!ngtcp2_is_bidi_stream(stream_id)) { + return {}; + } + + if (!config.quiet) { + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); + } + + return {}; +} + +std::expected +ProtoCodec::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { + auto stream = client_->find_stream(stream_id); + if (!stream) { + return {}; + } + + if (!stream->reqbuf.empty()) { + sendq_.emplace(stream); + } + + return {}; +} + +ngtcp2_ssize ProtoCodec::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, + uint8_t *dest, size_t destlen, + ngtcp2_tstamp ts) { + ngtcp2_vec vec; + + for (;;) { + int64_t stream_id = -1; + size_t vcnt = 0; + uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE; + Stream *stream = nullptr; + + if (!sendq_.empty() && ngtcp2_conn_get_max_data_left2(conn_)) { + stream = *std::ranges::begin(sendq_); + + stream_id = stream->stream_id; + vec.base = const_cast(stream->reqbuf.data()); + vec.len = stream->reqbuf.size(); + vcnt = 1; + flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; + } + + ngtcp2_ssize ndatalen; + + auto nwrite = + ngtcp2_conn_writev_stream(conn_, path, pi, dest, destlen, &ndatalen, + flags, stream_id, &vec, vcnt, ts); + if (nwrite < 0) { + switch (nwrite) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: + case NGTCP2_ERR_STREAM_SHUT_WR: + assert(ndatalen == -1); + sendq_.erase(std::ranges::begin(sendq_)); + continue; + case NGTCP2_ERR_WRITE_MORE: + assert(ndatalen >= 0); + stream->reqbuf = stream->reqbuf.subspan(as_unsigned(ndatalen)); + if (stream->reqbuf.empty()) { + sendq_.erase(std::ranges::begin(sendq_)); + } + continue; + } + + assert(ndatalen == -1); + + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); + ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, + 0); + + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + if (ndatalen >= 0) { + stream->reqbuf = stream->reqbuf.subspan(as_unsigned(ndatalen)); + if (stream->reqbuf.empty()) { + sendq_.erase(std::ranges::begin(sendq_)); + } + } + + return nwrite; + } +} + +std::expected ProtoCodec::submit_request(Stream *stream) { + const auto &req = stream->req; + + stream->rawreqbuf = config.http_method; + stream->rawreqbuf += ' '; + stream->rawreqbuf += req.path; + stream->rawreqbuf += "\r\n"; + + stream->reqbuf = as_uint8_span(std::span{stream->rawreqbuf}); + + if (!config.quiet) { + auto nva = std::to_array({ + util::make_nv_nn(":method", config.http_method), + util::make_nv_nn(":path", req.path), + }); + debug::print_http_request_headers(stream->stream_id, nva.data(), + nva.size()); + } + + sendq_.emplace(stream); + + return {}; +} + +} // namespace ngtcp2 diff --git a/deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.h b/deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.h new file mode 100644 index 00000000000000..224b8f2a7214bc --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/hq_client_proto_codec.h @@ -0,0 +1,95 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef HQ_CLIENT_PROTO_CODEC_H +#define HQ_CLIENT_PROTO_CODEC_H + +#ifdef HAVE_CONFIG_H +# include +#endif // defined(HAVE_CONFIG_H) + +#include +#include +#include + +#include + +#include "shared.h" +#include "client_base.h" + +struct Stream; +class Client; + +namespace ngtcp2 { + +struct StreamIDLess { + bool operator()(const Stream *lhs, const Stream *rhs) const; +}; + +class ProtoCodec { +public: + ProtoCodec(Client *handler, ngtcp2_ccerr &last_error); + + std::expected recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + + std::expected acked_stream_data_offset(int64_t stream_id, + uint64_t datalen) { + return {}; + } + + std::expected extend_max_stream_data(int64_t stream_id, + uint64_t max_data); + + void early_data_rejected() {} + + std::expected on_stream_close(int64_t stream_id, + uint64_t app_error_code); + + std::expected on_stream_reset(int64_t stream_id) { return {}; } + + std::expected on_stream_stop_sending(int64_t stream_id) { + return {}; + } + + std::expected submit_request(Stream *stream); + + ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, + size_t destlen, ngtcp2_tstamp ts); + + std::expected setup_codec() { return {}; } + + static constexpr auto protocol = AppProtocol::HQ; + static constexpr auto no_error = 0; + +private: + Client *client_; + ngtcp2_conn *conn_; + ngtcp2_ccerr &last_error_; + std::set sendq_; +}; + +} // namespace ngtcp2 + +#endif // !defined(HQ_CLIENT_PROTO_CODEC_H) diff --git a/deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.cc b/deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.cc new file mode 100644 index 00000000000000..8490ca24b0eb5e --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.cc @@ -0,0 +1,261 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "hq_server_proto_codec.h" + +#include "server.h" +#include "debug.h" + +extern Config config; + +namespace ngtcp2 { + +bool StreamIDLess::operator()(const Stream *lhs, const Stream *rhs) const { + return lhs->stream_id < rhs->stream_id; +} + +ProtoCodec::ProtoCodec(Handler *h, ngtcp2_ccerr &last_error) + : handler_{h}, conn_{handler_->conn()}, last_error_{last_error} {} + +namespace { +int on_msg_begin(http_parser *htp) { + auto s = static_cast(htp->data); + if (s->eos) { + return -1; + } + return 0; +} +} // namespace + +namespace { +int on_url_cb(http_parser *htp, const char *data, size_t datalen) { + auto s = static_cast(htp->data); + s->uri.append(data, datalen); + return 0; +} +} // namespace + +namespace { +int on_msg_complete(http_parser *htp) { + auto s = static_cast(htp->data); + s->eos = true; + s->start_response(); + return 0; +} +} // namespace + +constexpr auto htp_settings = http_parser_settings{ + .on_message_begin = on_msg_begin, + .on_url = on_url_cb, + .on_message_complete = on_msg_complete, +}; + +std::expected +ProtoCodec::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { + if (!config.quiet && !config.no_quic_dump) { + debug::print_stream_data(stream_id, data); + } + + auto stream = handler_->find_stream(stream_id); + if (!stream) { + return {}; + } + + if (!stream->eos) { + auto nread = http_parser_execute( + &stream->htp, &htp_settings, reinterpret_cast(data.data()), + data.size()); + if (nread != data.size()) { + if (auto rv = ngtcp2_conn_shutdown_stream(conn_, 0, stream_id, + /* app error code */ 1); + rv != 0) { + std::println(stderr, "ngtcp2_conn_shutdown_stream: {}", + ngtcp2_strerror(rv)); + ngtcp2_ccerr_set_liberr(&last_error_, NGTCP2_ERR_INTERNAL, nullptr, 0); + return std::unexpected{Error::QUIC}; + } + } + } + + ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, data.size()); + ngtcp2_conn_extend_max_offset(conn_, data.size()); + + return {}; +} + +std::expected +ProtoCodec::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { + auto stream = handler_->find_stream(stream_id); + if (!stream) { + return {}; + } + + if (!stream->resp_data.empty()) { + sendq_.emplace(stream); + } + + return {}; +} + +ngtcp2_ssize ProtoCodec::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, + uint8_t *dest, size_t destlen, + ngtcp2_tstamp ts) { + ngtcp2_vec vec; + + for (;;) { + int64_t stream_id = -1; + size_t vcnt = 0; + uint32_t flags = + NGTCP2_WRITE_STREAM_FLAG_MORE | NGTCP2_WRITE_STREAM_FLAG_PADDING; + Stream *stream = nullptr; + + if (!sendq_.empty() && ngtcp2_conn_get_max_data_left2(conn_)) { + stream = *std::ranges::begin(sendq_); + + stream_id = stream->stream_id; + vec.base = const_cast(stream->resp_data.data()); + vec.len = stream->resp_data.size(); + vcnt = 1; + flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; + } + + ngtcp2_ssize ndatalen; + + auto nwrite = + ngtcp2_conn_writev_stream(conn_, path, pi, dest, destlen, &ndatalen, + flags, stream_id, &vec, vcnt, ts); + if (nwrite < 0) { + switch (nwrite) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: + case NGTCP2_ERR_STREAM_SHUT_WR: + assert(ndatalen == -1); + sendq_.erase(std::ranges::begin(sendq_)); + continue; + case NGTCP2_ERR_WRITE_MORE: + assert(ndatalen >= 0); + stream->resp_data = stream->resp_data.subspan(as_unsigned(ndatalen)); + if (stream->resp_data.empty()) { + sendq_.erase(std::ranges::begin(sendq_)); + } + continue; + } + + assert(ndatalen == -1); + + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); + ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, + 0); + + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + if (ndatalen >= 0) { + stream->resp_data = stream->resp_data.subspan(as_unsigned(ndatalen)); + if (stream->resp_data.empty()) { + sendq_.erase(std::ranges::begin(sendq_)); + } + } + + return nwrite; + } +} + +std::expected +ProtoCodec::on_stream_close(int64_t stream_id, uint64_t app_error_code) { + auto stream = handler_->find_stream(stream_id); + if (!stream) { + return {}; + } + + sendq_.erase(stream); + + if (!config.quiet) { + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); + } + + return {}; +} + +std::expected +ProtoCodec::send_status_response(Stream *stream, unsigned int status_code) { + stream->status_resp_body = make_status_body(status_code); + stream->resp_data = as_uint8_span(std::span{stream->status_resp_body}); + + sendq_.emplace(stream); + + handler_->shutdown_read(stream->stream_id, 0); + + return {}; +} + +std::expected ProtoCodec::start_response(Stream *stream) { + if (stream->uri.empty()) { + send_status_response(stream, 400); + return {}; + } + + auto maybe_req = stream->request_path(); + if (!maybe_req) { + send_status_response(stream, 400); + return {}; + } + + const auto &req = *maybe_req; + + auto path = config.htdocs; + path /= std::filesystem::path{req.path}.relative_path(); + + auto maybe_fe = stream->open_file(path); + if (!maybe_fe) { + send_status_response(stream, 404); + return {}; + } + + const auto &fe = *maybe_fe; + + if (fe.flags & FILE_ENTRY_TYPE_DIR) { + send_status_response(stream, 404); + return {}; + } + + stream->map_file(fe); + + if (!config.quiet) { + auto nva = std::to_array({ + util::make_nv_nn(":status", "200"), + }); + + debug::print_http_response_headers(stream->stream_id, nva.data(), + nva.size()); + } + + sendq_.emplace(stream); + + return {}; +} + +} // namespace ngtcp2 diff --git a/deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.h b/deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.h new file mode 100644 index 00000000000000..a60d616e3da254 --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/hq_server_proto_codec.h @@ -0,0 +1,98 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef HQ_SERVER_PROTO_CODEC_H +#define HQ_SERVER_PROTO_CODEC_H + +#ifdef HAVE_CONFIG_H +# include +#endif // defined(HAVE_CONFIG_H) + +#include +#include +#include + +#include +#include + +#include "shared.h" +#include "server_base.h" + +struct Stream; +class Handler; + +namespace ngtcp2 { + +struct StreamIDLess { + bool operator()(const Stream *lhs, const Stream *rhs) const; +}; + +class ProtoCodec { +public: + ProtoCodec(Handler *handler, ngtcp2_ccerr &last_error); + + std::expected acked_stream_data_offset(int64_t stream_id, + uint64_t datalen) { + return {}; + } + + std::expected on_stream_reset(int64_t stream_id) { return {}; } + + std::expected on_stream_stop_sending(int64_t stream_id) { + return {}; + } + + void extend_max_remote_streams_bidi(uint64_t max_streams) {} + + std::expected extend_max_stream_data(int64_t stream_id, + uint64_t max_data); + + std::expected on_app_tx_ready() { return {}; } + + ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, + size_t destlen, ngtcp2_tstamp ts); + + std::expected recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + + std::expected on_stream_close(int64_t stream_id, + uint64_t app_error_code); + + std::expected start_response(Stream *stream); + + static constexpr auto protocol = AppProtocol::HQ; + +private: + std::expected send_status_response(Stream *stream, + unsigned int status_code); + + Handler *handler_; + ngtcp2_conn *conn_; + ngtcp2_ccerr &last_error_; + std::set sendq_; +}; + +} // namespace ngtcp2 + +#endif // !defined(HQ_SERVER_PROTO_CODEC_H) diff --git a/deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.cc b/deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.cc new file mode 100644 index 00000000000000..82e33acffb1914 --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.cc @@ -0,0 +1,606 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "http3_client_proto_codec.h" + +#include + +#include "client.h" +#include "debug.h" + +extern Config config; + +namespace ngtcp2 { + +ProtoCodec::ProtoCodec(Client *c, ngtcp2_ccerr &last_error) + : client_{c}, conn_{client_->conn()}, last_error_{last_error} {} + +ProtoCodec::~ProtoCodec() { + if (httpconn_) { + nghttp3_conn_del(httpconn_); + } +} + +std::expected +ProtoCodec::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { + auto nconsumed = nghttp3_conn_read_stream2( + httpconn_, stream_id, data.data(), data.size(), + flags & NGTCP2_STREAM_DATA_FLAG_FIN, ngtcp2_conn_get_timestamp(conn_)); + if (nconsumed < 0) { + std::println(stderr, "nghttp3_conn_read_stream2: {}", + nghttp3_strerror(static_cast(nconsumed))); + ngtcp2_ccerr_set_application_error( + &last_error_, + nghttp3_err_infer_quic_app_error_code(static_cast(nconsumed)), + nullptr, 0); + return std::unexpected{Error::HTTP3}; + } + + ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, + static_cast(nconsumed)); + ngtcp2_conn_extend_max_offset(conn_, static_cast(nconsumed)); + + return {}; +} + +std::expected +ProtoCodec::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) { + if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen); + rv != 0) { + std::println(stderr, "nghttp3_conn_add_ack_offset: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + return {}; +} + +std::expected +ProtoCodec::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { + if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) { + std::println(stderr, "nghttp3_conn_unblock_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + return {}; +} + +void ProtoCodec::early_data_rejected() { + nghttp3_conn_del(httpconn_); + httpconn_ = nullptr; +} + +void ProtoCodec::http_stream_close(int64_t stream_id, uint64_t app_error_code) { + if (!ngtcp2_is_bidi_stream(stream_id)) { + return; + } + + if (!config.quiet) { + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); + } +} + +std::expected +ProtoCodec::on_stream_close(int64_t stream_id, uint64_t app_error_code) { + if (!httpconn_) { + return {}; + } + + if (app_error_code == 0) { + app_error_code = NGHTTP3_H3_NO_ERROR; + } + + if (auto rv = nghttp3_conn_close_stream(httpconn_, stream_id, app_error_code); + rv != 0) { + if (rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + std::println(stderr, "nghttp3_conn_close_stream: {}", + nghttp3_strerror(rv)); + ngtcp2_ccerr_set_application_error( + &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); + return std::unexpected{Error::HTTP3}; + } + + return {}; + } + + http_stream_close(stream_id, app_error_code); + + return {}; +} + +std::expected ProtoCodec::on_stream_reset(int64_t stream_id) { + if (!httpconn_) { + return {}; + } + + if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + return {}; +} + +std::expected +ProtoCodec::on_stream_stop_sending(int64_t stream_id) { + if (!httpconn_) { + return {}; + } + + if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + return {}; +} + +namespace { +nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, + size_t veccnt, uint32_t *pflags, void *user_data, + void *stream_user_data) { + vec[0].base = config.data; + vec[0].len = config.datalen; + *pflags |= NGHTTP3_DATA_FLAG_EOF; + + return 1; +} +} // namespace + +std::expected ProtoCodec::submit_request(const Stream *stream) { + std::string content_length_str; + + const auto &req = stream->req; + + std::array nva{ + util::make_nv_nn(":method", config.http_method), + util::make_nv_nn(":scheme", req.scheme), + util::make_nv_nn(":authority", req.authority), + util::make_nv_nn(":path", req.path), + util::make_nv_nn("user-agent", "nghttp3/ngtcp2 client"), + }; + size_t nvlen = 5; + if (config.fd != -1) { + content_length_str = util::format_uint(config.datalen); + nva[nvlen++] = util::make_nv_nc("content-length", content_length_str); + } + + if (!config.quiet) { + debug::print_http_request_headers(stream->stream_id, nva.data(), nvlen); + } + + nghttp3_data_reader dr{ + .read_data = read_data, + }; + + if (auto rv = nghttp3_conn_submit_request( + httpconn_, stream->stream_id, nva.data(), nvlen, + config.fd == -1 ? nullptr : &dr, nullptr); + rv != 0) { + std::println(stderr, "nghttp3_conn_submit_request: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + return {}; +} + +ngtcp2_ssize ProtoCodec::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, + uint8_t *dest, size_t destlen, + ngtcp2_tstamp ts) { + std::array vec; + + for (;;) { + int64_t stream_id = -1; + int fin = 0; + nghttp3_ssize sveccnt = 0; + + if (httpconn_ && ngtcp2_conn_get_max_data_left2(conn_)) { + sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin, + vec.data(), vec.size()); + if (sveccnt < 0) { + std::println(stderr, "nghttp3_conn_writev_stream: {}", + nghttp3_strerror(static_cast(sveccnt))); + ngtcp2_ccerr_set_application_error( + &last_error_, + nghttp3_err_infer_quic_app_error_code(static_cast(sveccnt)), + nullptr, 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + } + + ngtcp2_ssize ndatalen; + auto v = vec.data(); + auto vcnt = static_cast(sveccnt); + + uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE; + if (fin) { + flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; + } + + auto nwrite = ngtcp2_conn_writev_stream( + conn_, path, pi, dest, destlen, &ndatalen, flags, stream_id, + reinterpret_cast(v), vcnt, ts); + if (nwrite < 0) { + switch (nwrite) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: + assert(ndatalen == -1); + nghttp3_conn_block_stream(httpconn_, stream_id); + continue; + case NGTCP2_ERR_STREAM_SHUT_WR: + assert(ndatalen == -1); + nghttp3_conn_shutdown_stream_write(httpconn_, stream_id); + continue; + case NGTCP2_ERR_WRITE_MORE: + assert(ndatalen >= 0); + if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, + as_unsigned(ndatalen)); + rv != 0) { + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); + ngtcp2_ccerr_set_application_error( + &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, + 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + continue; + } + + assert(ndatalen == -1); + + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); + ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, + 0); + + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + if (ndatalen >= 0) { + if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, + as_unsigned(ndatalen)); + rv != 0) { + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); + ngtcp2_ccerr_set_application_error( + &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); + + return NGTCP2_ERR_CALLBACK_FAILURE; + } + } + + return nwrite; + } +} + +namespace { +int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data, + size_t datalen, void *user_data, void *stream_user_data) { + if (!config.quiet && !config.no_http_dump) { + debug::print_http_data(stream_id, {data, datalen}); + } + auto pc = static_cast(user_data); + pc->http_consume(stream_id, datalen); + pc->http_write_data(stream_id, {data, datalen}); + return 0; +} +} // namespace + +namespace { +int http_deferred_consume(nghttp3_conn *conn, int64_t stream_id, + size_t nconsumed, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + pc->http_consume(stream_id, nconsumed); + return 0; +} +} // namespace + +void ProtoCodec::http_consume(int64_t stream_id, size_t nconsumed) { + ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed); + ngtcp2_conn_extend_max_offset(conn_, nconsumed); +} + +void ProtoCodec::http_write_data(int64_t stream_id, + std::span data) { + auto stream = client_->find_stream(stream_id); + if (!stream) { + return; + } + + if (stream->fd == -1) { + return; + } + + ssize_t nwrite; + + for (; !data.empty();) { + do { + nwrite = write(stream->fd, data.data(), data.size()); + } while (nwrite == -1 && errno == EINTR); + + if (nwrite < 0) { + std::println(stderr, "Could not write data to file: {}", strerror(errno)); + + return; + } + + data = data.subspan(static_cast(nwrite)); + } +} + +namespace { +int http_begin_headers(nghttp3_conn *conn, int64_t stream_id, void *user_data, + void *stream_user_data) { + if (!config.quiet) { + debug::print_http_begin_response_headers(stream_id); + } + return 0; +} +} // namespace + +namespace { +int http_recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token, + nghttp3_rcbuf *name, nghttp3_rcbuf *value, uint8_t flags, + void *user_data, void *stream_user_data) { + if (!config.quiet) { + debug::print_http_header(stream_id, name, value, flags); + } + return 0; +} +} // namespace + +namespace { +int http_end_headers(nghttp3_conn *conn, int64_t stream_id, int fin, + void *user_data, void *stream_user_data) { + if (!config.quiet) { + debug::print_http_end_headers(stream_id); + } + return 0; +} +} // namespace + +namespace { +int http_begin_trailers(nghttp3_conn *conn, int64_t stream_id, void *user_data, + void *stream_user_data) { + if (!config.quiet) { + debug::print_http_begin_trailers(stream_id); + } + return 0; +} +} // namespace + +namespace { +int http_recv_trailer(nghttp3_conn *conn, int64_t stream_id, int32_t token, + nghttp3_rcbuf *name, nghttp3_rcbuf *value, uint8_t flags, + void *user_data, void *stream_user_data) { + if (!config.quiet) { + debug::print_http_header(stream_id, name, value, flags); + } + return 0; +} +} // namespace + +namespace { +int http_end_trailers(nghttp3_conn *conn, int64_t stream_id, int fin, + void *user_data, void *stream_user_data) { + if (!config.quiet) { + debug::print_http_end_trailers(stream_id); + } + return 0; +} +} // namespace + +namespace { +int http_stop_sending(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + if (!pc->stop_sending(stream_id, app_error_code)) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + return 0; +} +} // namespace + +std::expected ProtoCodec::stop_sending(int64_t stream_id, + uint64_t app_error_code) { + if (auto rv = + ngtcp2_conn_shutdown_stream_read(conn_, 0, stream_id, app_error_code); + rv != 0) { + std::println(stderr, "ngtcp2_conn_shutdown_stream_read: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + return {}; +} + +namespace { +int http_reset_stream(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + if (!pc->reset_stream(stream_id, app_error_code)) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + return 0; +} +} // namespace + +std::expected ProtoCodec::reset_stream(int64_t stream_id, + uint64_t app_error_code) { + if (auto rv = + ngtcp2_conn_shutdown_stream_write(conn_, 0, stream_id, app_error_code); + rv != 0) { + std::println(stderr, "ngtcp2_conn_shutdown_stream_write: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + return {}; +} + +namespace { +void rand_bytes(uint8_t *dest, size_t destlen) { + if (!util::generate_secure_random({dest, destlen})) { + assert(0); + abort(); + } +} +} // namespace + +namespace { +int http_recv_settings(nghttp3_conn *conn, + const nghttp3_proto_settings *settings, + void *conn_user_data) { + if (!config.quiet) { + debug::print_http_settings(settings); + } + + return 0; +} +} // namespace + +namespace { +int http_recv_origin(nghttp3_conn *conn, const uint8_t *origin, + size_t originlen, void *conn_user_data) { + if (!config.quiet) { + debug::print_http_origin(origin, originlen); + } + + return 0; +} +} // namespace + +namespace { +int http_end_origin(nghttp3_conn *conn, void *conn_user_data) { + if (!config.quiet) { + debug::print_http_end_origin(); + } + + return 0; +} +} // namespace + +std::expected ProtoCodec::setup_codec() { + if (httpconn_) { + return {}; + } + + if (ngtcp2_conn_get_streams_uni_left2(conn_) < 3) { + std::println(stderr, + "peer does not allow at least 3 unidirectional streams."); + return std::unexpected{Error::QUIC}; + } + + static constexpr auto callbacks = nghttp3_callbacks{ + .recv_data = ::http_recv_data, + .deferred_consume = ::http_deferred_consume, + .begin_headers = ::http_begin_headers, + .recv_header = ::http_recv_header, + .end_headers = ::http_end_headers, + .begin_trailers = ::http_begin_trailers, + .recv_trailer = ::http_recv_trailer, + .end_trailers = ::http_end_trailers, + .stop_sending = ::http_stop_sending, + .reset_stream = ::http_reset_stream, + .recv_origin = ::http_recv_origin, + .end_origin = ::http_end_origin, + .rand = rand_bytes, + .recv_settings2 = ::http_recv_settings, + }; + nghttp3_settings settings; + nghttp3_settings_default(&settings); + settings.qpack_max_dtable_capacity = 4_k; + settings.qpack_blocked_streams = 100; + + auto mem = nghttp3_mem_default(); + + if (auto rv = + nghttp3_conn_client_new(&httpconn_, &callbacks, &settings, mem, this); + rv != 0) { + std::println(stderr, "nghttp3_conn_client_new: {}", nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + int64_t ctrl_stream_id; + + if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr); + rv != 0) { + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + + if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_bind_control_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + if (!config.quiet) { + std::println(stderr, "http: control stream={:#x}", ctrl_stream_id); + } + + int64_t qpack_enc_stream_id, qpack_dec_stream_id; + + if (auto rv = + ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr); + rv != 0) { + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + + if (auto rv = + ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr); + rv != 0) { + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + + if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id, + qpack_dec_stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_bind_qpack_streams: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + if (!config.quiet) { + std::println(stderr, "http: QPACK streams encoder={:#x} decoder={:#x}", + qpack_enc_stream_id, qpack_dec_stream_id); + } + + return {}; +} + +} // namespace ngtcp2 diff --git a/deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.h b/deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.h new file mode 100644 index 00000000000000..2655e1bf8072d5 --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/http3_client_proto_codec.h @@ -0,0 +1,102 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef HTTP3_CLIENT_PROTO_CODEC_H +#define HTTP3_CLIENT_PROTO_CODEC_H + +#ifdef HAVE_CONFIG_H +# include +#endif // defined(HAVE_CONFIG_H) + +#include +#include + +#include +#include + +#include "shared.h" +#include "client_base.h" + +struct Stream; +class Client; + +namespace ngtcp2 { + +class ProtoCodec { +public: + ProtoCodec(Client *handler, ngtcp2_ccerr &last_error); + ~ProtoCodec(); + + std::expected recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + + std::expected acked_stream_data_offset(int64_t stream_id, + uint64_t datalen); + + std::expected extend_max_stream_data(int64_t stream_id, + uint64_t max_data); + + void early_data_rejected(); + + std::expected on_stream_close(int64_t stream_id, + uint64_t app_error_code); + + std::expected on_stream_reset(int64_t stream_id); + + std::expected on_stream_stop_sending(int64_t stream_id); + + std::expected submit_request(const Stream *stream); + + ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, + size_t destlen, ngtcp2_tstamp ts); + + std::expected setup_codec(); + + // The following functions are made public so that they can be + // called from nghttp3 callback functions. + std::expected stop_sending(int64_t stream_id, + uint64_t app_error_code); + + std::expected reset_stream(int64_t stream_id, + uint64_t app_error_code); + + void http_consume(int64_t stream_id, size_t nconsumed); + + void http_write_data(int64_t stream_id, std::span data); + + static constexpr auto protocol = AppProtocol::H3; + static constexpr auto no_error = NGHTTP3_H3_NO_ERROR; + +private: + void http_stream_close(int64_t stream_id, uint64_t app_error_code); + + Client *client_; + ngtcp2_conn *conn_; + ngtcp2_ccerr &last_error_; + nghttp3_conn *httpconn_{}; +}; + +} // namespace ngtcp2 + +#endif // !defined(HTTP3_CLIENT_PROTO_CODEC_H) diff --git a/deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.cc b/deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.cc new file mode 100644 index 00000000000000..1a39177e32a6d1 --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.cc @@ -0,0 +1,844 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "http3_server_proto_codec.h" + +#include "server.h" +#include "debug.h" + +extern Config config; + +namespace ngtcp2 { + +ProtoCodec::ProtoCodec(Handler *h, ngtcp2_ccerr &last_error) + : handler_{h}, conn_{handler_->conn()}, last_error_{last_error} {} + +ProtoCodec::~ProtoCodec() { + if (httpconn_) { + nghttp3_conn_del(httpconn_); + } +} + +std::expected +ProtoCodec::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) { + if (!httpconn_) { + return {}; + } + + if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen); + rv != 0) { + std::println(stderr, "nghttp3_conn_add_ack_offset: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + return {}; +} + +std::expected ProtoCodec::on_stream_reset(int64_t stream_id) { + if (!httpconn_) { + return {}; + } + + if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + return {}; +} + +std::expected +ProtoCodec::on_stream_stop_sending(int64_t stream_id) { + if (!httpconn_) { + return {}; + } + + if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + return {}; +} + +void ProtoCodec::extend_max_remote_streams_bidi(uint64_t max_streams) { + if (!httpconn_) { + return; + } + + nghttp3_conn_set_max_client_streams_bidi(httpconn_, max_streams); +} + +std::expected +ProtoCodec::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { + if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) { + std::println(stderr, "nghttp3_conn_unblock_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + return {}; +} + +std::expected ProtoCodec::on_app_tx_ready() { + return setup_httpconn(); +} + +ngtcp2_ssize ProtoCodec::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, + uint8_t *dest, size_t destlen, + ngtcp2_tstamp ts) { + std::array vec; + + for (;;) { + int64_t stream_id = -1; + int fin = 0; + nghttp3_ssize sveccnt = 0; + + if (httpconn_ && ngtcp2_conn_get_max_data_left2(conn_)) { + sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin, + vec.data(), vec.size()); + if (sveccnt < 0) { + std::println(stderr, "nghttp3_conn_writev_stream: {}", + nghttp3_strerror(static_cast(sveccnt))); + ngtcp2_ccerr_set_application_error( + &last_error_, + nghttp3_err_infer_quic_app_error_code(static_cast(sveccnt)), + nullptr, 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + } + + ngtcp2_ssize ndatalen; + auto v = vec.data(); + auto vcnt = static_cast(sveccnt); + + uint32_t flags = + NGTCP2_WRITE_STREAM_FLAG_MORE | NGTCP2_WRITE_STREAM_FLAG_PADDING; + if (fin) { + flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; + } + + auto nwrite = ngtcp2_conn_writev_stream( + conn_, path, pi, dest, destlen, &ndatalen, flags, stream_id, + reinterpret_cast(v), vcnt, ts); + if (nwrite < 0) { + switch (nwrite) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: + assert(ndatalen == -1); + nghttp3_conn_block_stream(httpconn_, stream_id); + continue; + case NGTCP2_ERR_STREAM_SHUT_WR: + assert(ndatalen == -1); + nghttp3_conn_shutdown_stream_write(httpconn_, stream_id); + continue; + case NGTCP2_ERR_WRITE_MORE: + assert(ndatalen >= 0); + if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, + as_unsigned(ndatalen)); + rv != 0) { + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); + ngtcp2_ccerr_set_application_error( + &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, + 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + continue; + } + + assert(ndatalen == -1); + + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); + ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, + 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + if (ndatalen >= 0) { + if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, + as_unsigned(ndatalen)); + rv != 0) { + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); + ngtcp2_ccerr_set_application_error( + &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); + return NGTCP2_ERR_CALLBACK_FAILURE; + } + } + + return nwrite; + } +} + +std::expected +ProtoCodec::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { + if (!config.quiet && !config.no_quic_dump) { + debug::print_stream_data(stream_id, data); + } + + if (!httpconn_) { + return {}; + } + + auto nconsumed = nghttp3_conn_read_stream2( + httpconn_, stream_id, data.data(), data.size(), + flags & NGTCP2_STREAM_DATA_FLAG_FIN, ngtcp2_conn_get_timestamp(conn_)); + if (nconsumed < 0) { + std::println(stderr, "nghttp3_conn_read_stream2: {}", + nghttp3_strerror(static_cast(nconsumed))); + ngtcp2_ccerr_set_application_error( + &last_error_, + nghttp3_err_infer_quic_app_error_code(static_cast(nconsumed)), + nullptr, 0); + return std::unexpected{Error::HTTP3}; + } + + ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, + static_cast(nconsumed)); + ngtcp2_conn_extend_max_offset(conn_, static_cast(nconsumed)); + + return {}; +} + +std::expected +ProtoCodec::on_stream_close(int64_t stream_id, uint64_t app_error_code) { + if (!httpconn_) { + return {}; + } + + if (app_error_code == 0) { + app_error_code = NGHTTP3_H3_NO_ERROR; + } + + if (auto rv = nghttp3_conn_close_stream(httpconn_, stream_id, app_error_code); + rv != 0) { + if (rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + std::println(stderr, "nghttp3_conn_close_stream: {}", + nghttp3_strerror(rv)); + ngtcp2_ccerr_set_application_error( + &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); + return std::unexpected{Error::HTTP3}; + } + + return {}; + } + + http_stream_close(stream_id, app_error_code); + + return {}; +} + +namespace { +int http_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, + uint64_t datalen, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + auto stream = static_cast(stream_user_data); + pc->http_acked_stream_data(stream, datalen); + return 0; +} +} // namespace + +void ProtoCodec::http_acked_stream_data(Stream *stream, uint64_t datalen) { + stream->http_acked_stream_data(datalen); +} + +namespace { +int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data, + size_t datalen, void *user_data, void *stream_user_data) { + if (!config.quiet && !config.no_http_dump) { + debug::print_http_data(stream_id, {data, datalen}); + } + auto pc = static_cast(user_data); + pc->http_consume(stream_id, datalen); + return 0; +} +} // namespace + +namespace { +int http_deferred_consume(nghttp3_conn *conn, int64_t stream_id, + size_t nconsumed, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + pc->http_consume(stream_id, nconsumed); + return 0; +} +} // namespace + +void ProtoCodec::http_consume(int64_t stream_id, size_t nconsumed) { + ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed); + ngtcp2_conn_extend_max_offset(conn_, nconsumed); +} + +namespace { +int http_begin_request_headers(nghttp3_conn *conn, int64_t stream_id, + void *user_data, void *stream_user_data) { + if (!config.quiet) { + debug::print_http_begin_request_headers(stream_id); + } + + auto pc = static_cast(user_data); + pc->http_begin_request_headers(stream_id); + return 0; +} +} // namespace + +void ProtoCodec::http_begin_request_headers(int64_t stream_id) { + auto stream = handler_->find_stream(stream_id); + if (!stream) { + return; + } + + nghttp3_conn_set_stream_user_data(httpconn_, stream_id, stream); +} + +namespace { +int http_recv_request_header(nghttp3_conn *conn, int64_t stream_id, + int32_t token, nghttp3_rcbuf *name, + nghttp3_rcbuf *value, uint8_t flags, + void *user_data, void *stream_user_data) { + if (!config.quiet) { + debug::print_http_header(stream_id, name, value, flags); + } + + auto pc = static_cast(user_data); + auto stream = static_cast(stream_user_data); + pc->http_recv_request_header(stream, token, name, value); + return 0; +} +} // namespace + +void ProtoCodec::http_recv_request_header(Stream *stream, int32_t token, + nghttp3_rcbuf *name, + nghttp3_rcbuf *value) { + auto v = nghttp3_rcbuf_get_buf(value); + + switch (token) { + case NGHTTP3_QPACK_TOKEN__PATH: + stream->uri = std::string{v.base, v.base + v.len}; + break; + case NGHTTP3_QPACK_TOKEN__METHOD: + stream->method = std::string{v.base, v.base + v.len}; + break; + case NGHTTP3_QPACK_TOKEN__AUTHORITY: + stream->authority = std::string{v.base, v.base + v.len}; + break; + } +} + +namespace { +int http_end_request_headers(nghttp3_conn *conn, int64_t stream_id, int fin, + void *user_data, void *stream_user_data) { + if (!config.quiet) { + debug::print_http_end_headers(stream_id); + } + + auto pc = static_cast(user_data); + auto stream = static_cast(stream_user_data); + if (!pc->http_end_request_headers(stream)) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + return 0; +} +} // namespace + +std::expected +ProtoCodec::http_end_request_headers(Stream *stream) { + if (config.early_response) { + if (auto rv = start_response(stream); !rv) { + return rv; + } + + handler_->shutdown_read(stream->stream_id, NGHTTP3_H3_NO_ERROR); + } + return {}; +} + +namespace { +int http_stop_sending(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + if (!pc->http_stop_sending(stream_id, app_error_code)) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + return 0; +} +} // namespace + +std::expected +ProtoCodec::http_stop_sending(int64_t stream_id, uint64_t app_error_code) { + if (auto rv = + ngtcp2_conn_shutdown_stream_read(conn_, 0, stream_id, app_error_code); + rv != 0) { + std::println(stderr, "ngtcp2_conn_shutdown_stream_read: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + return {}; +} + +namespace { +int http_end_stream(nghttp3_conn *conn, int64_t stream_id, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + auto stream = static_cast(stream_user_data); + if (!pc->http_end_stream(stream)) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + return 0; +} +} // namespace + +std::expected ProtoCodec::http_end_stream(Stream *stream) { + if (!config.early_response) { + return start_response(stream); + } + return {}; +} + +namespace { +int http_reset_stream(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + auto pc = static_cast(user_data); + if (!pc->http_reset_stream(stream_id, app_error_code)) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + return 0; +} +} // namespace + +std::expected +ProtoCodec::http_reset_stream(int64_t stream_id, uint64_t app_error_code) { + if (auto rv = + ngtcp2_conn_shutdown_stream_write(conn_, 0, stream_id, app_error_code); + rv != 0) { + std::println(stderr, "ngtcp2_conn_shutdown_stream_write: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + return {}; +} + +namespace { +void rand_bytes(uint8_t *dest, size_t destlen) { + if (!util::generate_secure_random({dest, destlen})) { + assert(0); + abort(); + } +} +} // namespace + +namespace { +int http_recv_settings(nghttp3_conn *conn, + const nghttp3_proto_settings *settings, + void *conn_user_data) { + if (!config.quiet) { + debug::print_http_settings(settings); + } + + return 0; +} +} // namespace + +namespace { +nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, + size_t veccnt, uint32_t *pflags, void *user_data, + void *stream_user_data) { + auto stream = static_cast(stream_user_data); + + vec[0].base = const_cast(stream->resp_data.data()); + vec[0].len = stream->resp_data.size(); + *pflags |= NGHTTP3_DATA_FLAG_EOF; + if (config.send_trailers) { + *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM; + } + + return 1; +} +} // namespace + +auto dyn_buf = std::make_unique>(); + +namespace { +nghttp3_ssize dyn_read_data(nghttp3_conn *conn, int64_t stream_id, + nghttp3_vec *vec, size_t veccnt, uint32_t *pflags, + void *user_data, void *stream_user_data) { + auto stream = static_cast(stream_user_data); + + auto len = + std::min(dyn_buf->size(), static_cast(stream->dyndataleft)); + + vec[0].base = dyn_buf->data(); + vec[0].len = len; + + stream->dynbuflen += len; + stream->dyndataleft -= len; + + if (stream->dyndataleft == 0) { + *pflags |= NGHTTP3_DATA_FLAG_EOF; + if (config.send_trailers) { + *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM; + auto stream_id_str = util::format_uint(as_unsigned(stream_id)); + auto trailers = std::to_array({ + util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str), + }); + + if (auto rv = nghttp3_conn_submit_trailers( + conn, stream_id, trailers.data(), trailers.size()); + rv != 0) { + std::println(stderr, "nghttp3_conn_submit_trailers: {}", + nghttp3_strerror(rv)); + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + } + } + + return 1; +} +} // namespace + +std::expected ProtoCodec::start_response(Stream *stream) { + // TODO This should be handled by nghttp3 + if (stream->uri.empty() || stream->method.empty()) { + return send_status_response(stream, 400); + } + + auto maybe_req = stream->request_path(); + if (!maybe_req) { + return send_status_response(stream, 400); + } + + const auto &req = *maybe_req; + + uint64_t content_length; + nghttp3_data_reader dr{}; + auto content_type = "text/plain"sv; + + auto maybe_dyn_len = stream->find_dyn_length(req.path); + if (!maybe_dyn_len) { + auto path = config.htdocs; + path /= std::filesystem::path{req.path}.relative_path(); + + auto maybe_fe = stream->open_file(path); + if (!maybe_fe) { + return send_status_response(stream, 404); + } + + const auto &fe = *maybe_fe; + + if (fe.flags & FILE_ENTRY_TYPE_DIR) { + return send_redirect_response(stream, 308, req.path + '/'); + } + + content_length = fe.len; + + if (stream->method != "HEAD") { + stream->map_file(fe); + } + + dr.read_data = read_data; + + auto ext = path.extension(); + if (!ext.empty() && ext != ".") { + auto it = config.mime_types.find(ext.native()); + if (it != std::ranges::end(config.mime_types)) { + content_type = (*it).second; + } + } + } else { + content_length = *maybe_dyn_len; + stream->dynresp = true; + dr.read_data = dyn_read_data; + + if (stream->method != "HEAD") { + stream->dyndataleft = content_length; + } + + content_type = "application/octet-stream"sv; + } + + auto content_length_str = util::format_uint(content_length); + + std::array nva{ + util::make_nv_nn(":status"sv, "200"sv), + util::make_nv_nn("server"sv, NGTCP2_SERVER), + util::make_nv_nn("content-type"sv, content_type), + util::make_nv_nc("content-length"sv, content_length_str), + }; + + size_t nvlen = 4; + + std::string prival; + + if (req.pri.urgency != -1 || req.pri.inc != -1) { + nghttp3_pri pri; + + if (auto rv = + nghttp3_conn_get_stream_priority(httpconn_, &pri, stream->stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_get_stream_priority: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + if (req.pri.urgency != -1) { + pri.urgency = as_unsigned(req.pri.urgency); + } + if (req.pri.inc != -1) { + pri.inc = static_cast(req.pri.inc); + } + + if (auto rv = nghttp3_conn_set_server_stream_priority( + httpconn_, stream->stream_id, &pri); + rv != 0) { + std::println(stderr, "nghttp3_conn_set_server_stream_priority: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + prival = "u="; + prival += static_cast(pri.urgency + '0'); + prival += ",i"; + if (!pri.inc) { + prival += "=?0"; + } + + nva[nvlen++] = util::make_nv_nc("priority"sv, prival); + } + + if (!config.quiet) { + debug::print_http_response_headers(stream->stream_id, nva.data(), nvlen); + } + + if (auto rv = nghttp3_conn_submit_response(httpconn_, stream->stream_id, + nva.data(), nvlen, &dr); + rv != 0) { + std::println(stderr, "nghttp3_conn_submit_response: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + if (config.send_trailers && !maybe_dyn_len) { + auto stream_id_str = util::format_uint(as_unsigned(stream->stream_id)); + auto trailers = std::to_array({ + util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str), + }); + + if (auto rv = nghttp3_conn_submit_trailers( + httpconn_, stream->stream_id, trailers.data(), trailers.size()); + rv != 0) { + std::println(stderr, "nghttp3_conn_submit_trailers: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + } + + return {}; +} + +std::expected +ProtoCodec::send_status_response(Stream *stream, unsigned int status_code, + std::vector extra_headers) { + stream->status_resp_body = make_status_body(status_code); + + auto status_code_str = util::format_uint(status_code); + auto content_length_str = util::format_uint(stream->status_resp_body.size()); + + std::vector nva(4 + extra_headers.size()); + nva[0] = util::make_nv_nc(":status"sv, status_code_str); + nva[1] = util::make_nv_nn("server"sv, NGTCP2_SERVER); + nva[2] = util::make_nv_nn("content-type"sv, "text/html; charset=utf-8"); + nva[3] = util::make_nv_nc("content-length"sv, content_length_str); + for (size_t i = 0; i < extra_headers.size(); ++i) { + auto &hdr = extra_headers[i]; + auto &nv = nva[4 + i]; + nv = util::make_nv_cc(hdr.name, hdr.value); + } + + stream->resp_data = as_uint8_span(std::span{stream->status_resp_body}); + + nghttp3_data_reader dr{ + .read_data = read_data, + }; + + if (auto rv = nghttp3_conn_submit_response(httpconn_, stream->stream_id, + nva.data(), nva.size(), &dr); + rv != 0) { + std::println(stderr, "nghttp3_conn_submit_response: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + if (config.send_trailers) { + auto stream_id_str = util::format_uint(as_unsigned(stream->stream_id)); + auto trailers = std::to_array({ + util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str), + }); + + if (auto rv = nghttp3_conn_submit_trailers( + httpconn_, stream->stream_id, trailers.data(), trailers.size()); + rv != 0) { + std::println(stderr, "nghttp3_conn_submit_trailers: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + } + + handler_->shutdown_read(stream->stream_id, NGHTTP3_H3_NO_ERROR); + + return {}; +} + +std::expected +ProtoCodec::send_redirect_response(Stream *stream, unsigned int status_code, + std::string_view path) { + return send_status_response(stream, status_code, {{"location", path}}); +} + +std::expected ProtoCodec::setup_httpconn() { + if (httpconn_) { + return {}; + } + + if (ngtcp2_conn_get_streams_uni_left2(conn_) < 3) { + std::println(stderr, + "peer does not allow at least 3 unidirectional streams."); + return std::unexpected{Error::QUIC}; + } + + static constexpr auto callbacks = nghttp3_callbacks{ + .acked_stream_data = ::http_acked_stream_data, + .recv_data = ::http_recv_data, + .deferred_consume = ::http_deferred_consume, + .begin_headers = ::http_begin_request_headers, + .recv_header = ::http_recv_request_header, + .end_headers = ::http_end_request_headers, + .stop_sending = ::http_stop_sending, + .end_stream = ::http_end_stream, + .reset_stream = ::http_reset_stream, + .rand = rand_bytes, + .recv_settings2 = ::http_recv_settings, + }; + nghttp3_settings settings; + nghttp3_settings_default(&settings); + settings.qpack_max_dtable_capacity = 4096; + settings.qpack_blocked_streams = 100; + + nghttp3_vec origin_list; + + if (config.origin_list) { + origin_list.base = config.origin_list->data(); + origin_list.len = config.origin_list->size(); + + settings.origin_list = &origin_list; + } + + auto mem = nghttp3_mem_default(); + + if (auto rv = + nghttp3_conn_server_new(&httpconn_, &callbacks, &settings, mem, this); + rv != 0) { + std::println(stderr, "nghttp3_conn_server_new: {}", nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + auto params = ngtcp2_conn_get_local_transport_params2(conn_); + + nghttp3_conn_set_max_client_streams_bidi(httpconn_, + params->initial_max_streams_bidi); + + int64_t ctrl_stream_id; + + if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr); + rv != 0) { + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + + if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_bind_control_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + if (!config.quiet) { + std::println(stderr, "http: control stream={:#x}", ctrl_stream_id); + } + + int64_t qpack_enc_stream_id, qpack_dec_stream_id; + + if (auto rv = + ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr); + rv != 0) { + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + + if (auto rv = + ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr); + rv != 0) { + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; + } + + if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id, + qpack_dec_stream_id); + rv != 0) { + std::println(stderr, "nghttp3_conn_bind_qpack_streams: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; + } + + if (!config.quiet) { + std::println(stderr, "http: QPACK streams encoder={:#x} decoder={:#x}", + qpack_enc_stream_id, qpack_dec_stream_id); + } + + return {}; +} + +void ProtoCodec::http_stream_close(int64_t stream_id, uint64_t app_error_code) { + if (!ngtcp2_is_bidi_stream(stream_id)) { + return; + } + + if (!config.quiet) { + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); + } +} + +} // namespace ngtcp2 diff --git a/deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.h b/deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.h new file mode 100644 index 00000000000000..08b16b79b7eaee --- /dev/null +++ b/deps/ngtcp2/ngtcp2/examples/http3_server_proto_codec.h @@ -0,0 +1,120 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef HTTP3_SERVER_PROTO_CODEC_H +#define HTTP3_SERVER_PROTO_CODEC_H + +#ifdef HAVE_CONFIG_H +# include +#endif // defined(HAVE_CONFIG_H) + +#include +#include + +#include +#include + +#include "shared.h" +#include "server_base.h" + +struct Stream; +class Handler; + +namespace ngtcp2 { + +class ProtoCodec { +public: + ProtoCodec(Handler *handler, ngtcp2_ccerr &last_error); + ~ProtoCodec(); + + std::expected acked_stream_data_offset(int64_t stream_id, + uint64_t datalen); + + std::expected on_stream_reset(int64_t stream_id); + + std::expected on_stream_stop_sending(int64_t stream_id); + + void extend_max_remote_streams_bidi(uint64_t max_streams); + + std::expected extend_max_stream_data(int64_t stream_id, + uint64_t max_data); + + std::expected on_app_tx_ready(); + + ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, + size_t destlen, ngtcp2_tstamp ts); + + std::expected recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + + std::expected on_stream_close(int64_t stream_id, + uint64_t app_error_code); + + std::expected start_response(Stream *stream); + + // The following functions are made public so that they can be + // called from nghttp3 callback functions. + void http_acked_stream_data(Stream *stream, uint64_t datalen); + + void http_consume(int64_t stream_id, size_t nconsumed); + + void http_begin_request_headers(int64_t stream_id); + + void http_recv_request_header(Stream *stream, int32_t token, + nghttp3_rcbuf *name, nghttp3_rcbuf *value); + + std::expected http_end_request_headers(Stream *stream); + + std::expected http_stop_sending(int64_t stream_id, + uint64_t app_error_code); + + std::expected http_end_stream(Stream *stream); + + std::expected http_reset_stream(int64_t stream_id, + uint64_t app_error_code); + + static constexpr auto protocol = AppProtocol::H3; + +private: + std::expected + send_status_response(Stream *stream, unsigned int status_code, + std::vector extra_headers = {}); + + std::expected send_redirect_response(Stream *stream, + unsigned int status_code, + std::string_view path); + + std::expected setup_httpconn(); + + void http_stream_close(int64_t stream_id, uint64_t app_error_code); + + Handler *handler_; + ngtcp2_conn *conn_; + ngtcp2_ccerr &last_error_; + nghttp3_conn *httpconn_{}; +}; + +} // namespace ngtcp2 + +#endif // !defined(HTTP3_SERVER_PROTO_CODEC_H) diff --git a/deps/ngtcp2/ngtcp2/examples/server.cc b/deps/ngtcp2/ngtcp2/examples/server.cc index 35b387c36fd1e5..20f4a04d21504a 100644 --- a/deps/ngtcp2/ngtcp2/examples/server.cc +++ b/deps/ngtcp2/ngtcp2/examples/server.cc @@ -57,13 +57,9 @@ using namespace ngtcp2; using namespace std::literals; -namespace { -constexpr size_t NGTCP2_SV_SCIDLEN = 18; -} // namespace +constexpr auto NGTCP2_SV_SCIDLEN = 18UZ; -namespace { -constexpr size_t max_preferred_versionslen = 4; -} // namespace +constexpr auto max_preferred_versionslen = 4UZ; namespace { auto randgen = util::make_mt19937(); @@ -72,13 +68,13 @@ auto randgen = util::make_mt19937(); Config config; Stream::Stream(int64_t stream_id, Handler *handler) - : stream_id{stream_id}, handler{handler} {} - -namespace { -constexpr auto NGTCP2_SERVER = "nghttp3/ngtcp2 server"sv; -} // namespace + : stream_id{stream_id}, handler{handler} { +#ifdef WITH_EXAMPLE_HQ_PROTO_CODEC + htp.data = this; + http_parser_init(&htp, HTTP_REQUEST); +#endif // WITH_EXAMPLE_HQ_PROTO_CODEC +} -namespace { std::string make_status_body(unsigned int status_code) { auto status_string = util::format_uint(status_code); auto reason_phrase = http::get_reason_phrase(status_code); @@ -100,19 +96,12 @@ std::string make_status_body(unsigned int status_code) { body += ""; return body; } -} // namespace -struct Request { - std::string path; - struct { - int32_t urgency; - int inc; - } pri{}; -}; +std::expected Stream::start_response() { + return handler->start_response(this); +} -namespace { -std::expected request_path(std::string_view uri, - bool is_connect) { +std::expected Stream::request_path() { urlparse_url u; Request req{ .pri{ @@ -120,6 +109,7 @@ std::expected request_path(std::string_view uri, .inc = -1, }, }; + auto is_connect = method == "CONNECT"; if (auto rv = urlparse_parse_url(uri.data(), uri.size(), is_connect, &u); rv != 0) { @@ -196,25 +186,14 @@ std::expected request_path(std::string_view uri, } return req; } -} // namespace - -enum FileEntryFlag { - FILE_ENTRY_TYPE_DIR = 0x1, -}; - -struct FileEntry { - uint64_t len{}; - void *map{}; - int fd{}; - uint8_t flags{}; -}; namespace { std::unordered_map file_cache; } // namespace -std::expected Stream::open_file(const std::string &path) { - auto it = file_cache.find(path); +std::expected +Stream::open_file(const std::filesystem::path &path) { + auto it = file_cache.find(path.native()); if (it != std::ranges::end(file_cache)) { return (*it).second; } @@ -248,14 +227,13 @@ std::expected Stream::open_file(const std::string &path) { } } - file_cache.emplace(path, fe); + file_cache.emplace(path.native(), fe); return fe; } void Stream::map_file(const FileEntry &fe) { - data = static_cast(fe.map); - datalen = fe.len; + resp_data = {static_cast(fe.map), fe.len}; } std::expected Stream::find_dyn_length(std::string_view path) { @@ -285,63 +263,6 @@ std::expected Stream::find_dyn_length(std::string_view path) { return n; } -namespace { -nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, - size_t veccnt, uint32_t *pflags, void *user_data, - void *stream_user_data) { - auto stream = static_cast(stream_user_data); - - vec[0].base = stream->data; - vec[0].len = stream->datalen; - *pflags |= NGHTTP3_DATA_FLAG_EOF; - if (config.send_trailers) { - *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM; - } - - return 1; -} -} // namespace - -auto dyn_buf = std::make_unique>(); - -namespace { -nghttp3_ssize dyn_read_data(nghttp3_conn *conn, int64_t stream_id, - nghttp3_vec *vec, size_t veccnt, uint32_t *pflags, - void *user_data, void *stream_user_data) { - auto stream = static_cast(stream_user_data); - - auto len = - std::min(dyn_buf->size(), static_cast(stream->dyndataleft)); - - vec[0].base = dyn_buf->data(); - vec[0].len = len; - - stream->dynbuflen += len; - stream->dyndataleft -= len; - - if (stream->dyndataleft == 0) { - *pflags |= NGHTTP3_DATA_FLAG_EOF; - if (config.send_trailers) { - *pflags |= NGHTTP3_DATA_FLAG_NO_END_STREAM; - auto stream_id_str = util::format_uint(as_unsigned(stream_id)); - auto trailers = std::to_array({ - util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str), - }); - - if (auto rv = nghttp3_conn_submit_trailers( - conn, stream_id, trailers.data(), trailers.size()); - rv != 0) { - std::println(stderr, "nghttp3_conn_submit_trailers: {}", - nghttp3_strerror(rv)); - return NGHTTP3_ERR_CALLBACK_FAILURE; - } - } - } - - return 1; -} -} // namespace - void Stream::http_acked_stream_data(uint64_t datalen) { if (!dynresp) { return; @@ -352,210 +273,6 @@ void Stream::http_acked_stream_data(uint64_t datalen) { dynbuflen -= datalen; } -std::expected -Stream::send_status_response(nghttp3_conn *httpconn, unsigned int status_code, - const std::vector &extra_headers) { - status_resp_body = make_status_body(status_code); - - auto status_code_str = util::format_uint(status_code); - auto content_length_str = util::format_uint(status_resp_body.size()); - - std::vector nva(4 + extra_headers.size()); - nva[0] = util::make_nv_nc(":status"sv, status_code_str); - nva[1] = util::make_nv_nn("server"sv, NGTCP2_SERVER); - nva[2] = util::make_nv_nn("content-type"sv, "text/html; charset=utf-8"); - nva[3] = util::make_nv_nc("content-length"sv, content_length_str); - for (size_t i = 0; i < extra_headers.size(); ++i) { - auto &hdr = extra_headers[i]; - auto &nv = nva[4 + i]; - nv = util::make_nv_cc(hdr.name, hdr.value); - } - - data = const_cast( - reinterpret_cast(status_resp_body.data())); - datalen = status_resp_body.size(); - - nghttp3_data_reader dr{ - .read_data = read_data, - }; - - if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(), - nva.size(), &dr); - rv != 0) { - std::println(stderr, "nghttp3_conn_submit_response: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - if (config.send_trailers) { - auto stream_id_str = util::format_uint(as_unsigned(stream_id)); - auto trailers = std::to_array({ - util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str), - }); - - if (auto rv = nghttp3_conn_submit_trailers( - httpconn, stream_id, trailers.data(), trailers.size()); - rv != 0) { - std::println(stderr, "nghttp3_conn_submit_trailers: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - } - - handler->shutdown_read(stream_id, NGHTTP3_H3_NO_ERROR); - - return {}; -} - -std::expected -Stream::send_redirect_response(nghttp3_conn *httpconn, unsigned int status_code, - std::string_view path) { - return send_status_response(httpconn, status_code, {{"location", path}}); -} - -std::expected Stream::start_response(nghttp3_conn *httpconn) { - // TODO This should be handled by nghttp3 - if (uri.empty() || method.empty()) { - return send_status_response(httpconn, 400); - } - - auto maybe_req = request_path(uri, method == "CONNECT"); - if (!maybe_req) { - return send_status_response(httpconn, 400); - } - - const auto &req = *maybe_req; - - uint64_t content_length; - nghttp3_data_reader dr{}; - auto content_type = "text/plain"sv; - - auto maybe_dyn_len = find_dyn_length(req.path); - if (!maybe_dyn_len) { - auto path = config.htdocs + req.path; - auto maybe_fe = open_file(path); - if (!maybe_fe) { - return send_status_response(httpconn, 404); - } - - const auto &fe = *maybe_fe; - - if (fe.flags & FILE_ENTRY_TYPE_DIR) { - return send_redirect_response( - httpconn, 308, path.substr(config.htdocs.size() - 1) + '/'); - } - - content_length = fe.len; - - if (method != "HEAD") { - map_file(fe); - } - - dr.read_data = read_data; - - auto ext = std::ranges::end(req.path) - 1; - for (; ext != std::ranges::begin(req.path) && *ext != '.' && *ext != '/'; - --ext) - ; - if (*ext == '.') { - ++ext; - auto it = - config.mime_types.find(std::string{ext, std::ranges::end(req.path)}); - if (it != std::ranges::end(config.mime_types)) { - content_type = (*it).second; - } - } - } else { - content_length = *maybe_dyn_len; - dynresp = true; - dr.read_data = dyn_read_data; - - if (method != "HEAD") { - datalen = content_length; - dyndataleft = content_length; - } - - content_type = "application/octet-stream"sv; - } - - auto content_length_str = util::format_uint(content_length); - - std::array nva{ - util::make_nv_nn(":status"sv, "200"sv), - util::make_nv_nn("server"sv, NGTCP2_SERVER), - util::make_nv_nn("content-type"sv, content_type), - util::make_nv_nc("content-length"sv, content_length_str), - }; - - size_t nvlen = 4; - - std::string prival; - - if (req.pri.urgency != -1 || req.pri.inc != -1) { - nghttp3_pri pri; - - if (auto rv = nghttp3_conn_get_stream_priority(httpconn, &pri, stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_get_stream_priority: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - if (req.pri.urgency != -1) { - pri.urgency = as_unsigned(req.pri.urgency); - } - if (req.pri.inc != -1) { - pri.inc = static_cast(req.pri.inc); - } - - if (auto rv = - nghttp3_conn_set_server_stream_priority(httpconn, stream_id, &pri); - rv != 0) { - std::println(stderr, "nghttp3_conn_set_server_stream_priority: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - prival = "u="; - prival += static_cast(pri.urgency + '0'); - prival += ",i"; - if (!pri.inc) { - prival += "=?0"; - } - - nva[nvlen++] = util::make_nv_nc("priority"sv, prival); - } - - if (!config.quiet) { - debug::print_http_response_headers(stream_id, nva.data(), nvlen); - } - - if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(), - nvlen, &dr); - rv != 0) { - std::println(stderr, "nghttp3_conn_submit_response: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - if (config.send_trailers && !maybe_dyn_len) { - auto stream_id_str = util::format_uint(as_unsigned(stream_id)); - auto trailers = std::to_array({ - util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str), - }); - - if (auto rv = nghttp3_conn_submit_trailers( - httpconn, stream_id, trailers.data(), trailers.size()); - rv != 0) { - std::println(stderr, "nghttp3_conn_submit_trailers: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - } - - return {}; -} - namespace { void writecb(struct ev_loop *loop, ev_io *w, int revents) { auto h = static_cast(w->data); @@ -573,7 +290,7 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { auto s = h->server(); auto conn = h->conn(); - if (ngtcp2_conn_in_closing_period(conn)) { + if (ngtcp2_conn_in_closing_period2(conn)) { if (!config.quiet) { std::println(stderr, "Closing Period is over"); } @@ -581,7 +298,7 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { s->remove(h); return; } - if (ngtcp2_conn_in_draining_period(conn)) { + if (ngtcp2_conn_in_draining_period2(conn)) { if (!config.quiet) { std::println(stderr, "Draining Period is over"); } @@ -641,10 +358,6 @@ Handler::~Handler() { ev_timer_stop(loop_, &timer_); ev_io_stop(loop_, &wev_); - if (httpconn_) { - nghttp3_conn_del(httpconn_); - } - if (qlog_) { fclose(qlog_); } @@ -683,7 +396,7 @@ std::expected Handler::handshake_completed() { std::array token; - auto path = ngtcp2_conn_get_path(conn_); + auto path = ngtcp2_conn_get_path2(conn_); auto t = util::system_clock_now(); auto tokenlen = ngtcp2_crypto_generate_regular_token( @@ -764,18 +477,7 @@ int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id, std::expected Handler::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) { - if (!httpconn_) { - return {}; - } - - if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen); - rv != 0) { - std::println(stderr, "nghttp3_conn_add_ack_offset: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - return {}; + return proto_codec_->acked_stream_data_offset(stream_id, datalen); } namespace { @@ -796,16 +498,20 @@ void Handler::on_stream_open(int64_t stream_id) { streams_.emplace(stream_id, std::make_unique(stream_id, this)); } +Stream *Handler::find_stream(int64_t stream_id) const { + auto it = streams_.find(stream_id); + if (it == std::ranges::end(streams_)) { + return nullptr; + } + + return (*it).second.get(); +} + namespace { int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - - if (!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) { - app_error_code = NGHTTP3_H3_NO_ERROR; - } - if (!h->on_stream_close(stream_id, app_error_code)) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -826,15 +532,7 @@ int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size, } // namespace std::expected Handler::on_stream_reset(int64_t stream_id) { - if (httpconn_) { - if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - } - return {}; + return proto_codec_->on_stream_reset(stream_id); } namespace { @@ -850,22 +548,11 @@ int stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id, } // namespace std::expected Handler::on_stream_stop_sending(int64_t stream_id) { - if (!httpconn_) { - return {}; - } - - if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - return {}; + return proto_codec_->on_stream_stop_sending(stream_id); } namespace { -void rand_bytes(uint8_t *dest, size_t destlen) { +void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { if (!util::generate_secure_random({dest, destlen})) { assert(0); abort(); @@ -873,12 +560,6 @@ void rand_bytes(uint8_t *dest, size_t destlen) { } } // namespace -namespace { -void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { - rand_bytes(dest, destlen); -} -} // namespace - namespace { int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, ngtcp2_stateless_reset_token *token, size_t cidlen, @@ -974,345 +655,7 @@ int extend_max_remote_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams, } // namespace void Handler::extend_max_remote_streams_bidi(uint64_t max_streams) { - if (!httpconn_) { - return; - } - - nghttp3_conn_set_max_client_streams_bidi(httpconn_, max_streams); -} - -namespace { -int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data, - size_t datalen, void *user_data, void *stream_user_data) { - if (!config.quiet && !config.no_http_dump) { - debug::print_http_data(stream_id, {data, datalen}); - } - auto h = static_cast(user_data); - h->http_consume(stream_id, datalen); - return 0; -} -} // namespace - -namespace { -int http_deferred_consume(nghttp3_conn *conn, int64_t stream_id, - size_t nconsumed, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - h->http_consume(stream_id, nconsumed); - return 0; -} -} // namespace - -void Handler::http_consume(int64_t stream_id, size_t nconsumed) { - ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, nconsumed); - ngtcp2_conn_extend_max_offset(conn_, nconsumed); -} - -namespace { -int http_begin_request_headers(nghttp3_conn *conn, int64_t stream_id, - void *user_data, void *stream_user_data) { - if (!config.quiet) { - debug::print_http_begin_request_headers(stream_id); - } - - auto h = static_cast(user_data); - h->http_begin_request_headers(stream_id); - return 0; -} -} // namespace - -void Handler::http_begin_request_headers(int64_t stream_id) { - auto it = streams_.find(stream_id); - assert(it != std::ranges::end(streams_)); - auto &stream = (*it).second; - - nghttp3_conn_set_stream_user_data(httpconn_, stream_id, stream.get()); -} - -namespace { -int http_recv_request_header(nghttp3_conn *conn, int64_t stream_id, - int32_t token, nghttp3_rcbuf *name, - nghttp3_rcbuf *value, uint8_t flags, - void *user_data, void *stream_user_data) { - if (!config.quiet) { - debug::print_http_header(stream_id, name, value, flags); - } - - auto h = static_cast(user_data); - auto stream = static_cast(stream_user_data); - h->http_recv_request_header(stream, token, name, value); - return 0; -} -} // namespace - -void Handler::http_recv_request_header(Stream *stream, int32_t token, - nghttp3_rcbuf *name, - nghttp3_rcbuf *value) { - auto v = nghttp3_rcbuf_get_buf(value); - - switch (token) { - case NGHTTP3_QPACK_TOKEN__PATH: - stream->uri = std::string{v.base, v.base + v.len}; - break; - case NGHTTP3_QPACK_TOKEN__METHOD: - stream->method = std::string{v.base, v.base + v.len}; - break; - case NGHTTP3_QPACK_TOKEN__AUTHORITY: - stream->authority = std::string{v.base, v.base + v.len}; - break; - } -} - -namespace { -int http_end_request_headers(nghttp3_conn *conn, int64_t stream_id, int fin, - void *user_data, void *stream_user_data) { - if (!config.quiet) { - debug::print_http_end_headers(stream_id); - } - - auto h = static_cast(user_data); - auto stream = static_cast(stream_user_data); - if (!h->http_end_request_headers(stream)) { - return NGHTTP3_ERR_CALLBACK_FAILURE; - } - return 0; -} -} // namespace - -std::expected Handler::http_end_request_headers(Stream *stream) { - if (config.early_response) { - if (auto rv = start_response(stream); !rv) { - return rv; - } - - shutdown_read(stream->stream_id, NGHTTP3_H3_NO_ERROR); - } - return {}; -} - -namespace { -int http_end_stream(nghttp3_conn *conn, int64_t stream_id, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - auto stream = static_cast(stream_user_data); - if (!h->http_end_stream(stream)) { - return NGHTTP3_ERR_CALLBACK_FAILURE; - } - return 0; -} -} // namespace - -std::expected Handler::http_end_stream(Stream *stream) { - if (!config.early_response) { - return start_response(stream); - } - return {}; -} - -std::expected Handler::start_response(Stream *stream) { - return stream->start_response(httpconn_); -} - -namespace { -int http_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, - uint64_t datalen, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - auto stream = static_cast(stream_user_data); - h->http_acked_stream_data(stream, datalen); - return 0; -} -} // namespace - -void Handler::http_acked_stream_data(Stream *stream, uint64_t datalen) { - stream->http_acked_stream_data(datalen); -} - -void Handler::http_stream_close(int64_t stream_id, uint64_t app_error_code) { - if (!ngtcp2_is_bidi_stream(stream_id)) { - return; - } - - assert(!ngtcp2_conn_is_local_stream(conn_, stream_id)); - ngtcp2_conn_extend_max_streams_bidi(conn_, 1); - - auto it = streams_.find(stream_id); - if (it == std::ranges::end(streams_)) { - return; - } - - if (!config.quiet) { - std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", - stream_id, app_error_code); - } - - streams_.erase(it); -} - -namespace { -int http_stop_sending(nghttp3_conn *conn, int64_t stream_id, - uint64_t app_error_code, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - if (!h->http_stop_sending(stream_id, app_error_code)) { - return NGHTTP3_ERR_CALLBACK_FAILURE; - } - return 0; -} -} // namespace - -std::expected Handler::http_stop_sending(int64_t stream_id, - uint64_t app_error_code) { - if (auto rv = - ngtcp2_conn_shutdown_stream_read(conn_, 0, stream_id, app_error_code); - rv != 0) { - std::println(stderr, "ngtcp2_conn_shutdown_stream_read: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - return {}; -} - -namespace { -int http_reset_stream(nghttp3_conn *conn, int64_t stream_id, - uint64_t app_error_code, void *user_data, - void *stream_user_data) { - auto h = static_cast(user_data); - if (!h->http_reset_stream(stream_id, app_error_code)) { - return NGHTTP3_ERR_CALLBACK_FAILURE; - } - return 0; -} -} // namespace - -std::expected Handler::http_reset_stream(int64_t stream_id, - uint64_t app_error_code) { - if (auto rv = - ngtcp2_conn_shutdown_stream_write(conn_, 0, stream_id, app_error_code); - rv != 0) { - std::println(stderr, "ngtcp2_conn_shutdown_stream_write: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - return {}; -} - -namespace { -int http_recv_settings(nghttp3_conn *conn, - const nghttp3_proto_settings *settings, - void *conn_user_data) { - if (!config.quiet) { - debug::print_http_settings(settings); - } - - return 0; -} -} // namespace - -std::expected Handler::setup_httpconn() { - if (httpconn_) { - return {}; - } - - if (ngtcp2_conn_get_streams_uni_left(conn_) < 3) { - std::println(stderr, - "peer does not allow at least 3 unidirectional streams."); - return std::unexpected{Error::QUIC}; - } - - nghttp3_callbacks callbacks{ - .acked_stream_data = ::http_acked_stream_data, - .recv_data = ::http_recv_data, - .deferred_consume = ::http_deferred_consume, - .begin_headers = ::http_begin_request_headers, - .recv_header = ::http_recv_request_header, - .end_headers = ::http_end_request_headers, - .stop_sending = ::http_stop_sending, - .end_stream = ::http_end_stream, - .reset_stream = ::http_reset_stream, - .rand = rand_bytes, - .recv_settings2 = ::http_recv_settings, - }; - nghttp3_settings settings; - nghttp3_settings_default(&settings); - settings.qpack_max_dtable_capacity = 4096; - settings.qpack_blocked_streams = 100; - - nghttp3_vec origin_list; - - if (config.origin_list) { - origin_list.base = config.origin_list->data(); - origin_list.len = config.origin_list->size(); - - settings.origin_list = &origin_list; - } - - auto mem = nghttp3_mem_default(); - - if (auto rv = - nghttp3_conn_server_new(&httpconn_, &callbacks, &settings, mem, this); - rv != 0) { - std::println(stderr, "nghttp3_conn_server_new: {}", nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - auto params = ngtcp2_conn_get_local_transport_params(conn_); - - nghttp3_conn_set_max_client_streams_bidi(httpconn_, - params->initial_max_streams_bidi); - - int64_t ctrl_stream_id; - - if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr); - rv != 0) { - std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_bind_control_stream: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - if (!config.quiet) { - std::println(stderr, "http: control stream={:#x}", ctrl_stream_id); - } - - int64_t qpack_enc_stream_id, qpack_dec_stream_id; - - if (auto rv = - ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr); - rv != 0) { - std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = - ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr); - rv != 0) { - std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", - ngtcp2_strerror(rv)); - return std::unexpected{Error::QUIC}; - } - - if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id, - qpack_dec_stream_id); - rv != 0) { - std::println(stderr, "nghttp3_conn_bind_qpack_streams: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - - if (!config.quiet) { - std::println(stderr, "http: QPACK streams encoder={:#x} decoder={:#x}", - qpack_enc_stream_id, qpack_dec_stream_id); - } - - return {}; + proto_codec_->extend_max_remote_streams_bidi(max_streams); } namespace { @@ -1329,12 +672,7 @@ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, std::expected Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { - if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) { - std::println(stderr, "nghttp3_conn_unblock_stream: {}", - nghttp3_strerror(rv)); - return std::unexpected{Error::HTTP3}; - } - return {}; + return proto_codec_->extend_max_stream_data(stream_id, max_data); } namespace { @@ -1345,7 +683,7 @@ int recv_tx_key(ngtcp2_conn *conn, ngtcp2_encryption_level level, } auto h = static_cast(user_data); - if (!h->setup_httpconn()) { + if (!h->on_app_tx_ready()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1353,6 +691,14 @@ int recv_tx_key(ngtcp2_conn *conn, ngtcp2_encryption_level level, } } // namespace +std::expected Handler::on_app_tx_ready() { + return proto_codec_->on_app_tx_ready(); +} + +std::expected Handler::start_response(Stream *stream) { + return proto_codec_->start_response(stream); +} + namespace { void write_qlog(void *user_data, uint32_t flags, const void *data, size_t datalen) { @@ -1372,7 +718,7 @@ Handler::init(const Endpoint &ep, const Address &local_addr, const ngtcp2_cid *scid, const ngtcp2_cid *ocid, std::span token, ngtcp2_token_type token_type, uint32_t version, TLSServerContext &tls_ctx) { - auto callbacks = ngtcp2_callbacks{ + static constexpr auto callbacks = ngtcp2_callbacks{ .recv_client_initial = ngtcp2_crypto_recv_client_initial_cb, .recv_crypto_data = ::recv_crypto_data, .handshake_completed = ::handshake_completed, @@ -1408,7 +754,7 @@ Handler::init(const Endpoint &ep, const Address &local_addr, ngtcp2_settings settings; ngtcp2_settings_default(&settings); - settings.log_printf = config.quiet ? nullptr : debug::log_printf; + settings.log_write = config.quiet ? nullptr : debug::log_write; settings.initial_ts = util::timestamp(); settings.token = token.data(); settings.tokenlen = token.size(); @@ -1425,13 +771,12 @@ Handler::init(const Endpoint &ep, const Address &local_addr, settings.no_tx_udp_payload_size_shaping = 1; } if (!config.qlog_dir.empty()) { - auto path = std::string{config.qlog_dir}; - path += '/'; - path += util::format_hex(scid_.data, as_signed(scid_.datalen)); + auto path = config.qlog_dir; + path /= util::format_hex(scid_.data, as_signed(scid_.datalen)); path += ".sqlog"; qlog_ = fopen(path.c_str(), "w"); if (qlog_ == nullptr) { - std::println(stderr, "Could not open qlog file {}: {}", path, + std::println(stderr, "Could not open qlog file {}: {}", path.native(), strerror(errno)); return std::unexpected{Error::IO}; } @@ -1539,6 +884,8 @@ Handler::init(const Endpoint &ep, const Address &local_addr, return std::unexpected{Error::QUIC}; } + proto_codec_ = std::make_unique(this, last_error_); + if (auto rv = tls_session_.init(tls_ctx, this); !rv) { return rv; } @@ -1578,7 +925,7 @@ std::expected Handler::feed_data(const Endpoint &ep, case NGTCP2_ERR_CRYPTO: if (!last_error_.error_code) { ngtcp2_ccerr_set_tls_alert( - &last_error_, ngtcp2_conn_get_tls_alert(conn_), nullptr, 0); + &last_error_, ngtcp2_conn_get_tls_alert2(conn_), nullptr, 0); } break; default: @@ -1618,8 +965,8 @@ std::expected Handler::handle_expiry() { } std::expected Handler::on_write() { - if (ngtcp2_conn_in_closing_period(conn_) || - ngtcp2_conn_in_draining_period(conn_)) { + if (ngtcp2_conn_in_closing_period2(conn_) || + ngtcp2_conn_in_draining_period2(conn_)) { return {}; } @@ -1655,88 +1002,7 @@ ngtcp2_ssize write_pkt(ngtcp2_conn *conn, ngtcp2_path *path, ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts) { - std::array vec; - - for (;;) { - int64_t stream_id = -1; - int fin = 0; - nghttp3_ssize sveccnt = 0; - - if (httpconn_ && ngtcp2_conn_get_max_data_left(conn_)) { - sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin, - vec.data(), vec.size()); - if (sveccnt < 0) { - std::println(stderr, "nghttp3_conn_writev_stream: {}", - nghttp3_strerror(static_cast(sveccnt))); - ngtcp2_ccerr_set_application_error( - &last_error_, - nghttp3_err_infer_quic_app_error_code(static_cast(sveccnt)), - nullptr, 0); - return NGTCP2_ERR_CALLBACK_FAILURE; - } - } - - ngtcp2_ssize ndatalen; - auto v = vec.data(); - auto vcnt = static_cast(sveccnt); - - uint32_t flags = - NGTCP2_WRITE_STREAM_FLAG_MORE | NGTCP2_WRITE_STREAM_FLAG_PADDING; - if (fin) { - flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; - } - - auto nwrite = ngtcp2_conn_writev_stream( - conn_, path, pi, dest, destlen, &ndatalen, flags, stream_id, - reinterpret_cast(v), vcnt, ts); - if (nwrite < 0) { - switch (nwrite) { - case NGTCP2_ERR_STREAM_DATA_BLOCKED: - assert(ndatalen == -1); - nghttp3_conn_block_stream(httpconn_, stream_id); - continue; - case NGTCP2_ERR_STREAM_SHUT_WR: - assert(ndatalen == -1); - nghttp3_conn_shutdown_stream_write(httpconn_, stream_id); - continue; - case NGTCP2_ERR_WRITE_MORE: - assert(ndatalen >= 0); - if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, - as_unsigned(ndatalen)); - rv != 0) { - std::println(stderr, "nghttp3_conn_add_write_offset: {}", - nghttp3_strerror(rv)); - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, - 0); - return NGTCP2_ERR_CALLBACK_FAILURE; - } - continue; - } - - assert(ndatalen == -1); - - std::println(stderr, "ngtcp2_conn_writev_stream: {}", - ngtcp2_strerror(static_cast(nwrite))); - ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, - 0); - return NGTCP2_ERR_CALLBACK_FAILURE; - } - - if (ndatalen >= 0) { - if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, - as_unsigned(ndatalen)); - rv != 0) { - std::println(stderr, "nghttp3_conn_add_write_offset: {}", - nghttp3_strerror(rv)); - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); - return NGTCP2_ERR_CALLBACK_FAILURE; - } - } - - return nwrite; - } + return proto_codec_->write_pkt(path, pi, dest, destlen, ts); } std::expected Handler::write_streams() { @@ -1844,7 +1110,7 @@ void Handler::start_draining_period() { ev_set_cb(&timer_, close_waitcb); timer_.repeat = - static_cast(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3; + static_cast(ngtcp2_conn_get_pto2(conn_)) / NGTCP2_SECONDS * 3; ev_timer_again(loop_, &timer_); if (!config.quiet) { @@ -1854,8 +1120,8 @@ void Handler::start_draining_period() { } std::expected Handler::start_closing_period() { - if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || - ngtcp2_conn_in_draining_period(conn_)) { + if (!conn_ || ngtcp2_conn_in_closing_period2(conn_) || + ngtcp2_conn_in_draining_period2(conn_)) { return {}; } @@ -1863,7 +1129,7 @@ std::expected Handler::start_closing_period() { ev_set_cb(&timer_, close_waitcb); timer_.repeat = - static_cast(ngtcp2_conn_get_pto(conn_)) / NGTCP2_SECONDS * 3; + static_cast(ngtcp2_conn_get_pto2(conn_)) / NGTCP2_SECONDS * 3; ev_timer_again(loop_, &timer_); if (!config.quiet) { @@ -1905,7 +1171,7 @@ std::expected Handler::handle_error() { return rv; } - if (ngtcp2_conn_in_draining_period(conn_)) { + if (ngtcp2_conn_in_draining_period2(conn_)) { return std::unexpected{Error::CLOSE_WAIT}; } @@ -1923,9 +1189,9 @@ std::expected Handler::send_conn_close() { assert(conn_closebuf_ && conn_closebuf_->size()); assert(conn_); - assert(!ngtcp2_conn_in_draining_period(conn_)); + assert(!ngtcp2_conn_in_draining_period2(conn_)); - auto path = ngtcp2_conn_get_path(conn_); + auto path = ngtcp2_conn_get_path2(conn_); return server_->send_packet(*static_cast(path->user_data), path->local, path->remote, @@ -1961,7 +1227,7 @@ Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, } void Handler::update_timer() { - auto expiry = ngtcp2_conn_get_expiry(conn_); + auto expiry = ngtcp2_conn_get_expiry2(conn_); auto now = util::timestamp(); if (expiry <= now) { @@ -1990,28 +1256,7 @@ Handler::recv_stream_data(uint32_t flags, int64_t stream_id, debug::print_stream_data(stream_id, data); } - if (!httpconn_) { - return {}; - } - - auto nconsumed = nghttp3_conn_read_stream2( - httpconn_, stream_id, data.data(), data.size(), - flags & NGTCP2_STREAM_DATA_FLAG_FIN, ngtcp2_conn_get_timestamp(conn_)); - if (nconsumed < 0) { - std::println(stderr, "nghttp3_conn_read_stream2: {}", - nghttp3_strerror(static_cast(nconsumed))); - ngtcp2_ccerr_set_application_error( - &last_error_, - nghttp3_err_infer_quic_app_error_code(static_cast(nconsumed)), - nullptr, 0); - return std::unexpected{Error::HTTP3}; - } - - ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, - static_cast(nconsumed)); - ngtcp2_conn_extend_max_offset(conn_, static_cast(nconsumed)); - - return {}; + return proto_codec_->recv_stream_data(flags, stream_id, data); } std::expected @@ -2020,7 +1265,7 @@ Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, size_t secretlen) { - auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); + auto crypto_ctx = ngtcp2_conn_get_crypto_ctx2(conn_); auto aead = &crypto_ctx->aead; auto keylen = ngtcp2_crypto_aead_keylen(aead); auto ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); @@ -2056,28 +1301,21 @@ std::expected Handler::on_stream_close(int64_t stream_id, std::println(stderr, "QUIC stream {:#x} closed", stream_id); } - if (httpconn_) { - if (app_error_code == 0) { - app_error_code = NGHTTP3_H3_NO_ERROR; - } - auto rv = nghttp3_conn_close_stream(httpconn_, stream_id, app_error_code); - switch (rv) { - case 0: - http_stream_close(stream_id, app_error_code); - break; - case NGHTTP3_ERR_STREAM_NOT_FOUND: - if (ngtcp2_is_bidi_stream(stream_id)) { - assert(!ngtcp2_conn_is_local_stream(conn_, stream_id)); - ngtcp2_conn_extend_max_streams_bidi(conn_, 1); - } - break; - default: - std::println(stderr, "nghttp3_conn_close_stream: {}", - nghttp3_strerror(rv)); - ngtcp2_ccerr_set_application_error( - &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); - return std::unexpected{Error::HTTP3}; + if (auto rv = proto_codec_->on_stream_close(stream_id, app_error_code); !rv) { + return rv; + } + + if (!ngtcp2_conn_is_local_stream2(conn_, stream_id)) { + if (ngtcp2_is_bidi_stream(stream_id)) { + ngtcp2_conn_extend_max_streams_bidi(conn_, 1); } + + // TODO We might later add uni stream extension here. + } + + auto it = streams_.find(stream_id); + if (it != std::ranges::end(streams_)) { + streams_.erase(it); } return {}; @@ -2541,7 +1779,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, switch (hd.token[0]) { case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2: if (auto rv = verify_retry_token(&ocid, &hd, remote_addr); !rv) { - if (rv.error() != Error::UNREADABLE_TOKEN) { + if (rv.error() != Error::UNREADABLE_TOKEN || config.validate_addr) { send_stateless_connection_close(&hd, ep, local_addr, remote_addr); return; @@ -2604,11 +1842,11 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, std::array scids; auto conn = h->conn(); - auto num_scid = ngtcp2_conn_get_scid(conn, nullptr); + auto num_scid = ngtcp2_conn_get_scid2(conn, nullptr); assert(num_scid <= scids.size()); - ngtcp2_conn_get_scid(conn, scids.data()); + ngtcp2_conn_get_scid2(conn, scids.data()); for (size_t i = 0; i < num_scid; ++i) { associate_cid(&scids[i], h.get()); @@ -2621,13 +1859,13 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, auto h = (*handler_it).second; auto conn = h->conn(); - if (ngtcp2_conn_in_closing_period(conn)) { + if (ngtcp2_conn_in_closing_period2(conn)) { if (!h->send_conn_close(ep, local_addr, remote_addr, pi, data)) { remove(h); } return; } - if (ngtcp2_conn_in_draining_period(conn)) { + if (ngtcp2_conn_in_draining_period2(conn)) { return; } @@ -3130,10 +2368,10 @@ void Server::dissociate_cid(const ngtcp2_cid *cid) { handlers_.erase(*cid); } void Server::remove(const Handler *h) { auto conn = h->conn(); - dissociate_cid(ngtcp2_conn_get_client_initial_dcid(conn)); + dissociate_cid(ngtcp2_conn_get_client_initial_dcid2(conn)); - std::vector cids(ngtcp2_conn_get_scid(conn, nullptr)); - ngtcp2_conn_get_scid(conn, cids.data()); + std::vector cids(ngtcp2_conn_get_scid2(conn, nullptr)); + ngtcp2_conn_get_scid2(conn, cids.data()); for (auto &cid : cids) { dissociate_cid(&cid); @@ -3280,7 +2518,7 @@ void print_help() { Path to file that contains MIME media types and the extensions. Default: )" - << config.mime_types_file << R"( + << config.mime_types_file.native() << R"( --early-response Start sending response when it receives HTTP header fields without waiting for request body. If HTTP @@ -3392,11 +2630,10 @@ void print_help() { Discovery. must be strictly larger than 1200. --ech-config-file= Read private key and ECHConfig from . The file - denoted by must contain private key and ECHConfig - as described in - https://datatracker.ietf.org/doc/html/draft-farrell-tls-pemesni. - ECH configuration is only applied if an underlying TLS - stack supports it. + denoted by must contain private key and + ECHConfigList as described in RFC 9934. ECH + configuration is only applied if an underlying TLS stack + supports it. --origin= Specify the origin to send in ORIGIN frame. Repeat to add multiple origins. @@ -3435,11 +2672,11 @@ int main(int argc, char **argv) { prog = basename(argv[0]); } - std::string_view ech_config_file; + std::filesystem::path ech_config_file; for (;;) { static int flag = 0; - constexpr static option long_opts[] = { + static constexpr option long_opts[] = { {"help", no_argument, nullptr, 'h'}, {"tx-loss", required_argument, nullptr, 't'}, {"rx-loss", required_argument, nullptr, 'r'}, @@ -3664,22 +2901,24 @@ int main(int argc, char **argv) { config.max_dyn_length = *n; } break; - case 19: + case 19: { // --cc - if (strcmp("cubic", optarg) == 0) { + auto cc = std::string_view{optarg}; + if (cc == "cubic"sv) { config.cc_algo = NGTCP2_CC_ALGO_CUBIC; break; } - if (strcmp("reno", optarg) == 0) { + if (cc == "reno"sv) { config.cc_algo = NGTCP2_CC_ALGO_RENO; break; } - if (strcmp("bbr", optarg) == 0) { + if (cc == "bbr"sv) { config.cc_algo = NGTCP2_CC_ALGO_BBR; break; } std::println(stderr, "cc: specify cubic, reno, or bbr"); exit(EXIT_FAILURE); + } case 20: // --initial-rtt if (auto t = util::parse_duration(optarg); !t) { @@ -3733,62 +2972,76 @@ int main(int argc, char **argv) { config.handshake_timeout = *t; } break; - case 27: { + case 27: // --preferred-versions - auto l = util::split_str(optarg); - if (l.size() > max_preferred_versionslen) { + if (strlen(optarg) == 0) { + config.preferred_versions.resize(0); + + break; + } + + config.preferred_versions = + util::split_str(optarg) | std::ranges::views::transform([](auto &&k) { + if (k == "v1"sv) { + return NGTCP2_PROTO_VER_V1; + } + + if (k == "v2"sv) { + return NGTCP2_PROTO_VER_V2; + } + + auto rv = util::parse_version(k); + if (!rv) { + std::println(stderr, "preferred-versions: invalid version {}", k); + exit(EXIT_FAILURE); + } + + if (!ngtcp2_is_supported_version(*rv)) { + std::println(stderr, "preferred-versions: unsupported version {}", + k); + exit(EXIT_FAILURE); + } + + return *rv; + }) | + std::ranges::to(); + + if (config.preferred_versions.size() > max_preferred_versionslen) { std::println(stderr, "preferred-versions: too many versions > {}", max_preferred_versionslen); exit(EXIT_FAILURE); } - config.preferred_versions.resize(l.size()); - auto it = std::ranges::begin(config.preferred_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "preferred-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - if (!ngtcp2_is_supported_version(*rv)) { - std::println(stderr, "preferred-versions: unsupported version {}", - k); - exit(EXIT_FAILURE); - } - *it++ = *rv; - } + break; - } - case 28: { + case 28: // --available-versions - auto l = util::split_str(optarg); - config.available_versions.resize(l.size()); - auto it = std::ranges::begin(config.available_versions); - for (const auto &k : l) { - if (k == "v1"sv) { - *it++ = NGTCP2_PROTO_VER_V1; - continue; - } - if (k == "v2"sv) { - *it++ = NGTCP2_PROTO_VER_V2; - continue; - } - auto rv = util::parse_version(k); - if (!rv) { - std::println(stderr, "available-versions: invalid version {}", k); - exit(EXIT_FAILURE); - } - *it++ = *rv; + if (strlen(optarg) == 0) { + config.available_versions.resize(0); + + break; } + + config.available_versions = + util::split_str(optarg) | std::ranges::views::transform([](auto &&k) { + if (k == "v1"sv) { + return NGTCP2_PROTO_VER_V1; + } + + if (k == "v2"sv) { + return NGTCP2_PROTO_VER_V2; + } + + auto rv = util::parse_version(k); + if (!rv) { + std::println(stderr, "available-versions: invalid version {}", k); + exit(EXIT_FAILURE); + } + + return *rv; + }) | + std::ranges::to(); + break; - } case 29: // --no-pmtud config.no_pmtud = true; @@ -3818,25 +3071,36 @@ int main(int argc, char **argv) { config.initial_pkt_num = static_cast(*n); } break; - case 32: { + case 32: // --pmtud-probes - auto l = util::split_str(optarg); - for (auto &s : l) { - if (auto n = util::parse_uint_iec(s); !n) { - std::println(stderr, "pmtud-probes: invalid argument"); - exit(EXIT_FAILURE); - } else if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE || - *n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { - std::println( - stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", - NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); - exit(EXIT_FAILURE); - } else { - config.pmtud_probes.push_back(static_cast(*n)); - } + if (strlen(optarg) == 0) { + config.pmtud_probes.resize(0); + + break; } + + config.pmtud_probes = + util::split_str(optarg) | std::ranges::views::transform([](auto &&s) { + auto n = util::parse_uint_iec(s); + if (!n) { + std::println(stderr, "pmtud-probes: invalid argument"); + exit(EXIT_FAILURE); + } + + if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE || + *n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) { + std::println( + stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", + NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, + NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); + exit(EXIT_FAILURE); + } + + return static_cast(*n); + }) | + std::ranges::to(); + break; - } case 33: // --ech-config-file ech_config_file = optarg; @@ -3918,7 +3182,7 @@ int main(int argc, char **argv) { if (auto mt = util::read_mime_types(config.mime_types_file); !mt) { std::println(stderr, "mime-types-file: Could not read MIME media types file {}", - config.mime_types_file); + config.mime_types_file.native()); } else { config.mime_types = std::move(*mt); } @@ -3936,15 +3200,11 @@ int main(int argc, char **argv) { TLSServerContext tls_ctx; - if (!tls_ctx.init(private_key_file, cert_file, AppProtocol::H3)) { + if (!tls_ctx.init(private_key_file, cert_file, ProtoCodec::protocol)) { exit(EXIT_FAILURE); } - if (config.htdocs.back() != '/') { - config.htdocs += '/'; - } - - std::println(stderr, "Using document root {}", config.htdocs); + std::println(stderr, "Using document root {}", config.htdocs.native()); auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); }); diff --git a/deps/ngtcp2/ngtcp2/examples/server.h b/deps/ngtcp2/ngtcp2/examples/server.h index 3f0cdee8574038..ea3162a47846f0 100644 --- a/deps/ngtcp2/ngtcp2/examples/server.h +++ b/deps/ngtcp2/ngtcp2/examples/server.h @@ -39,7 +39,6 @@ #include #include -#include #include @@ -49,25 +48,56 @@ #include "shared.h" #include "util.h" +#ifdef WITH_EXAMPLE_HTTP3_PROTO_CODEC +# include "http3_server_proto_codec.h" +#endif // WITH_EXAMPLE_HTTP3_PROTO_CODEC + +#ifdef WITH_EXAMPLE_HQ_PROTO_CODEC +# include + +# include "hq_server_proto_codec.h" +#endif // WITH_EXAMPLE_HQ_PROTO_CODEC + using namespace ngtcp2; class Handler; -struct FileEntry; + +enum FileEntryFlag { + FILE_ENTRY_TYPE_DIR = 0x1, +}; + +struct FileEntry { + uint64_t len{}; + void *map{}; + int fd{}; + uint8_t flags{}; +}; + +std::string make_status_body(unsigned int status_code); + +struct Request { + std::string path; + struct { + int32_t urgency; + int inc; + } pri{}; +}; struct Stream { Stream(int64_t stream_id, Handler *handler); - std::expected start_response(nghttp3_conn *conn); - std::expected open_file(const std::string &path); + std::expected start_response(); + std::expected open_file(const std::filesystem::path &path); void map_file(const FileEntry &fe); std::expected - send_status_response(nghttp3_conn *conn, unsigned int status_code, + send_status_response(ProtoCodec *pc, unsigned int status_code, const std::vector &extra_headers = {}); - std::expected send_redirect_response(nghttp3_conn *conn, + std::expected send_redirect_response(ProtoCodec *pc, unsigned int status_code, std::string_view path); std::expected find_dyn_length(std::string_view path); void http_acked_stream_data(uint64_t datalen); + std::expected request_path(); int64_t stream_id; Handler *handler; @@ -76,16 +106,20 @@ struct Stream { std::string method; std::string authority; std::string status_resp_body; - // data is a pointer to the memory which maps file denoted by fd. - uint8_t *data{}; - // datalen is the length of mapped file by data. - uint64_t datalen{}; + // resp_data is a pointer to the response data. It might be the + // memory which maps file denoted by fd, or status_resp_body. + std::span resp_data; // dynresp is true if dynamic data response is enabled. bool dynresp{}; // dyndataleft is the number of dynamic data left to send. uint64_t dyndataleft{}; // dynbuflen is the number of bytes in-flight. uint64_t dynbuflen{}; +#ifdef WITH_EXAMPLE_HQ_PROTO_CODEC + http_parser htp; + // eos gets true when one HTTP request message is seen. + bool eos{}; +#endif // WITH_EXAMPLE_HQ_PROTO_CODEC }; class Server; @@ -153,27 +187,13 @@ class Handler : public HandlerBase { const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, size_t secretlen); - std::expected setup_httpconn(); - void http_consume(int64_t stream_id, size_t nconsumed); void extend_max_remote_streams_bidi(uint64_t max_streams); - Stream *find_stream(int64_t stream_id); - void http_begin_request_headers(int64_t stream_id); - void http_recv_request_header(Stream *stream, int32_t token, - nghttp3_rcbuf *name, nghttp3_rcbuf *value); - std::expected http_end_request_headers(Stream *stream); - std::expected http_end_stream(Stream *stream); - std::expected start_response(Stream *stream); + Stream *find_stream(int64_t stream_id) const; std::expected on_stream_reset(int64_t stream_id); std::expected on_stream_stop_sending(int64_t stream_id); std::expected extend_max_stream_data(int64_t stream_id, uint64_t max_data); void shutdown_read(int64_t stream_id, uint64_t app_error_code); - void http_acked_stream_data(Stream *stream, uint64_t datalen); - void http_stream_close(int64_t stream_id, uint64_t app_error_code); - std::expected http_stop_sending(int64_t stream_id, - uint64_t app_error_code); - std::expected http_reset_stream(int64_t stream_id, - uint64_t app_error_code); void write_qlog(const void *data, size_t datalen); @@ -189,6 +209,10 @@ class Handler : public HandlerBase { ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts); + std::expected on_app_tx_ready(); + + std::expected start_response(Stream *stream); + private: struct ev_loop *loop_; Server *server_; @@ -196,7 +220,7 @@ class Handler : public HandlerBase { ev_timer timer_; FILE *qlog_{}; ngtcp2_cid scid_{}; - nghttp3_conn *httpconn_{}; + std::unique_ptr proto_codec_; std::unordered_map> streams_; // conn_closebuf_ contains a packet which contains CONNECTION_CLOSE. // This packet is repeatedly sent as a response to the incoming diff --git a/deps/ngtcp2/ngtcp2/examples/server_base.cc b/deps/ngtcp2/ngtcp2/examples/server_base.cc index 6f0b3be869af50..0e439299cfe56c 100644 --- a/deps/ngtcp2/ngtcp2/examples/server_base.cc +++ b/deps/ngtcp2/ngtcp2/examples/server_base.cc @@ -26,7 +26,6 @@ #include #include -#include #include "debug.h" diff --git a/deps/ngtcp2/ngtcp2/examples/server_base.h b/deps/ngtcp2/ngtcp2/examples/server_base.h index a600c433ab32e3..9438d11f8bd82f 100644 --- a/deps/ngtcp2/ngtcp2/examples/server_base.h +++ b/deps/ngtcp2/ngtcp2/examples/server_base.h @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -59,11 +60,11 @@ struct Config { // groups is the list of supported groups. const char *groups{util::crypto_default_groups()}; // htdocs is a root directory to serve documents. - std::string htdocs{util::realpath(".")}; + std::filesystem::path htdocs{util::realpath(".")}; // mime_types_file is a path to "MIME media types and the // extensions" file. Ubuntu mime-support package includes it in // /etc/mime/types. - std::string_view mime_types_file{"/etc/mime.types"sv}; + std::filesystem::path mime_types_file{"/etc/mime.types"sv}; // mime_types maps file extension to MIME media type. std::unordered_map mime_types; // port is the port number which server listens on for incoming @@ -87,7 +88,7 @@ struct Config { // certificate based authentication. bool verify_client{}; // qlog_dir is the path to directory where qlog is stored. - std::string_view qlog_dir; + std::filesystem::path qlog_dir; // no_quic_dump is true if hexdump of QUIC STREAM and CRYPTO data // should be disabled. bool no_quic_dump{}; @@ -178,7 +179,7 @@ struct HTTPHeader { std::string_view value; }; -inline constexpr size_t NGTCP2_STATELESS_RESET_BURST = 100; +inline constexpr auto NGTCP2_STATELESS_RESET_BURST = 100UZ; struct Buffer { Buffer(const uint8_t *data, size_t datalen); @@ -201,6 +202,8 @@ struct Buffer { uint8_t *tail; }; +inline constexpr auto NGTCP2_SERVER = "ngtcp2 server"sv; + class HandlerBase { public: HandlerBase(); diff --git a/deps/ngtcp2/ngtcp2/examples/shared.cc b/deps/ngtcp2/ngtcp2/examples/shared.cc index f9714c69ec14f1..ef78394f04af72 100644 --- a/deps/ngtcp2/ngtcp2/examples/shared.cc +++ b/deps/ngtcp2/ngtcp2/examples/shared.cc @@ -28,7 +28,6 @@ #include #include -#include #include #ifdef HAVE_NETINET_IN_H diff --git a/deps/ngtcp2/ngtcp2/examples/shared.h b/deps/ngtcp2/ngtcp2/examples/shared.h index 5c4a97646a06be..b9e0e1f0b01261 100644 --- a/deps/ngtcp2/ngtcp2/examples/shared.h +++ b/deps/ngtcp2/ngtcp2/examples/shared.h @@ -101,7 +101,7 @@ inline constexpr auto H3_ALPN_V1 = span_from_lit(RAW_H3_ALPN); inline constexpr uint32_t TLS_ALERT_ECH_REQUIRED = 121; -inline constexpr size_t MAX_RECV_PKTS = 64; +inline constexpr auto MAX_RECV_PKTS = 64UZ; // msghdr_get_ecn gets ECN bits from |msg|. |family| is the address // family from which packet is received. @@ -187,7 +187,8 @@ void sockaddr_set(Sockaddr &skaddr, const sockaddr *sa); template <> struct std::formatter : public std::formatter { - auto format(ngtcp2::Error e, format_context &ctx) const { + template + auto format(ngtcp2::Error e, FormatContext &ctx) const { auto s = "unknown"sv; switch (e) { diff --git a/deps/ngtcp2/ngtcp2/examples/sim.cc b/deps/ngtcp2/ngtcp2/examples/sim.cc index 326c3701caf18c..2f371092bdcd27 100644 --- a/deps/ngtcp2/ngtcp2/examples/sim.cc +++ b/deps/ngtcp2/ngtcp2/examples/sim.cc @@ -31,7 +31,6 @@ #include #include #include -#include #include "ngtcp2/ngtcp2_crypto_wolfssl.h" @@ -42,11 +41,12 @@ using namespace std::literals; namespace ngtcp2 { -namespace { constexpr auto ALPN_LIST = "ngtcp2-sim"sv; -constexpr size_t CIDLEN = 10; +constexpr auto CIDLEN = 10UZ; constexpr uint8_t SERVER_SECRET[] = "server_secret"; +constexpr std::array static_secret{0xCA, 0xCE, 0xCA, 0xFE}; +namespace { std::expected generate_secure_random(std::span data) { if (wolfSSL_RAND_bytes(data.data(), static_cast(data.size())) != 1) { return std::unexpected{Error::CRYPTO}; @@ -79,14 +79,6 @@ int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, } } // namespace -ngtcp2_tstamp to_ngtcp2_tstamp(const Timestamp &ts) { - return static_cast(ts.time_since_epoch().count()); -} - -Timestamp to_timestamp(ngtcp2_tstamp ts) { - return Timestamp{Timestamp::duration{ts}}; -} - uint64_t LinkConfig::compute_expected_goodput(Timestamp::duration rtt) const { // Assume 80% usage ratio. uint64_t g = rate * 8 / 10; @@ -155,7 +147,7 @@ ngtcp2_settings default_client_settings() { ngtcp2_settings settings; ngtcp2_settings_default(&settings); - settings.log_printf = debug::log_printf; + settings.log_write = debug::log_write; return settings; } @@ -164,7 +156,7 @@ ngtcp2_settings default_server_settings() { ngtcp2_settings settings; ngtcp2_settings_default(&settings); - settings.log_printf = debug::log_printf; + settings.log_write = debug::log_write; return settings; } @@ -261,31 +253,34 @@ Endpoint::Endpoint(Endpoint &&other) noexcept conn_{std::exchange(other.conn_, nullptr)}, conn_ref_{ngtcp2::get_conn, this}, channel_{std::exchange(other.channel_, {})}, - initialized_{std::exchange(other.initialized_, false)} {} - -Endpoint::~Endpoint() { - ngtcp2_conn_del(conn_); - + initialized_{std::exchange(other.initialized_, false)} { if (ssl_) { - wolfSSL_free(ssl_); - } - - if (ssl_ctx_) { - wolfSSL_CTX_free(ssl_ctx_); + wolfSSL_set_app_data(ssl_, &conn_ref_); } } -Endpoint &Endpoint::operator=(Endpoint &&other) noexcept { +Endpoint::~Endpoint() { reset(); } + +void Endpoint::reset() { ngtcp2_conn_del(conn_); + conn_ = nullptr; if (ssl_) { wolfSSL_free(ssl_); + ssl_ = nullptr; } if (ssl_ctx_) { wolfSSL_CTX_free(ssl_ctx_); + ssl_ctx_ = nullptr; } + initialized_ = false; +} + +Endpoint &Endpoint::operator=(Endpoint &&other) noexcept { + reset(); + config_ = std::exchange(other.config_, {}); ssl_ctx_ = std::exchange(other.ssl_ctx_, nullptr); ssl_ = std::exchange(other.ssl_, nullptr); @@ -301,7 +296,6 @@ Endpoint &Endpoint::operator=(Endpoint &&other) noexcept { return *this; } -namespace { constexpr auto tls_key = R"(-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwEvkGGgXAcRaG7Z8 gA7C6+W2RsW9gcjV9e5ybr0ikaahRANCAASCo35bDi+Q/q/CzHI1e5QaBrbqbFhW @@ -323,12 +317,12 @@ MAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAO4tnDNRAcooz62vf2m7vTyDqFCjcaIv SJ9Gq0lvEXEcAiBwWBNUASBqLaje3hmtgwxcF7EIqqiGo5j8f9Ufgu6SRg== -----END CERTIFICATE----- )"sv; -} // namespace std::expected Endpoint::setup_server(std::span original_dcid, std::span client_scid, uint32_t version, - const ngtcp2_addr *remote_addr) { + const ngtcp2_addr *remote_addr, + std::optional token_params) { ngtcp2_cid scid{ .datalen = CIDLEN, }; @@ -341,8 +335,21 @@ Endpoint::setup_server(std::span original_dcid, ngtcp2_cid_init(&dcid, client_scid.data(), client_scid.size()); auto params = config_.params; - ngtcp2_cid_init(¶ms.original_dcid, original_dcid.data(), - original_dcid.size()); + auto settings = config_.settings; + + if (token_params) { + params.original_dcid = *token_params->original_dcid; + params.retry_scid = *token_params->retry_scid; + params.retry_scid_present = 1; + + settings.token = token_params->token.data(); + settings.tokenlen = token_params->token.size(); + settings.token_type = NGTCP2_TOKEN_TYPE_RETRY; + } else { + ngtcp2_cid_init(¶ms.original_dcid, original_dcid.data(), + original_dcid.size()); + } + params.original_dcid_present = 1; if (ngtcp2_crypto_generate_stateless_reset_token( @@ -357,8 +364,8 @@ Endpoint::setup_server(std::span original_dcid, }; if (ngtcp2_conn_server_new(&conn_, &dcid, &scid, &path, version, - &config_.callbacks, &config_.settings, ¶ms, - nullptr, config_.user_data) != 0) { + &config_.callbacks, &settings, ¶ms, nullptr, + config_.user_data) != 0) { return std::unexpected{Error::QUIC}; } @@ -473,7 +480,23 @@ std::expected Endpoint::on_read(const NetworkPath &path, auto rv = ngtcp2_conn_read_pkt(conn_, &cpath, nullptr, pkt.data(), pkt.size(), ts); if (rv != 0) { - std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl; + if (rv == NGTCP2_ERR_RETRY) { + assert(ngtcp2_conn_is_server(conn_)); + + reset(); + + ngtcp2_version_cid vcid; + + auto rv = + ngtcp2_pkt_decode_version_cid(&vcid, pkt.data(), pkt.size(), CIDLEN); + if (rv != 0) { + return std::unexpected{Error::QUIC}; + } + + return send_retry(path, vcid); + } + + std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); return std::unexpected{Error::QUIC}; } @@ -482,16 +505,66 @@ std::expected Endpoint::on_read(const NetworkPath &path, return {}; } +std::expected +Endpoint::send_retry(const NetworkPath &path, const ngtcp2_version_cid &vcid) { + ngtcp2_cid dcid, odcid; + + assert(vcid.scidlen <= NGTCP2_MAX_CIDLEN); + assert(vcid.dcidlen <= NGTCP2_MAX_CIDLEN); + + ngtcp2_cid_init(&dcid, vcid.scid, vcid.scidlen); + ngtcp2_cid_init(&odcid, vcid.dcid, vcid.dcidlen); + + ngtcp2_cid scid; + + scid.datalen = CIDLEN; + + if (auto rv = generate_secure_random({scid.data, scid.datalen}); !rv) { + return rv; + } + + std::array token; + + auto cpath = to_ngtcp2_path(path); + + auto tokenlen = ngtcp2_crypto_generate_retry_token2( + token.data(), static_secret.data(), static_secret.size(), vcid.version, + cpath.remote.addr, cpath.remote.addrlen, &scid, &odcid, + to_ngtcp2_tstamp(channel_.get_timestamp())); + if (tokenlen < 0) { + return std::unexpected{Error::QUIC}; + } + + std::array buf; + + auto nwrite = ngtcp2_crypto_write_retry(buf.data(), buf.size(), vcid.version, + &dcid, &scid, &odcid, token.data(), + as_unsigned(tokenlen)); + if (nwrite < 0) { + return std::unexpected{Error::QUIC}; + } + + if (nwrite) { + channel_.send_pkt(path, {buf.data(), as_unsigned(nwrite)}); + } + + return {}; +} + std::expected Endpoint::on_write(const Context &ctx) { if (auto rv = config_.on_write(conn_, ctx); !rv) { return rv; } - auto next_expiry_ts = ngtcp2_conn_get_expiry(conn_); + auto next_expiry_ts = ngtcp2_conn_get_expiry2(conn_); if (next_expiry_ts == UINT64_MAX) { return {}; } + if (to_ngtcp2_tstamp(Timestamp::max()) < next_expiry_ts) { + return std::unexpected{Error::INTERNAL}; + } + ctx.endpoint->get_channel().schedule_timeout(to_timestamp(next_expiry_ts)); return {}; @@ -500,8 +573,7 @@ std::expected Endpoint::on_write(const Context &ctx) { std::expected Endpoint::on_timeout(const Context &ctx) { auto rv = ngtcp2_conn_handle_expiry(conn_, to_ngtcp2_tstamp(ctx.ts)); if (rv != 0) { - std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_handle_expiry: {}", ngtcp2_strerror(rv)); return std::unexpected{Error::QUIC}; } @@ -524,7 +596,7 @@ ngtcp2_path to_ngtcp2_path(const NetworkPath &path) { }; } -NetworkPath NetworkPath::invert() { +NetworkPath NetworkPath::invert() const { auto path = *this; std::swap(path.local, path.remote); @@ -558,7 +630,7 @@ Channel &Channel::operator=(Channel &&other) noexcept { return *this; } -void Channel::send_pkt(const NetworkPath &path, std::span pkt) { +void Channel::send_pkt(const NetworkPath &path, std::span pkt) { auto rate = link_config_.rate / 8; if (rate == 0) { @@ -794,9 +866,33 @@ std::expected Simulator::deliver_pkt(Endpoint &remote_ep, return {}; } + ngtcp2_cid odcid; + std::optional token_params; + + if (hd.tokenlen) { + auto cpath = to_ngtcp2_path(path); + auto delay = local_ep.get_endpoint_config().link.delay; + auto timeout = delay * 2 * 2; + + auto rv = ngtcp2_crypto_verify_retry_token2( + &odcid, hd.token, hd.tokenlen, static_secret.data(), + static_secret.size(), vcid.version, cpath.remote.addr, + cpath.remote.addrlen, &hd.dcid, to_ngtcp2_duration(timeout), + to_ngtcp2_tstamp(ts)); + if (rv != 0) { + return std::unexpected{Error::QUIC}; + } + + token_params = TokenParams{ + .original_dcid = &odcid, + .retry_scid = &hd.dcid, + .token = {hd.token, hd.tokenlen}, + }; + } + if (auto rv = local_ep.setup_server( {vcid.dcid, vcid.dcidlen}, {vcid.scid, vcid.scidlen}, vcid.version, - &remote_ep.get_endpoint_config().local_addr); + &remote_ep.get_endpoint_config().local_addr, token_params); !rv) { return rv; } @@ -838,8 +934,8 @@ void HandshakeApp::configure(EndpointConfig &config) { auto nwrite = ngtcp2_conn_write_pkt(conn, &ps.path, nullptr, buf.data(), buf.size(), ts); if (nwrite < 0) { - std::cerr << "ngtcp2_conn_write_pkt: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_conn_write_pkt: {}", + ngtcp2_strerror(static_cast(nwrite))); return std::unexpected{Error::QUIC}; } @@ -924,8 +1020,8 @@ UniStreamApp::extend_max_local_streams_uni(ngtcp2_conn *conn) { auto rv = ngtcp2_conn_open_uni_stream(conn, &stream_id, nullptr); if (rv != 0) { - std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); return std::unexpected{Error::QUIC}; } @@ -974,8 +1070,8 @@ std::expected UniStreamApp::on_write(ngtcp2_conn *conn, return {}; } - std::cerr << "ngtcp2_conn_writev_stream: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); return std::unexpected{Error::QUIC}; } diff --git a/deps/ngtcp2/ngtcp2/examples/sim.h b/deps/ngtcp2/ngtcp2/examples/sim.h index c8fa7c203045d3..98e72791b6f1b5 100644 --- a/deps/ngtcp2/ngtcp2/examples/sim.h +++ b/deps/ngtcp2/ngtcp2/examples/sim.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -45,14 +46,23 @@ #include "shared.h" namespace ngtcp2 { -inline constexpr size_t MAX_UDP_PAYLOAD_SIZE = 1500; +inline constexpr auto MAX_UDP_PAYLOAD_SIZE = 1500UZ; using Timestamp = std::chrono::time_point; -ngtcp2_tstamp to_ngtcp2_tstamp(const Timestamp &ts); +[[nodiscard]] constexpr ngtcp2_tstamp to_ngtcp2_tstamp(Timestamp ts) { + return static_cast(ts.time_since_epoch().count()); +} + +[[nodiscard]] constexpr ngtcp2_duration +to_ngtcp2_duration(Timestamp::duration d) { + return static_cast(d.count()); +} -Timestamp to_timestamp(ngtcp2_tstamp ts); +[[nodiscard]] constexpr Timestamp to_timestamp(ngtcp2_tstamp ts) { + return Timestamp{Timestamp::duration{ts}}; +} class Simulator; class Endpoint; @@ -63,15 +73,18 @@ struct Context { Endpoint *endpoint; }; -constexpr unsigned long long operator""_kbps(unsigned long long k) { +[[nodiscard]] constexpr unsigned long long +operator""_kbps(unsigned long long k) noexcept { return k * 1'000; } -constexpr unsigned long long operator""_mbps(unsigned long long m) { +[[nodiscard]] constexpr unsigned long long +operator""_mbps(unsigned long long m) noexcept { return m * 1'000'000; } -constexpr unsigned long long operator""_gbps(unsigned long long g) { +[[nodiscard]] constexpr unsigned long long +operator""_gbps(unsigned long long g) noexcept { return g * 1'000'000'000; } @@ -132,7 +145,7 @@ EndpointConfig default_client_endpoint_config(); EndpointConfig default_server_endpoint_config(); struct NetworkPath { - NetworkPath invert(); + NetworkPath invert() const; Address local{}; Address remote{}; @@ -174,9 +187,10 @@ class Channel { Channel &operator=(const Channel &) = delete; Channel &operator=(Channel &&) noexcept; - void send_pkt(const NetworkPath &path, std::span pkt); + void send_pkt(const NetworkPath &path, std::span pkt); void schedule_timeout(Timestamp ts); void set_timestamp(Timestamp ts) { ts_ = ts; } + Timestamp get_timestamp() const { return ts_; } Timestamp get_next_timestamp() const; Event get_next_event(); void pop_tx_queue(); @@ -197,6 +211,12 @@ class Channel { Timestamp ts_{}; }; +struct TokenParams { + const ngtcp2_cid *original_dcid; + const ngtcp2_cid *retry_scid; + std::span token; +}; + class Endpoint { public: Endpoint(); @@ -212,7 +232,8 @@ class Endpoint { std::expected setup_server(std::span original_dcid, std::span client_scid, uint32_t version, - const ngtcp2_addr *remote_addr); + const ngtcp2_addr *remote_addr, + std::optional token_params); ngtcp2_conn *get_conn() const { return conn_; } bool get_initialized() const { return initialized_; } const EndpointConfig &get_endpoint_config() const { return config_; } @@ -224,6 +245,10 @@ class Endpoint { Channel &get_channel() { return channel_; } private: + void reset(); + std::expected send_retry(const NetworkPath &path, + const ngtcp2_version_cid &vcid); + EndpointConfig config_; WOLFSSL_CTX *ssl_ctx_{}; WOLFSSL *ssl_{}; @@ -297,4 +322,4 @@ class UniStreamApp { } // namespace ngtcp2 -#endif // SIM_H +#endif // !defined(SIM_H) diff --git a/deps/ngtcp2/ngtcp2/examples/sim_test.cc b/deps/ngtcp2/ngtcp2/examples/sim_test.cc index 6755907ec5605e..b7e6d69e36d67f 100644 --- a/deps/ngtcp2/ngtcp2/examples/sim_test.cc +++ b/deps/ngtcp2/ngtcp2/examples/sim_test.cc @@ -24,8 +24,6 @@ */ #include "sim_test.h" -#include - #include "sim.h" #include "util.h" diff --git a/deps/ngtcp2/ngtcp2/examples/simpleclient.c b/deps/ngtcp2/ngtcp2/examples/simpleclient.c index fb0b8862979c94..65ab3560552b02 100644 --- a/deps/ngtcp2/ngtcp2/examples/simpleclient.c +++ b/deps/ngtcp2/ngtcp2/examples/simpleclient.c @@ -383,7 +383,7 @@ static int client_read(struct client *c) { if (!c->last_error.error_code) { if (rv == NGTCP2_ERR_CRYPTO) { ngtcp2_ccerr_set_tls_alert( - &c->last_error, ngtcp2_conn_get_tls_alert(c->conn), NULL, 0); + &c->last_error, ngtcp2_conn_get_tls_alert2(c->conn), NULL, 0); } else { ngtcp2_ccerr_set_liberr(&c->last_error, rv, NULL, 0); } @@ -506,7 +506,7 @@ static int client_write(struct client *c) { return -1; } - expiry = ngtcp2_conn_get_expiry(c->conn); + expiry = ngtcp2_conn_get_expiry2(c->conn); now = timestamp(); t = expiry < now ? 1e-9 : (ev_tstamp)(expiry - now) / NGTCP2_SECONDS; @@ -533,8 +533,8 @@ static void client_close(struct client *c) { ngtcp2_path_storage ps; uint8_t buf[1280]; - if (ngtcp2_conn_in_closing_period(c->conn) || - ngtcp2_conn_in_draining_period(c->conn)) { + if (ngtcp2_conn_in_closing_period2(c->conn) || + ngtcp2_conn_in_draining_period2(c->conn)) { goto fin; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc index 40205ace4e72a2..b6f28a5d3c1bd0 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc @@ -25,7 +25,6 @@ #include "tls_client_context_boringssl.h" #include -#include #include #include @@ -53,10 +52,10 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { c->ticket_received(); - auto f = BIO_new_file(config.session_file, "w"); + auto f = BIO_new_file(config.session_file.c_str(), "w"); if (f == nullptr) { std::println(stderr, "Could not write TLS session in {}", - config.session_file); + config.session_file.native()); return 0; } @@ -107,7 +106,7 @@ std::expected TLSClientContext::init(const char *private_key_file, } } - if (config.session_file) { + if (!config.session_file.empty()) { SSL_CTX_set_session_cache_mode(ssl_ctx_, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb); diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc index 5eab5bc8fe47ec..d7f9f8f58c8abc 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -69,10 +68,10 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { std::numeric_limits::max()) { std::println(stderr, "max_early_data_size is not 0xffffffff"); } - auto f = BIO_new_file(config.session_file, "w"); + auto f = BIO_new_file(config.session_file.c_str(), "w"); if (f == nullptr) { std::println(stderr, "Could not write TLS session in {}", - config.session_file); + config.session_file.native()); return 0; } @@ -123,7 +122,7 @@ std::expected TLSClientContext::init(const char *private_key_file, } } - if (config.session_file) { + if (!config.session_file.empty()) { SSL_CTX_set_session_cache_mode(ssl_ctx_, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb); diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc index f70df693ef44cd..d5ee705be0a778 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc @@ -24,8 +24,6 @@ */ #include "tls_client_context_picotls.h" -#include - #include #include @@ -45,10 +43,10 @@ int save_ticket_cb(ptls_save_ticket_t *self, ptls_t *ptls, ptls_iovec_t input) { c->ticket_received(); - auto f = BIO_new_file(config.session_file, "w"); + auto f = BIO_new_file(config.session_file.c_str(), "w"); if (f == nullptr) { std::println(stderr, "Could not write TLS session in {}", - config.session_file); + config.session_file.native()); return 0; } @@ -121,7 +119,7 @@ std::expected TLSClientContext::init(const char *private_key_file, return std::unexpected{Error::CRYPTO}; } - if (config.session_file) { + if (!config.session_file.empty()) { ctx_.save_ticket = &save_ticket; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc index ce4ac8dbf7d29b..b88717708f3aaf 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -69,10 +68,10 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { std::numeric_limits::max()) { std::println(stderr, "max_early_data_size is not 0xffffffff"); } - auto f = BIO_new_file(config.session_file, "w"); + auto f = BIO_new_file(config.session_file.c_str(), "w"); if (f == nullptr) { std::println(stderr, "Could not write TLS session in {}", - config.session_file); + config.session_file.native()); return 0; } @@ -129,7 +128,7 @@ std::expected TLSClientContext::init(const char *private_key_file, } } - if (config.session_file) { + if (!config.session_file.empty()) { SSL_CTX_set_session_cache_mode(ssl_ctx_, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL); SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb); diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc index cca571a7c1da36..8eef8a259deef5 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc @@ -25,7 +25,6 @@ #include "tls_client_context_wolfssl.h" #include -#include #include #include @@ -65,7 +64,7 @@ int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) { auto sz = wolfSSL_i2d_SSL_SESSION(session, nullptr); if (sz <= 0) { std::println(stderr, "Could not export TLS session in {}", - config.session_file); + config.session_file.native()); return 0; } if (static_cast(sz) > sizeof(sbuffer)) { @@ -75,10 +74,10 @@ int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) { data = sbuffer; sz = wolfSSL_i2d_SSL_SESSION(session, &data); - auto f = wolfSSL_BIO_new_file(config.session_file, "w"); + auto f = wolfSSL_BIO_new_file(config.session_file.c_str(), "w"); if (f == nullptr) { std::println(stderr, "Could not write TLS session in {}", - config.session_file); + config.session_file.native()); return 0; } @@ -147,7 +146,7 @@ std::expected TLSClientContext::init(const char *private_key_file, } } - if (config.session_file) { + if (!config.session_file.empty()) { wolfSSL_CTX_UseSessionTicket(ssl_ctx_); wolfSSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb); } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc index 109265641a52c5..75989b66bbf594 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc @@ -25,7 +25,6 @@ #include "tls_client_session_boringssl.h" #include -#include #include #include "tls_client_context_boringssl.h" @@ -73,17 +72,17 @@ TLSClientSession::init(bool &early_data_enabled, SSL_set_tlsext_host_name(ssl_, remote_addr); } - if (config.session_file) { - auto f = BIO_new_file(config.session_file, "r"); + if (!config.session_file.empty()) { + auto f = BIO_new_file(config.session_file.c_str(), "r"); if (f == nullptr) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr); BIO_free(f); if (session == nullptr) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { if (!SSL_set_session(ssl_, session)) { std::println(stderr, "Could not set session"); @@ -116,8 +115,8 @@ bool TLSClientSession::get_ech_accepted() const { return SSL_ech_accepted(ssl_); } -std::expected -TLSClientSession::write_ech_config_list(const char *path) const { +std::expected TLSClientSession::write_ech_config_list( + const std::filesystem::path &path) const { const uint8_t *retry_configs; size_t retry_configslen; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h index fad6372cc801c1..89000c9ff2ee89 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h @@ -29,6 +29,8 @@ # include #endif // defined(HAVE_CONFIG_H) +#include + #include "tls_session_base_quictls.h" #include "shared.h" @@ -48,7 +50,8 @@ class TLSClientSession : public TLSSessionBase { bool get_early_data_accepted() const; bool get_ech_accepted() const; - std::expected write_ech_config_list(const char *path) const; + std::expected + write_ech_config_list(const std::filesystem::path &path) const; }; #endif // !defined(TLS_CLIENT_SESSION_BORINGSSL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc index c5edb78881ce91..b15a45fc2a8ee5 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc @@ -25,7 +25,6 @@ #include "tls_client_session_ossl.h" #include -#include #include @@ -81,17 +80,17 @@ TLSClientSession::init(bool &early_data_enabled, SSL_set_tlsext_host_name(ssl, remote_addr); } - if (config.session_file) { - auto f = BIO_new_file(config.session_file, "r"); + if (!config.session_file.empty()) { + auto f = BIO_new_file(config.session_file.c_str(), "r"); if (f == nullptr) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr); BIO_free(f); if (session == nullptr) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { if (!SSL_set_session(ssl, session)) { std::println(stderr, "Could not set session"); diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h index 9b08292f9679f3..4476ba4c7beda1 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h @@ -29,6 +29,8 @@ # include #endif // defined(HAVE_CONFIG_H) +#include + #include "tls_session_base_ossl.h" #include "shared.h" @@ -48,7 +50,8 @@ class TLSClientSession : public TLSSessionBase { bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - std::expected write_ech_config_list(const char *path) const { + std::expected + write_ech_config_list(const std::filesystem::path &path) const { return {}; } }; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc index 31b26653899f6e..d65d2a096f3a09 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc @@ -25,7 +25,6 @@ #include "tls_client_session_picotls.h" #include -#include #include #include @@ -119,11 +118,11 @@ TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, ptls_set_server_name(cptls_.ptls, remote_addr, strlen(remote_addr)); } - if (config.session_file) { - auto f = BIO_new_file(config.session_file, "r"); + if (!config.session_file.empty()) { + auto f = BIO_new_file(config.session_file.c_str(), "r"); if (f == nullptr) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { auto f_d = defer([f] { BIO_free(f); }); @@ -133,7 +132,7 @@ TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, if (PEM_read_bio(f, &name, &header, &data, &datalen) != 1) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { if ("PICOTLS SESSION PARAMETERS"sv != name) { std::println(stderr, "TLS session file contains unexpected name: {}", diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h index 1dd36a2732f242..c5aed12e20f32e 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h @@ -29,6 +29,8 @@ # include #endif // defined(HAVE_CONFIG_H) +#include + #include "tls_session_base_picotls.h" #include "shared.h" @@ -49,7 +51,8 @@ class TLSClientSession : public TLSSessionBase { bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - std::expected write_ech_config_list(const char *path) const { + std::expected + write_ech_config_list(const std::filesystem::path &path) const { return {}; } }; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc index 11aa3174018c32..b2060568347b8f 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc @@ -25,7 +25,6 @@ #include "tls_client_session_quictls.h" #include -#include #include @@ -74,17 +73,17 @@ TLSClientSession::init(bool &early_data_enabled, SSL_set_tlsext_host_name(ssl_, remote_addr); } - if (config.session_file) { - auto f = BIO_new_file(config.session_file, "r"); + if (!config.session_file.empty()) { + auto f = BIO_new_file(config.session_file.c_str(), "r"); if (f == nullptr) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr); BIO_free(f); if (session == nullptr) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { if (!SSL_set_session(ssl_, session)) { std::println(stderr, "Could not set session"); diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h index 53e7a474fddb2b..ad309f61840ebe 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h @@ -29,6 +29,8 @@ # include #endif // defined(HAVE_CONFIG_H) +#include + #include "tls_session_base_quictls.h" #include "shared.h" @@ -48,7 +50,8 @@ class TLSClientSession : public TLSSessionBase { bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - std::expected write_ech_config_list(const char *path) const { + std::expected + write_ech_config_list(const std::filesystem::path &path) const { return {}; } }; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc index ad9c2d16faf1fc..16f5ed79769e7b 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc @@ -26,7 +26,6 @@ #include #include -#include #include "tls_client_context_wolfssl.h" #include "client_base.h" @@ -81,12 +80,12 @@ TLSClientSession::init(bool &early_data_enabled, // Just use QUIC v1 wolfSSL_set_quic_transport_version(ssl_, 0x39); - if (config.session_file) { + if (!config.session_file.empty()) { #ifdef HAVE_SESSION_TICKET - auto f = wolfSSL_BIO_new_file(config.session_file, "r"); + auto f = wolfSSL_BIO_new_file(config.session_file.c_str(), "r"); if (f == nullptr) { std::println(stderr, "Could not open TLS session file {}", - config.session_file); + config.session_file.native()); } else { char *name, *header; unsigned char *data; @@ -96,7 +95,7 @@ TLSClientSession::init(bool &early_data_enabled, if (wolfSSL_PEM_read_bio(f, &name, &header, &data, &datalen) != 1) { std::println(stderr, "Could not read TLS session file {}", - config.session_file); + config.session_file.native()); } else { if ("WOLFSSL SESSION PARAMETERS"sv != name) { std::println(stderr, "TLS session file contains unexpected name: {}", @@ -106,12 +105,12 @@ TLSClientSession::init(bool &early_data_enabled, session = wolfSSL_d2i_SSL_SESSION(nullptr, &pdata, datalen); if (session == nullptr) { std::println(stderr, "Could not parse TLS session from file {}", - config.session_file); + config.session_file.native()); } else { auto ret = wolfSSL_set_session(ssl_, session); if (ret != WOLFSSL_SUCCESS) { std::println(stderr, "Could not install TLS session from file {}", - config.session_file); + config.session_file.native()); } else { if (!config.disable_early_data && wolfSSL_SESSION_get_max_early_data(session)) { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h index 0621a8b21f2939..eb876ebdfcf3af 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h @@ -29,6 +29,8 @@ # include #endif // defined(HAVE_CONFIG_H) +#include + #include "tls_session_base_wolfssl.h" #include "shared.h" @@ -48,7 +50,8 @@ class TLSClientSession : public TLSSessionBase { bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - std::expected write_ech_config_list(const char *path) const { + std::expected + write_ech_config_list(const std::filesystem::path &path) const { return {}; } }; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc index 06b7c34c9fed22..64b3bd013ed9d5 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc @@ -25,7 +25,6 @@ #include "tls_server_context_boringssl.h" #include -#include #include #include @@ -56,7 +55,7 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -95,7 +94,7 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -137,7 +136,7 @@ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { std::expected TLSServerContext::init(const char *private_key_file, const char *cert_file, AppProtocol app_proto) { - constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; + static constexpr unsigned char sid_ctx[] = "ngtcp2 server"; ssl_ctx_ = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx_) { @@ -213,7 +212,7 @@ std::expected TLSServerContext::init(const char *private_key_file, } #endif // defined(HAVE_LIBBROTLI) - if (!config.ech_config.ech_config.empty()) { + if (!config.ech_config.ech_config_list.empty()) { const auto &echconf = config.ech_config; auto pkey = EVP_HPKE_KEY_new(); @@ -232,11 +231,13 @@ std::expected TLSServerContext::init(const char *private_key_file, auto keys = SSL_ECH_KEYS_new(); auto keys_d = defer([keys] { SSL_ECH_KEYS_free(keys); }); - if (SSL_ECH_KEYS_add(keys, 1, echconf.ech_config.data(), - echconf.ech_config.size(), pkey) != 1) { - std::println(stderr, "SSL_ECH_KEYS_add failed: {}", - ERR_error_string(ERR_get_error(), nullptr)); - return std::unexpected{Error::CRYPTO}; + for (const auto &ech_config : echconf.ech_config_list) { + if (SSL_ECH_KEYS_add(keys, 1, ech_config.data(), ech_config.size(), + pkey) != 1) { + std::println(stderr, "SSL_ECH_KEYS_add failed: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; + } } if (SSL_CTX_set1_ech_keys(ssl_ctx_, keys) != 1) { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc index 9b382351c51caf..054db5caaf00b1 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -67,7 +66,7 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -106,7 +105,7 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -149,7 +148,7 @@ namespace { int gen_ticket_cb(SSL *ssl, void *arg) { auto conn_ref = static_cast(SSL_get_app_data(ssl)); auto h = static_cast(conn_ref->user_data); - auto ver = htonl(ngtcp2_conn_get_negotiated_version(h->conn())); + auto ver = htonl(ngtcp2_conn_get_negotiated_version2(h->conn())); if (!SSL_SESSION_set1_ticket_appdata(SSL_get0_session(ssl), &ver, sizeof(ver))) { @@ -192,7 +191,7 @@ SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session, auto conn_ref = static_cast(SSL_get_app_data(ssl)); auto h = static_cast(conn_ref->user_data); - if (ngtcp2_conn_get_client_chosen_version(h->conn()) != ntohl(ver)) { + if (ngtcp2_conn_get_client_chosen_version2(h->conn()) != ntohl(ver)) { switch (status) { case SSL_TICKET_SUCCESS: return SSL_TICKET_RETURN_IGNORE; @@ -215,7 +214,7 @@ SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session, std::expected TLSServerContext::init(const char *private_key_file, const char *cert_file, AppProtocol app_proto) { - constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; + static constexpr unsigned char sid_ctx[] = "ngtcp2 server"; ssl_ctx_ = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx_) { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc index e1498c159957e5..597669df7caf9d 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc @@ -24,7 +24,6 @@ */ #include "tls_server_context_picotls.h" -#include #include #include @@ -207,7 +206,7 @@ int encrypt_ticket_cb(ptls_encrypt_ticket_t *encrypt_ticket, ptls_t *ptls, uint32_t ver; if (is_encrypt) { - ver = htonl(ngtcp2_conn_get_negotiated_version(conn)); + ver = htonl(ngtcp2_conn_get_negotiated_version2(conn)); // TODO Replace std::make_unique with // std::make_unique_for_overwrite when it is available. auto buf = std::make_unique(src.len + sizeof(ver)); @@ -245,7 +244,7 @@ int encrypt_ticket_cb(ptls_encrypt_ticket_t *encrypt_ticket, ptls_t *ptls, memcpy(&ver, dst->base + dst->off - sizeof(ver), sizeof(ver)); - if (ngtcp2_conn_get_client_chosen_version(conn) != ntohl(ver)) { + if (ngtcp2_conn_get_client_chosen_version2(conn) != ntohl(ver)) { return -1; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc index 2a2be68510018f..9c93fdc9ac9b57 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -67,7 +66,7 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -106,7 +105,7 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -150,7 +149,7 @@ namespace { int gen_ticket_cb(SSL *ssl, void *arg) { auto conn_ref = static_cast(SSL_get_app_data(ssl)); auto h = static_cast(conn_ref->user_data); - auto ver = htonl(ngtcp2_conn_get_negotiated_version(h->conn())); + auto ver = htonl(ngtcp2_conn_get_negotiated_version2(h->conn())); if (!SSL_SESSION_set1_ticket_appdata(SSL_get0_session(ssl), &ver, sizeof(ver))) { @@ -193,7 +192,7 @@ SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session, auto conn_ref = static_cast(SSL_get_app_data(ssl)); auto h = static_cast(conn_ref->user_data); - if (ngtcp2_conn_get_client_chosen_version(h->conn()) != ntohl(ver)) { + if (ngtcp2_conn_get_client_chosen_version2(h->conn()) != ntohl(ver)) { switch (status) { case SSL_TICKET_SUCCESS: return SSL_TICKET_RETURN_IGNORE; @@ -217,7 +216,7 @@ SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session, std::expected TLSServerContext::init(const char *private_key_file, const char *cert_file, AppProtocol app_proto) { - constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; + static constexpr unsigned char sid_ctx[] = "ngtcp2 server"; ssl_ctx_ = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx_) { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc index 4c87a6d2666bcc..5245b555c8f88c 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc @@ -25,7 +25,6 @@ #include "tls_server_context_wolfssl.h" #include -#include #include #include #include @@ -54,7 +53,7 @@ int alpn_select_proto_h3_cb(WOLFSSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -94,7 +93,7 @@ int alpn_select_proto_hq_cb(WOLFSSL *ssl, const unsigned char **out, auto h = static_cast(conn_ref->user_data); // This should be the negotiated version, but we have not set the // negotiated version when this callback is called. - auto version = ngtcp2_conn_get_client_chosen_version(h->conn()); + auto version = ngtcp2_conn_get_client_chosen_version2(h->conn()); switch (version) { case NGTCP2_PROTO_VER_V1: @@ -136,7 +135,7 @@ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { std::expected TLSServerContext::init(const char *private_key_file, const char *cert_file, AppProtocol app_proto) { - constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; + static constexpr unsigned char sid_ctx[] = "ngtcp2 server"; #ifdef DEBUG_WOLFSSL if (!config.quiet) { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc index 89c581708c3a99..c2f28045496c2b 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc @@ -25,7 +25,6 @@ #include "tls_server_session_boringssl.h" #include -#include #include diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc index 1b708ede2c0c3a..c0e3a71d1d3179 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc @@ -24,8 +24,6 @@ */ #include "tls_server_session_ossl.h" -#include - #include #include "tls_server_context_ossl.h" diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc index 1d7071df2fb916..6f4dbf568acafa 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc @@ -25,7 +25,6 @@ #include "tls_server_session_picotls.h" #include -#include #include diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc index 5600efea0ed87a..7379f390040488 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc @@ -24,8 +24,6 @@ */ #include "tls_server_session_quictls.h" -#include - #include #include "tls_server_context_quictls.h" diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc index c596b79893a3c4..dce9e47aa8fb4e 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc @@ -24,8 +24,6 @@ */ #include "tls_server_session_wolfssl.h" -#include - #include "tls_server_context_wolfssl.h" #include "server_base.h" diff --git a/deps/ngtcp2/ngtcp2/examples/util.cc b/deps/ngtcp2/ngtcp2/examples/util.cc index b398210179e080..8f6d7c7668f074 100644 --- a/deps/ngtcp2/ngtcp2/examples/util.cc +++ b/deps/ngtcp2/ngtcp2/examples/util.cc @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -58,13 +57,13 @@ namespace ngtcp2 { namespace util { std::expected -read_hpke_private_key_pem(std::string_view filename); +read_hpke_private_key_pem(const std::filesystem::path &path); -std::expected, Error> read_pem(std::string_view filename, - std::string_view name, - std::string_view type); +std::expected, Error> +read_pem(const std::filesystem::path &path, std::string_view name, + std::string_view type); -std::expected write_pem(std::string_view filename, +std::expected write_pem(const std::filesystem::path &path, std::string_view name, std::string_view type, std::span data); @@ -270,7 +269,7 @@ std::expected hexdump(FILE *out, std::span data) { // accept, which is the size of a single full line output + one // repeat line marker ("*\n"). If the remaining buffer size is less // than that, flush the buffer and reset. - constexpr size_t min_space = 79 + 2; + constexpr auto min_space = 79UZ + 2UZ; auto fd = fileno(out); std::array buf; @@ -390,8 +389,8 @@ constexpr bool rws(char c) { return c == '\t' || c == ' '; } } // namespace std::expected, Error> -read_mime_types(std::string_view filename) { - std::ifstream f(filename.data()); +read_mime_types(const std::filesystem::path &filename) { + std::ifstream f(filename); if (!f) { return std::unexpected{Error::IO}; } @@ -417,7 +416,9 @@ read_mime_types(std::string_view filename) { } p = std::ranges::find_if(ext, std::ranges::end(line), rws); - dest.emplace(std::string{ext, p}, media_type); + auto key = "."s; + key += std::string{ext, p}; + dest.emplace(key, media_type); } } @@ -455,6 +456,10 @@ parse_uint_internal(std::string_view s) { for (size_t i = 0; i < s.size(); ++i) { auto c = s[i]; if (!is_digit(c)) { + if (i == 0) { + return std::unexpected{Error::INVALID_ARGUMENT}; + } + return {{res, i}}; } @@ -614,7 +619,7 @@ template InputIt eat_dir(InputIt first, InputIt last) { } // namespace std::expected normalize_path(std::string_view path) { - constexpr size_t max_path = 1024; + constexpr auto max_path = 1024UZ; if (path.size() > max_path) { return std::unexpected{Error::INVALID_ARGUMENT}; @@ -710,30 +715,6 @@ std::expected create_nonblock_socket(int domain, int type, return fd; } -std::vector split_str(std::string_view s, char delim) { - size_t len = 1; - auto last = std::ranges::end(s); - std::string_view::const_iterator d; - for (auto first = std::ranges::begin(s); - (d = std::ranges::find(first, last, delim)) != last; - ++len, first = d + 1) - ; - - auto list = std::vector(len); - - len = 0; - for (auto first = std::ranges::begin(s);; ++len) { - auto stop = std::ranges::find(first, last, delim); - // xcode clang does not understand std::string_view{first, stop}. - list[len] = std::string_view{first, static_cast(stop - first)}; - if (stop == last) { - break; - } - first = stop + 1; - } - return list; -} - std::expected parse_version(std::string_view s) { if (!util::istarts_with(s, "0x"sv)) { return std::unexpected{Error::INVALID_ARGUMENT}; @@ -750,25 +731,25 @@ std::expected parse_version(std::string_view s) { } std::expected, Error> -read_token(std::string_view filename) { - return read_pem(filename, "token"sv, "QUIC TOKEN"sv); +read_token(const std::filesystem::path &path) { + return read_pem(path, "token"sv, "QUIC TOKEN"sv); } -std::expected write_token(std::string_view filename, +std::expected write_token(const std::filesystem::path &path, std::span token) { - return write_pem(filename, "token"sv, "QUIC TOKEN"sv, token); + return write_pem(path, "token"sv, "QUIC TOKEN"sv, token); } std::expected, Error> -read_transport_params(std::string_view filename) { - return read_pem(filename, "transport parameters"sv, +read_transport_params(const std::filesystem::path &path) { + return read_pem(path, "transport parameters"sv, "QUIC TRANSPORT PARAMETERS"sv); } std::expected -write_transport_params(std::string_view filename, +write_transport_params(const std::filesystem::path &path, std::span data) { - return write_pem(filename, "transport parameters"sv, + return write_pem(path, "transport parameters"sv, "QUIC TRANSPORT PARAMETERS"sv, data); } @@ -802,8 +783,9 @@ std::string percent_decode(std::string_view s) { return result; } -std::expected, Error> read_file(std::string_view path) { - auto fd = open(path.data(), O_RDONLY); +std::expected, Error> +read_file(const std::filesystem::path &path) { + auto fd = open(path.c_str(), O_RDONLY); if (fd == -1) { return std::unexpected{Error::IO}; } @@ -831,8 +813,8 @@ std::expected, Error> read_file(std::string_view path) { size_t clamp_buffer_size(ngtcp2_conn *conn, size_t buflen, size_t gso_burst) { return std::min(gso_burst == 0 - ? ngtcp2_conn_get_send_quantum(conn) - : ngtcp2_conn_get_path_max_tx_udp_payload_size(conn) * + ? ngtcp2_conn_get_send_quantum2(conn) + : ngtcp2_conn_get_path_max_tx_udp_payload_size2(conn) * gso_burst, buflen); } @@ -844,20 +826,60 @@ bool recv_pkt_time_threshold_exceeded(bool time_sensitive, ngtcp2_tstamp start, } std::expected -read_ech_server_config(std::string_view path) { +read_ech_server_config(const std::filesystem::path &path) { auto pkey = read_hpke_private_key_pem(path); if (!pkey) { return std::unexpected{pkey.error()}; } - auto ech_config = read_pem(path, "ECH config"sv, "ECHCONFIG"sv); - if (!ech_config) { - return std::unexpected{ech_config.error()}; + auto maybe_ech_config_list = read_pem(path, "ECH config"sv, "ECHCONFIG"sv); + if (!maybe_ech_config_list) { + return std::unexpected{maybe_ech_config_list.error()}; + } + + auto ech_config_list = std::span{*maybe_ech_config_list}; + if (ech_config_list.size() < 2) { + return std::unexpected{Error::INVALID_ARGUMENT}; + } + + auto data = ech_config_list.subspan(2); + + if (auto len = + static_cast((ech_config_list[0] << 8) + ech_config_list[1]); + len != data.size()) { + return std::unexpected{Error::INVALID_ARGUMENT}; + } + + std::vector> ech_configs; + + for (; !data.empty();) { + // version and length, each 2 bytes + if (data.size() < 4) { + return std::unexpected{Error::INVALID_ARGUMENT}; + } + + auto version = (data[0] << 8) + data[1]; + + auto conflen = static_cast(4 + (data[2] << 8) + data[3]); + if (data.size() < conflen) { + return std::unexpected{Error::INVALID_ARGUMENT}; + } + + if (version == 0xFE0D) { + auto conf = data.first(conflen); + ech_configs.emplace_back(std::ranges::begin(conf), + std::ranges::end(conf)); + } else { + std::println(stderr, "Skipping the unsupported ECH version {:#x}", + version); + } + + data = data.subspan(conflen); } return ECHServerConfig{ .private_key = std::move(*pkey), - .ech_config = std::move(*ech_config), + .ech_config_list = std::move(ech_configs), }; } @@ -878,16 +900,17 @@ std::span generate_siphash_key() { return key; } -std::string realpath(const char *path) { - auto cpath = ::realpath(path, nullptr); - if (!cpath) { - assert(0); +std::filesystem::path realpath(const std::filesystem::path &path) { + std::error_code ec; + + auto abspath = std::filesystem::canonical(path, ec); + if (ec) { + std::println(stderr, "Could not get canonical path for {}: {}", + path.native(), ec.message()); abort(); } - auto cpath_d = defer([cpath] { free(cpath); }); - - return cpath; + return abspath; } } // namespace util diff --git a/deps/ngtcp2/ngtcp2/examples/util.h b/deps/ngtcp2/ngtcp2/examples/util.h index 81306fd03d91a1..1fc855470dcf78 100644 --- a/deps/ngtcp2/ngtcp2/examples/util.h +++ b/deps/ngtcp2/ngtcp2/examples/util.h @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -293,9 +295,9 @@ std::string_view strccalgo(ngtcp2_cc_algo cc_algo); // read_mime_types reads "MIME media types and the extensions" file // denoted by |filename| and returns the mapping of extension to MIME -// media type. +// media type. The key contains the leading "." (e.g., .txt). std::expected, Error> -read_mime_types(std::string_view filename); +read_mime_types(const std::filesystem::path &filename); inline constexpr auto count_digit_tbl = [] { std::array::digits10> tbl; @@ -516,14 +518,14 @@ std::expected create_nonblock_socket(int domain, int type, int protocol); std::expected, Error> -read_token(std::string_view filename); -std::expected write_token(std::string_view filename, +read_token(const std::filesystem::path &path); +std::expected write_token(const std::filesystem::path &path, std::span token); std::expected, Error> -read_transport_params(std::string_view filename); +read_transport_params(const std::filesystem::path &path); std::expected -write_transport_params(std::string_view filename, +write_transport_params(const std::filesystem::path &path, std::span data); const char *crypto_default_ciphers(); @@ -532,15 +534,21 @@ const char *crypto_default_groups(); // split_str parses delimited strings in |s| and returns substrings // delimited by |delim|. The any white spaces around substring are -// treated as a part of substring. -std::vector split_str(std::string_view s, char delim = ','); +// treated as a part of substring. If |s| is an empty string, this +// function returns an empty view. +inline auto split_str(std::string_view s, char delim = ',') { + return s | std::ranges::views::split(delim) | + std::ranges::views::transform( + [](auto &&r) { return std::string_view{r}; }); +} // parse_version parses |s| to get 4 byte QUIC version. |s| must be a // hex string and must start with "0x" (e.g., 0x00000001). std::expected parse_version(std::string_view s); // read_file reads a file denoted by |path| and returns its content. -std::expected, Error> read_file(std::string_view path); +std::expected, Error> +read_file(const std::filesystem::path &path); size_t clamp_buffer_size(ngtcp2_conn *conn, size_t buflen, size_t gso_burst); @@ -564,14 +572,14 @@ struct ECHServerConfig { // private_key contains a private key used for decrypting encrypted // Client Hello. HPKEPrivateKey private_key; - // ech_config contains a serialized ECHConfig. - std::vector ech_config; + // ech_config_list contains list of a serialized ECHConfig. + std::vector> ech_config_list; }; // read_ech_server_config reads server-side ECH configuration from a // file denoted by |path|. std::expected -read_ech_server_config(std::string_view path); +read_ech_server_config(const std::filesystem::path &path); std::span generate_siphash_key(); @@ -586,7 +594,7 @@ get_string(std::string_view uri, const urlparse_url &u, urlparse_url_fields f) { } // realpath returns the canonicalized absolute path to |path|. -std::string realpath(const char *path); +std::filesystem::path realpath(const std::filesystem::path &path); } // namespace util @@ -615,7 +623,8 @@ inline bool operator==(const ngtcp2_cid &lhs, const ngtcp2_cid &rhs) { template <> struct std::formatter : public std::formatter { - auto format(ngtcp2_cid cid, format_context &ctx) const { + template + auto format(const ngtcp2_cid &cid, FormatContext &ctx) const { std::array buf; buf[0] = '0'; buf[1] = 'x'; diff --git a/deps/ngtcp2/ngtcp2/examples/util_openssl.cc b/deps/ngtcp2/ngtcp2/examples/util_openssl.cc index 382eb3039c2f3d..f07dd01654e036 100644 --- a/deps/ngtcp2/ngtcp2/examples/util_openssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/util_openssl.cc @@ -25,10 +25,10 @@ #include "util.h" #include -#include #include #include #include +#include #include @@ -58,10 +58,10 @@ std::expected generate_secure_random(std::span data) { } std::expected -read_hpke_private_key_pem(std::string_view filename) { - auto f = BIO_new_file(filename.data(), "r"); +read_hpke_private_key_pem(const std::filesystem::path &path) { + auto f = BIO_new_file(path.c_str(), "r"); if (f == nullptr) { - std::println(stderr, "Could not open file {}", filename); + std::println(stderr, "Could not open file {}", path.native()); return std::unexpected{Error::IO}; } @@ -98,12 +98,12 @@ read_hpke_private_key_pem(std::string_view filename) { return res; } -std::expected, Error> read_pem(std::string_view filename, - std::string_view name, - std::string_view type) { - auto f = BIO_new_file(filename.data(), "r"); +std::expected, Error> +read_pem(const std::filesystem::path &path, std::string_view name, + std::string_view type) { + auto f = BIO_new_file(path.c_str(), "r"); if (f == nullptr) { - std::println(stderr, "Could not open {} file {}", name, filename); + std::println(stderr, "Could not open {} file {}", name, path.native()); return std::unexpected{Error::IO}; } @@ -115,7 +115,7 @@ std::expected, Error> read_pem(std::string_view filename, long datalen; if (PEM_read_bio(f, &pem_type, &header, &data, &datalen) != 1) { - std::println(stderr, "Could not read {} file {}", name, filename); + std::println(stderr, "Could not read {} file {}", name, path.native()); return std::unexpected{Error::IO}; } @@ -133,13 +133,13 @@ std::expected, Error> read_pem(std::string_view filename, } } -std::expected write_pem(std::string_view filename, +std::expected write_pem(const std::filesystem::path &path, std::string_view name, std::string_view type, std::span data) { - auto f = BIO_new_file(filename.data(), "w"); + auto f = BIO_new_file(path.c_str(), "w"); if (f == nullptr) { - std::println(stderr, "Could not write {} in {}", name, filename); + std::println(stderr, "Could not write {} in {}", name, path.native()); return std::unexpected{Error::IO}; } @@ -165,9 +165,11 @@ const char *crypto_default_ciphers() { const char *crypto_default_groups() { return "X25519:P-256:P-384:P-521" -#if defined(WITH_EXAMPLE_BORINGSSL) || defined(WITH_EXAMPLE_OSSL) +#if defined(WITH_EXAMPLE_BORINGSSL) || defined(WITH_EXAMPLE_OSSL) || \ + defined(LIBRESSL_VERSION_NUMBER) ":X25519MLKEM768" -#endif // defined(WITH_EXAMPLE_BORINGSSL) || defined(WITH_EXAMPLE_OSSL) +#endif // defined(WITH_EXAMPLE_BORINGSSL) || defined(WITH_EXAMPLE_OSSL) || + // defined(LIBRESSL_VERSION_NUMBER) ; } diff --git a/deps/ngtcp2/ngtcp2/examples/util_test.cc b/deps/ngtcp2/ngtcp2/examples/util_test.cc index 430a61a9734202..46934221d0a7d4 100644 --- a/deps/ngtcp2/ngtcp2/examples/util_test.cc +++ b/deps/ngtcp2/ngtcp2/examples/util_test.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include "util.h" @@ -49,6 +50,7 @@ const MunitTest tests[]{ munit_void_test(test_util_format_hex), munit_void_test(test_util_decode_hex), munit_void_test(test_util_is_hex_string), + munit_void_test(test_util_split_str), munit_test_end(), }; } // namespace @@ -60,21 +62,21 @@ const MunitSuite util_suite{ namespace util { std::expected -read_hpke_private_key_pem(std::string_view filename) { +read_hpke_private_key_pem(const std::filesystem::path &path) { return std::unexpected{Error::NOT_IMPLEMENTED}; } } // namespace util namespace util { -std::expected, Error> read_pem(std::string_view filename, - std::string_view name, - std::string_view type) { +std::expected, Error> +read_pem(const std::filesystem::path &path, std::string_view name, + std::string_view type) { return std::unexpected{Error::NOT_IMPLEMENTED}; } } // namespace util namespace util { -std::expected write_pem(std::string_view filename, +std::expected write_pem(const std::filesystem::path &path, std::string_view name, std::string_view type, std::span data) { @@ -162,6 +164,10 @@ void test_util_parse_uint() { auto res = util::parse_uint("1a"); assert_false(res.has_value()); } + { + auto res = util::parse_uint(""); + assert_false(res.has_value()); + } } void test_util_parse_uint_iec() { @@ -207,6 +213,14 @@ void test_util_parse_uint_iec() { auto res = util::parse_uint_iec("1Gx"); assert_false(res.has_value()); } + { + auto res = util::parse_uint_iec("G"); + assert_false(res.has_value()); + } + { + auto res = util::parse_uint_iec(""); + assert_false(res.has_value()); + } } void test_util_parse_duration() { @@ -276,6 +290,18 @@ void test_util_parse_duration() { auto res = util::parse_duration("1mxy"); assert_false(res.has_value()); } + { + auto res = util::parse_duration("s"); + assert_false(res.has_value()); + } + { + auto res = util::parse_duration("ms"); + assert_false(res.has_value()); + } + { + auto res = util::parse_duration(""); + assert_false(res.has_value()); + } } void test_util_normalize_path() { @@ -579,4 +605,21 @@ void test_util_is_hex_string() { assert_false(util::is_hex_string("z"sv)); } +void test_util_split_str() { + assert_true((std::vector{"alpha"sv, "bravo"sv, "charlie"sv} == + (util::split_str("alpha,bravo,charlie"sv) | + std::ranges::to()))); + assert_true((std::vector{"alpha"sv, "bravo"sv, "charlie"sv} == + (util::split_str("alpha bravo charlie"sv, ' ') | + std::ranges::to()))); + assert_true((std::vector{} == + (util::split_str(""sv, ' ') | std::ranges::to()))); + assert_true((std::vector{""sv, ""sv} == + (util::split_str(","sv) | std::ranges::to()))); + assert_true( + (std::vector{""sv, "alpha"sv, ""sv, ""sv, "bravo"sv, "charlie"sv, ""sv, + ""sv} == (util::split_str(" alpha bravo charlie "sv, ' ') | + std::ranges::to()))); +} + } // namespace ngtcp2 diff --git a/deps/ngtcp2/ngtcp2/examples/util_test.h b/deps/ngtcp2/ngtcp2/examples/util_test.h index f5a597d76d5da8..3546bcfc0ce6db 100644 --- a/deps/ngtcp2/ngtcp2/examples/util_test.h +++ b/deps/ngtcp2/ngtcp2/examples/util_test.h @@ -49,6 +49,7 @@ munit_void_test_decl(test_util_hexdump) munit_void_test_decl(test_util_format_hex) munit_void_test_decl(test_util_decode_hex) munit_void_test_decl(test_util_is_hex_string) +munit_void_test_decl(test_util_split_str) } // namespace ngtcp2 diff --git a/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc index 8918847da1a95f..904067b101edd4 100644 --- a/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc @@ -25,10 +25,10 @@ #include "util.h" #include -#include #include #include #include +#include #include @@ -51,16 +51,16 @@ std::expected generate_secure_random(std::span data) { } std::expected -read_hpke_private_key_pem(std::string_view filename) { +read_hpke_private_key_pem(const std::filesystem::path &path) { return std::unexpected{Error::NOT_IMPLEMENTED}; } -std::expected, Error> read_pem(std::string_view filename, - std::string_view name, - std::string_view type) { - auto f = wolfSSL_BIO_new_file(filename.data(), "r"); +std::expected, Error> +read_pem(const std::filesystem::path &path, std::string_view name, + std::string_view type) { + auto f = wolfSSL_BIO_new_file(path.c_str(), "r"); if (f == nullptr) { - std::println(stderr, "Could not open {} file {}", name, filename); + std::println(stderr, "Could not open {} file {}", name, path.native()); return std::unexpected{Error::IO}; } @@ -71,7 +71,7 @@ std::expected, Error> read_pem(std::string_view filename, long datalen; if (wolfSSL_PEM_read_bio(f, &pem_type, &header, &data, &datalen) != 1) { - std::println(stderr, "Could not read {} file {}", name, filename); + std::println(stderr, "Could not read {} file {}", name, path.native()); return std::unexpected{Error::IO}; } @@ -82,20 +82,21 @@ std::expected, Error> read_pem(std::string_view filename, }); if (type != pem_type) { - std::println(stderr, "{} file {} contains unexpected type", name, filename); + std::println(stderr, "{} file {} contains unexpected type", name, + path.native()); return std::unexpected{Error::IO}; } return {{data, data + datalen}}; } -std::expected write_pem(std::string_view filename, +std::expected write_pem(const std::filesystem::path &path, std::string_view name, std::string_view type, std::span data) { - auto f = wolfSSL_BIO_new_file(filename.data(), "w"); + auto f = wolfSSL_BIO_new_file(path.c_str(), "w"); if (f == nullptr) { - std::println(stderr, "Could not write {} to {}", name, filename); + std::println(stderr, "Could not write {} to {}", name, path.native()); return std::unexpected{Error::IO}; } diff --git a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h index c71ff364e3099f..278b30ca07bf18 100644 --- a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h +++ b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h @@ -275,16 +275,24 @@ typedef struct ngtcp2_mem { /** * @macro * + * .. warning:: + * + * .. version-deprecated:: 1.1.0 + * * :macro:`NGTCP2_PROTO_VER_MAX` is the highest QUIC version that this - * library supports. Deprecated since v1.1.0. + * library supports. */ #define NGTCP2_PROTO_VER_MAX NGTCP2_PROTO_VER_V1 /** * @macro * + * .. warning:: + * + * .. version-deprecated:: 1.1.0 + * * :macro:`NGTCP2_PROTO_VER_MIN` is the lowest QUIC version that this - * library supports. Deprecated since v1.1.0. + * library supports. */ #define NGTCP2_PROTO_VER_MIN NGTCP2_PROTO_VER_V1 @@ -324,11 +332,13 @@ typedef struct ngtcp2_mem { /** * @macro * + * .. warning:: + * + * .. version-deprecated:: 1.17.0 + * Path MTU Discovery is not capped to this value anymore. + * * :macro:`NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE` was the maximum UDP * datagram payload size that Path MTU Discovery can discover. - * - * Deprecated since v1.17.0. Path MTU Discovery is not capped to this - * value anymore. */ #define NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE 1452 @@ -1186,10 +1196,12 @@ typedef struct ngtcp2_pkt_hd { /** * @struct * - * :type:`ngtcp2_pkt_stateless_reset` represents Stateless Reset. + * .. warning:: * - * Deprecated since v1.22.0. Use :type:`ngtcp2_pkt_stateless_reset2` - * instead. + * .. version-deprecated:: 1.22.0 + * Use :type:`ngtcp2_pkt_stateless_reset2` instead. + * + * :type:`ngtcp2_pkt_stateless_reset` represents Stateless Reset. */ typedef struct ngtcp2_pkt_stateless_reset { /** @@ -1212,7 +1224,7 @@ typedef struct ngtcp2_pkt_stateless_reset { * * :type:`ngtcp2_stateless_reset_token` stores stateless reset token. * - * This struct has been available since v1.22.0. + * .. version-added:: 1.22.0 */ typedef struct ngtcp2_stateless_reset_token { uint8_t data[NGTCP2_STATELESS_RESET_TOKENLEN]; @@ -1223,7 +1235,7 @@ typedef struct ngtcp2_stateless_reset_token { * * :type:`ngtcp2_pkt_stateless_reset2` represents Stateless Reset. * - * This struct has been available since v1.22.0. + * .. version-added:: 1.22.0 */ typedef struct ngtcp2_pkt_stateless_reset2 { /** @@ -1350,6 +1362,14 @@ typedef struct sockaddr ngtcp2_sockaddr; * the generic struct sockaddr_in defined in ngtcp2.h. */ typedef struct sockaddr_in ngtcp2_sockaddr_in; +/** + * @typedef + * + * :type:`ngtcp2_in_addr` is typedefed to struct in_addr. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * the generic struct in_addr defined in ngtcp2.h. + */ +typedef struct in_addr ngtcp2_in_addr; /** * @typedef * @@ -1358,6 +1378,14 @@ typedef struct sockaddr_in ngtcp2_sockaddr_in; * to the generic struct sockaddr_in6 defined in ngtcp2.h. */ typedef struct sockaddr_in6 ngtcp2_sockaddr_in6; +/** + * @typedef + * + * :type:`ngtcp2_in6_addr` is typedefed to struct in6_addr. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * the generic struct in6_addr defined in ngtcp2.h. + */ +typedef struct in6_addr ngtcp2_in6_addr; /** * @typedef * @@ -1652,50 +1680,59 @@ typedef struct ngtcp2_conn_info { * packets which have not been acknowledged. */ uint64_t bytes_in_flight; - /* The following fields have been added since NGTCP2_CONN_INFO_V2. */ + /* The following fields have been added since + NGTCP2_CONN_INFO_V2. */ /** - * :member:`pkt_sent` is the number of QUIC packets sent. This - * field has been available since v1.16.0. + * :member:`pkt_sent` is the number of QUIC packets sent. + * + * .. version-added:: 1.16.0 */ uint64_t pkt_sent; /** * :member:`bytes_sent` is the number of bytes (the sum of QUIC - * packet length) sent. This field has been available since - * v1.16.0. + * packet length) sent. + * + * .. version-added:: 1.16.0 */ uint64_t bytes_sent; /** * :member:`pkt_recv` is the number of QUIC packets received, - * excluding discarded ones. This field has been available since - * v1.16.0. + * excluding discarded ones. + * + * .. version-added:: 1.16.0 */ uint64_t pkt_recv; /** * :member:`bytes_recv` is the number of bytes (the sum of QUIC - * packet length) received, excluding discarded ones. This field - * has been available since v1.16.0. + * packet length) received, excluding discarded ones. + * + * .. version-added:: 1.16.0 */ uint64_t bytes_recv; /** * :member:`pkt_lost` is the number of QUIC packets that are - * considered lost, excluding PMTUD packets. This field has been - * available since v1.16.0. + * considered lost, excluding PMTUD packets. + * + * .. version-added:: 1.16.0 */ uint64_t pkt_lost; /** * :member:`bytes_lost` is the number of bytes (the sum of QUIC - * packet length) lost, excluding PMTUD packets. This field has - * been available since v1.16.0. + * packet length) lost, excluding PMTUD packets. + * + * .. version-added:: 1.16.0 */ uint64_t bytes_lost; /** - * :member:`ping_recv` is the number of PING frames received. This - * field has been available since v1.16.0. + * :member:`ping_recv` is the number of PING frames received. + * + * .. version-added:: 1.16.0 */ uint64_t ping_recv; /** * :member:`pkt_discarded` is the number of QUIC packets discarded. - * This field has been available since v1.16.0. + * + * .. version-added:: 1.16.0 */ uint64_t pkt_discarded; } ngtcp2_conn_info; @@ -1723,12 +1760,32 @@ typedef enum ngtcp2_cc_algo { /** * @functypedef * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use :type:`ngtcp2_log_write` instead. + * * :type:`ngtcp2_printf` is a callback function for logging. * |user_data| is the same object passed to `ngtcp2_conn_client_new` * or `ngtcp2_conn_server_new`. */ typedef void (*ngtcp2_printf)(void *user_data, const char *format, ...); +/** + * @functypedef + * + * :type:`ngtcp2_log_write` is a callback function for logging. + * |user_data| is the same object passed to `ngtcp2_conn_client_new` + * or `ngtcp2_conn_server_new`. The caller guarantees that the memory + * region [|msg|, |msg| + |len|], inclusive, are writable, and + * |msg|[|len|] == '\0'. If application needs to emit a single line + * with a line terminator, one can do msg[len] = '\n', and write |len| + * + 1 bytes from |msg|. + * + * .. version-added:: 1.23.0 + */ +typedef void (*ngtcp2_log_write)(void *user_data, char *msg, size_t len); + /** * @macrosection * @@ -1803,7 +1860,8 @@ typedef enum ngtcp2_token_type { #define NGTCP2_SETTINGS_V1 1 #define NGTCP2_SETTINGS_V2 2 #define NGTCP2_SETTINGS_V3 3 -#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V3 +#define NGTCP2_SETTINGS_V4 4 +#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V4 /** * @struct @@ -1830,6 +1888,11 @@ typedef struct ngtcp2_settings { */ ngtcp2_duration initial_rtt; /** + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use :member:`log_write` instead. + * * :member:`log_printf` is a function that the library uses to write * logs. ``NULL`` means no logging output. It is nothing to do * with qlog. @@ -2009,14 +2072,16 @@ typedef struct ngtcp2_settings { * or equal to :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE`. Otherwise * the behavior is undefined. The maximum value in this array * should be set to :member:`max_tx_udp_payload_size`. If this - * field is not set, the predefined PMTUD probes are made. This - * field has been available since v1.4.0. + * field is not set, the predefined PMTUD probes are made. + * + * .. version-added:: 1.4.0 */ const uint16_t *pmtud_probes; /** * :member:`pmtud_probeslen` is the number of elements that are - * contained in the array pointed by :member:`pmtud_probes`. This - * field has been available since v1.4.0. + * contained in the array pointed by :member:`pmtud_probes`. + * + * .. version-added:: 1.4.0 */ size_t pmtud_probeslen; /* The following fields have been added since NGTCP2_SETTINGS_V3. */ @@ -2026,16 +2091,31 @@ typedef struct ngtcp2_settings { * activity from a remote endpoint. If detected, certain amount of * tokens are consumed. If no tokens are available to consume, the * connection is closed. The rate of token generation is specified - * by :member:`glitch_ratelim_rate`. This field has been available - * since v1.15.0. + * by :member:`glitch_ratelim_rate`. + * + * .. version-added:: 1.15.0 */ uint64_t glitch_ratelim_burst; /** * :member:`glitch_ratelim_rate` is the number of tokens generated * per second. See :member:`glitch_ratelim_burst` for "glitch" rate - * limiter. This field has been available since v1.15.0. + * limiter. + * + * .. version-added:: 1.15.0 */ uint64_t glitch_ratelim_rate; + /* The following fields have been added since NGTCP2_SETTINGS_V4. */ + /** + * :member:`log_write` is the callback function when a single log + * message is emitted. If both :member:`log_write` and + * :member:`log_printf` are specified, the former has precedence. + * If both :member:`log_write` and :member:`log_printf` are + * ``NULL``, logging is disabled. For qlog, see + * :member:`qlog_write`. + * + * .. version-added:: 1.23.0 + */ + ngtcp2_log_write log_write; } ngtcp2_settings; /** @@ -2461,6 +2541,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_decode_hd_short(ngtcp2_pkt_hd *dest, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use `ngtcp2_pkt_write_stateless_reset2` instead. + * * `ngtcp2_pkt_write_stateless_reset` writes Stateless Reset packet in * the buffer pointed by |dest| whose length is |destlen|. * |stateless_reset_token| is a pointer to the Stateless Reset Token, @@ -2481,9 +2566,6 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_decode_hd_short(ngtcp2_pkt_hd *dest, * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` * |randlen| is strictly less than * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`. - * - * Deprecated since v1.22.0. Use `ngtcp2_pkt_write_stateless_reset2` - * instead. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset( uint8_t *dest, size_t destlen, const uint8_t *stateless_reset_token, @@ -2511,7 +2593,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset( * |randlen| is strictly less than * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`. * - * This function has been available since v1.22.0. + * .. version-added:: 1.22.0 */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset2( uint8_t *dest, size_t destlen, const ngtcp2_stateless_reset_token *token, @@ -2966,6 +3048,11 @@ typedef int (*ngtcp2_acked_stream_data_offset)( /** * @functypedef * + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :type:`ngtcp2_recv_stateless_reset2` instead. + * * :type:`ngtcp2_recv_stateless_reset` is a callback function which is * called when Stateless Reset packet is received. The stateless * reset details are given in |sr|. @@ -2973,9 +3060,6 @@ typedef int (*ngtcp2_acked_stream_data_offset)( * The implementation of this callback should return 0 if it succeeds. * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library * call return immediately. - * - * Deprecated since v1.22.0. Use :type:`ngtcp2_recv_stateless_reset2` - * instead. */ typedef int (*ngtcp2_recv_stateless_reset)(ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset *sr, @@ -3028,6 +3112,11 @@ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, /** * @functypedef * + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :type:`ngtcp2_get_new_connection_id2` instead. + * * :type:`ngtcp2_get_new_connection_id` is a callback function to ask * an application for new connection ID. Application must generate * new unused connection ID with the exact |cidlen| bytes, and store @@ -3040,9 +3129,6 @@ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. - * - * Deprecated since v1.22.0. Use - * :type:`ngtcp2_get_new_connection_id2` instead. */ typedef int (*ngtcp2_get_new_connection_id)(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token, size_t cidlen, @@ -3187,7 +3273,7 @@ typedef int (*ngtcp2_path_validation)(ngtcp2_conn *conn, uint32_t flags, * address, leave :member:`dest->local ` * unmodified, or copy the value of :member:`local * ` field of the current network path obtained - * from `ngtcp2_conn_get_path()`. Both :member:`dest->local.addr + * from `ngtcp2_conn_get_path2()`. Both :member:`dest->local.addr * ` and :member:`dest->remote.addr * ` point to buffers which are at least * sizeof(:type:`ngtcp2_sockaddr_union`) bytes long, respectively. If @@ -3227,6 +3313,11 @@ typedef enum ngtcp2_connection_id_status_type { /** * @functypedef * + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :type:`ngtcp2_connection_id_status2` instead. + * * :type:`ngtcp2_connection_id_status` is a callback function which is * called when the status of Destination Connection ID changes. * @@ -3240,9 +3331,6 @@ typedef enum ngtcp2_connection_id_status_type { * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. - * - * Deprecated since v1.22.0. Use :type:`ngtcp2_connection_id_status2` - * instead. */ typedef int (*ngtcp2_connection_id_status)( ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq, @@ -3361,6 +3449,11 @@ typedef int (*ngtcp2_lost_datagram)(ngtcp2_conn *conn, uint64_t dgram_id, /** * @functypedef * + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :type:`ngtcp2_get_path_challenge_data2` instead. + * * :type:`ngtcp2_get_path_challenge_data` is a callback function to * ask an application for new data that is sent in PATH_CHALLENGE * frame. Application must generate new unpredictable, exactly @@ -3370,9 +3463,6 @@ typedef int (*ngtcp2_lost_datagram)(ngtcp2_conn *conn, uint64_t dgram_id, * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. - * - * Deprecated since v1.22.0. Use - * :type:`ngtcp2_get_path_challenge_data2` instead. */ typedef int (*ngtcp2_get_path_challenge_data)(ngtcp2_conn *conn, uint8_t *data, void *user_data); @@ -3455,7 +3545,7 @@ typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn, * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library * call return immediately. * - * This type has been available since v1.22.0 + * .. version-added:: 1.22.0 */ typedef int (*ngtcp2_recv_stateless_reset2)( ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset2 *sr, void *user_data); @@ -3473,7 +3563,7 @@ typedef int (*ngtcp2_recv_stateless_reset2)( * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. * - * This type has been available since v1.22.0 + * .. version-added:: 1.22.0 */ typedef int (*ngtcp2_get_new_connection_id2)( ngtcp2_conn *conn, ngtcp2_cid *cid, ngtcp2_stateless_reset_token *token, @@ -3496,7 +3586,7 @@ typedef int (*ngtcp2_get_new_connection_id2)( * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. * - * This type has been available since v1.22.0 + * .. version-added:: 1.22.0 */ typedef int (*ngtcp2_connection_id_status2)( ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq, @@ -3508,7 +3598,7 @@ typedef int (*ngtcp2_connection_id_status2)( * * :type:`ngtcp2_path_challenge_data` stores path challenge data. * - * This type has been available since v1.22.0. + * .. version-added:: 1.22.0 */ typedef struct ngtcp2_path_challenge_data { uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; @@ -3527,7 +3617,7 @@ typedef struct ngtcp2_path_challenge_data { * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. * - * This type has been available since v1.22.0. + * .. version-added:: 1.22.0 */ typedef int (*ngtcp2_get_path_challenge_data2)(ngtcp2_conn *conn, ngtcp2_path_challenge_data *data, @@ -3620,14 +3710,17 @@ typedef struct ngtcp2_callbacks { */ ngtcp2_stream_close stream_close; /** + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :member:`recv_stateless_reset2` instead. If both + * :member:`recv_stateless_reset` and + * :member:`recv_stateless_reset2` are set, the latter has the + * precedence. + * * :member:`recv_stateless_reset` is a callback function which is * invoked when Stateless Reset packet is received. This callback * function is optional. - * - * Deprecated since v1.22.0. Use :member:`recv_stateless_reset2` - * instead. If both :member:`recv_stateless_reset` and - * :member:`recv_stateless_reset2` are set, the latter has the - * precedence. */ ngtcp2_recv_stateless_reset recv_stateless_reset; /** @@ -3657,15 +3750,18 @@ typedef struct ngtcp2_callbacks { */ ngtcp2_rand rand; /** + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :member:`get_new_connection_id2` instead. If both + * :member:`get_new_connection_id` and + * :member:`get_new_connection_id2` are set, the latter has the + * precedence. + * * :member:`get_new_connection_id` is a callback function which is * invoked when the library needs new connection ID. Either this * callback function or :member:`get_new_connection_id2` must be * specified. - * - * Deprecated since v1.22.0. Use :member:`get_new_connection_id2` - * instead. If both :member:`get_new_connection_id` and - * :member:`get_new_connection_id2` are set, the latter has the - * precedence. */ ngtcp2_get_new_connection_id get_new_connection_id; /** @@ -3722,14 +3818,17 @@ typedef struct ngtcp2_callbacks { */ ngtcp2_extend_max_stream_data extend_max_stream_data; /** + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :member:`dcid_status2` instead. If both + * :member:`dcid_status` and :member:`dcid_status2` are set, the + * latter has the precedence. + * * :member:`dcid_status` is a callback function which is invoked * when the new Destination Connection ID is activated, or the * activated Destination Connection ID is now deactivated. This * callback function is optional. - * - * Deprecated since v1.22.0. Use :member:`dcid_status2` instead. - * If both :member:`dcid_status` and :member:`dcid_status2` are set, - * the latter has the precedence. */ ngtcp2_connection_id_status dcid_status; /** @@ -3777,12 +3876,14 @@ typedef struct ngtcp2_callbacks { */ ngtcp2_lost_datagram lost_datagram; /** + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :member:`get_path_challenge_data2` instead. + * * :member:`get_path_challenge_data` is a callback function which is * invoked when the library needs new data sent along with * PATH_CHALLENGE frame. This callback must be specified. - * - * Deprecated since v1.22.0. Use :member:`get_path_challenge_data2` - * instead. */ ngtcp2_get_path_challenge_data get_path_challenge_data; /** @@ -3819,40 +3920,48 @@ typedef struct ngtcp2_callbacks { * is only used by client. */ ngtcp2_tls_early_data_rejected tls_early_data_rejected; - /* The following fields have been added since NGTCP2_CALLBACKS_V2. */ + /* The following fields have been added since + NGTCP2_CALLBACKS_V2. */ /** * :member:`begin_path_validation` is a callback function which is - * invoked when a path validation has started. This field is - * available since v1.14.0. + * invoked when a path validation has started. + * + * .. version-added:: 1.14.0 */ ngtcp2_begin_path_validation begin_path_validation; - /* The following fields have been added since NGTCP2_CALLBACKS_V3. */ + /* The following fields have been added since + NGTCP2_CALLBACKS_V3. */ /** * :member:`recv_stateless_reset2` is a callback function which is * invoked when Stateless Reset packet is received. This callback - * function is optional. This field is available since v1.22.0. + * function is optional. + * + * .. version-added:: 1.22.0 */ ngtcp2_recv_stateless_reset2 recv_stateless_reset2; /** * :member:`get_new_connection_id2` is a callback function which is * invoked when the library needs new connection ID. This callback - * function must be specified. This field is available since - * v1.22.0. + * function must be specified. + * + * .. version-added:: 1.22.0 */ ngtcp2_get_new_connection_id2 get_new_connection_id2; /** * :member:`dcid_status2` is a callback function which is invoked * when the new Destination Connection ID is activated, or the * activated Destination Connection ID is now deactivated. This - * callback function is optional. This field is available since - * v1.22.0. + * callback function is optional. + * + * .. version-added:: 1.22.0 */ ngtcp2_connection_id_status2 dcid_status2; /** * :member:`get_path_challenge_data2` is a callback function which * is invoked when the library needs new data sent along with - * PATH_CHALLENGE frame. This callback must be specified. This - * field is available since v1.22.0. + * PATH_CHALLENGE frame. This callback must be specified. + * + * .. version-added:: 1.22.0 */ ngtcp2_get_path_challenge_data2 get_path_challenge_data2; } ngtcp2_callbacks; @@ -4046,7 +4155,7 @@ NGTCP2_EXTERN void ngtcp2_conn_del(ngtcp2_conn *conn); * `ngtcp2_conn_write_connection_close` makes a connection enter * this state. * :macro:`NGTCP2_ERR_CRYPTO` - * An error happened in TLS stack. `ngtcp2_conn_get_tls_alert` + * An error happened in TLS stack. `ngtcp2_conn_get_tls_alert2` * returns TLS alert if set. * * If any other negative error is returned, call @@ -4080,7 +4189,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_pkt_versioned( * This function returns 0 if it succeeds. In general, this function * returns the same set of error codes from `ngtcp2_conn_read_pkt`. * - * This function has been available since v1.22.0. + * .. version-added:: 1.22.0 */ NGTCP2_EXTERN int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn, ngtcp2_tstamp ts); @@ -4098,11 +4207,24 @@ NGTCP2_EXTERN void ngtcp2_conn_tls_handshake_completed(ngtcp2_conn *conn); /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_handshake_completed2` instead. + * * `ngtcp2_conn_get_handshake_completed` returns nonzero if QUIC * handshake has completed. */ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_handshake_completed2` returns nonzero if QUIC + * handshake has completed. + */ +NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed2(const ngtcp2_conn *conn); + /** * @function * @@ -4353,38 +4475,70 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, * can set the error code (e.g., * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM`) using this function. * - * See also `ngtcp2_conn_get_tls_error`. + * See also `ngtcp2_conn_get_tls_error2`. */ NGTCP2_EXTERN void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr); /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_tls_error2` instead. + * * `ngtcp2_conn_get_tls_error` returns the value set by * `ngtcp2_conn_set_tls_error`. If no value is set, this function * returns 0. */ NGTCP2_EXTERN int ngtcp2_conn_get_tls_error(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_tls_error2` returns the value set by + * `ngtcp2_conn_set_tls_error`. If no value is set, this function + * returns 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN int ngtcp2_conn_get_tls_error2(const ngtcp2_conn *conn); + /** * @function * * `ngtcp2_conn_set_tls_alert` sets a TLS alert |alert| generated by a * TLS stack of a local endpoint to |conn|. * - * See also `ngtcp2_conn_get_tls_alert`. + * See also `ngtcp2_conn_get_tls_alert2`. */ NGTCP2_EXTERN void ngtcp2_conn_set_tls_alert(ngtcp2_conn *conn, uint8_t alert); /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_tls_alert2` instead. + * * `ngtcp2_conn_get_tls_alert` returns the value set by * `ngtcp2_conn_set_tls_alert`. If no value is set, this function * returns 0. */ NGTCP2_EXTERN uint8_t ngtcp2_conn_get_tls_alert(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_tls_alert2` returns the value set by + * `ngtcp2_conn_set_tls_alert`. If no value is set, this function + * returns 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint8_t ngtcp2_conn_get_tls_alert2(const ngtcp2_conn *conn); + /** * @function * @@ -4401,6 +4555,11 @@ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_expiry2` instead. + * * `ngtcp2_conn_get_expiry` returns the next expiry time. It returns * ``UINT64_MAX`` if there is no next expiry. * @@ -4408,6 +4567,18 @@ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, */ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_expiry2` returns the next expiry time. It returns + * ``UINT64_MAX`` if there is no next expiry. + * + * Call `ngtcp2_conn_handle_expiry` when the expiry time has passed. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry2(const ngtcp2_conn *conn); + /** * @function * @@ -4424,7 +4595,7 @@ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn); * `ngtcp2_conn_read_pkt` and `ngtcp2_conn_handle_expiry` before * calling `ngtcp2_conn_writev_stream`. After calling * `ngtcp2_conn_writev_stream`, new expiry is set. The application - * should call `ngtcp2_conn_get_expiry` to get a new deadline and set + * should call `ngtcp2_conn_get_expiry2` to get a new deadline and set * the timer. */ NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, @@ -4433,10 +4604,24 @@ NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_pto2` instead. + * * `ngtcp2_conn_get_pto` returns Probe Timeout (PTO). */ NGTCP2_EXTERN ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_pto2` returns Probe Timeout (PTO). + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN ngtcp2_duration ngtcp2_conn_get_pto2(const ngtcp2_conn *conn); + /** * @function * @@ -4464,6 +4649,11 @@ NGTCP2_EXTERN int ngtcp2_conn_decode_and_set_remote_transport_params( /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_remote_transport_params2` instead. + * * `ngtcp2_conn_get_remote_transport_params` returns a pointer to the * remote QUIC transport parameters. If no remote transport * parameters are set, it returns NULL. @@ -4474,6 +4664,23 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_remote_transport_params2` returns a pointer to the + * remote QUIC transport parameters. If no remote transport + * parameters are set, it returns NULL. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_transport_params * +ngtcp2_conn_get_remote_transport_params2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_encode_0rtt_transport_params2` instead. + * * `ngtcp2_conn_encode_0rtt_transport_params` encodes the QUIC * transport parameters that are used for 0-RTT data in the buffer * pointed by |dest| of length |destlen|. It includes at least the @@ -4511,6 +4718,48 @@ ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params(ngtcp2_conn *conn, uint8_t *dest, size_t destlen); +/** + * @function + * + * `ngtcp2_conn_encode_0rtt_transport_params2` encodes the QUIC + * transport parameters that are used for 0-RTT data in the buffer + * pointed by |dest| of length |destlen|. It includes at least the + * following fields: + * + * - :member:`ngtcp2_transport_params.initial_max_streams_bidi` + * - :member:`ngtcp2_transport_params.initial_max_streams_uni` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_bidi_local` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_bidi_remote` + * - :member:`ngtcp2_transport_params.initial_max_stream_data_uni` + * - :member:`ngtcp2_transport_params.initial_max_data` + * - :member:`ngtcp2_transport_params.active_connection_id_limit` + * - :member:`ngtcp2_transport_params.max_datagram_frame_size` + * + * If |conn| is initialized as server, the following additional fields + * are also included: + * + * - :member:`ngtcp2_transport_params.max_idle_timeout` + * - :member:`ngtcp2_transport_params.max_udp_payload_size` + * - :member:`ngtcp2_transport_params.disable_active_migration` + * + * If |conn| is initialized as client, these parameters are + * synthesized from the remote transport parameters received from + * server. Otherwise, they are the local transport parameters that + * are set by the local endpoint. + * + * This function returns the number of bytes written, or one of the + * following negative error codes: + * + * :macro:`NGTCP2_ERR_NOBUF` + * Buffer is too small. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN +ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params2(const ngtcp2_conn *conn, + uint8_t *dest, + size_t destlen); + /** * @function * @@ -4570,6 +4819,11 @@ NGTCP2_EXTERN int ngtcp2_conn_set_local_transport_params_versioned( /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_local_transport_params2` instead. + * * `ngtcp2_conn_get_local_transport_params` returns a pointer to the * local QUIC transport parameters. */ @@ -4579,6 +4833,22 @@ ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_local_transport_params2` returns a pointer to the + * local QUIC transport parameters. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_transport_params * +ngtcp2_conn_get_local_transport_params2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_encode_local_transport_params2` instead. + * * `ngtcp2_conn_encode_local_transport_params` encodes the local QUIC * transport parameters in |dest| of length |destlen|. * @@ -4591,6 +4861,23 @@ ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn); NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_encode_local_transport_params( ngtcp2_conn *conn, uint8_t *dest, size_t destlen); +/** + * @function + * + * `ngtcp2_conn_encode_local_transport_params2` encodes the local QUIC + * transport parameters in |dest| of length |destlen|. + * + * This function returns the number of bytes written, or one of the + * following negative error codes: + * + * :macro:`NGTCP2_ERR_NOBUF` + * Buffer is too small. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_encode_local_transport_params2( + const ngtcp2_conn *conn, uint8_t *dest, size_t destlen); + /** * @function * @@ -5095,6 +5382,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_in_closing_period2` instead. + * * `ngtcp2_conn_in_closing_period` returns nonzero if |conn| is in the * closing period. */ @@ -5103,11 +5395,36 @@ NGTCP2_EXTERN int ngtcp2_conn_in_closing_period(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_in_closing_period2` returns nonzero if |conn| is in + * the closing period. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN int ngtcp2_conn_in_closing_period2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_in_draining_period2` instead. + * * `ngtcp2_conn_in_draining_period` returns nonzero if |conn| is in * the draining period. */ NGTCP2_EXTERN int ngtcp2_conn_in_draining_period(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_in_draining_period2` returns nonzero if |conn| is in + * the draining period. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN int ngtcp2_conn_in_draining_period2(const ngtcp2_conn *conn); + /** * @function * @@ -5174,6 +5491,11 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_dcid2` instead. + * * `ngtcp2_conn_get_dcid` returns the non-NULL pointer to the current * Destination Connection ID. If no Destination Connection ID is * present, the return value is not ``NULL``, and its :member:`datalen @@ -5184,6 +5506,23 @@ NGTCP2_EXTERN const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_dcid2` returns the non-NULL pointer to the current + * Destination Connection ID. If no Destination Connection ID is + * present, the return value is not ``NULL``, and its :member:`datalen + * ` field is 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_cid *ngtcp2_conn_get_dcid2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_client_initial_dcid2` instead. + * * `ngtcp2_conn_get_client_initial_dcid` returns the non-NULL pointer * to the Destination Connection ID that client sent in its Initial * packet. If the Destination Connection ID is not present, the @@ -5196,7 +5535,26 @@ ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_scid` writes the all Source Connection IDs which a + * `ngtcp2_conn_get_client_initial_dcid2` returns the non-NULL pointer + * to the Destination Connection ID that client sent in its Initial + * packet. If the Destination Connection ID is not present, the + * return value is not ``NULL``, and its :member:`datalen + * ` field is 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_cid * +ngtcp2_conn_get_client_initial_dcid2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_scid2` instead. + * + * `ngtcp2_conn_get_scid` writes all Source Connection IDs which a * local endpoint has provided to a remote endpoint, and are not * retired in |dest|. If |dest| is NULL, this function does not write * anything, and returns the number of Source Connection IDs that @@ -5208,15 +5566,35 @@ ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn); NGTCP2_EXTERN size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest); /** - * @struct + * @function * - * :type:`ngtcp2_cid_token` is the convenient struct to store - * Connection ID, its associated path, and stateless reset token. + * `ngtcp2_conn_get_scid2` writes all Source Connection IDs which a + * local endpoint has provided to a remote endpoint, and are not + * retired in |dest|. If |dest| is NULL, this function does not write + * anything, and returns the number of Source Connection IDs that + * would otherwise be written to the provided buffer. The buffer + * pointed by |dest| must have sizeof(:type:`ngtcp2_cid`) * n bytes + * available, where n is the return value of `ngtcp2_conn_get_scid2` + * with |dest| == NULL. * - * Deprecated since v1.22.0. Use :type:`ngtcp2_cid_token2` instead. + * .. version-added:: 1.23.0 */ -typedef struct ngtcp2_cid_token { - /** +NGTCP2_EXTERN size_t ngtcp2_conn_get_scid2(const ngtcp2_conn *conn, + ngtcp2_cid *dest); + +/** + * @struct + * + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use :type:`ngtcp2_cid_token2` instead. + * + * :type:`ngtcp2_cid_token` is the convenient struct to store + * Connection ID, its associated path, and stateless reset token. + */ +typedef struct ngtcp2_cid_token { + /** * :member:`seq` is the sequence number of this Connection ID. */ uint64_t seq; @@ -5244,7 +5622,12 @@ typedef struct ngtcp2_cid_token { /** * @function * - * `ngtcp2_conn_get_active_dcid` writes the all active Destination + * .. warning:: + * + * .. version-deprecated:: 1.22.0 + * Use `ngtcp2_conn_get_active_dcid3` instead. + * + * `ngtcp2_conn_get_active_dcid` writes all active Destination * Connection IDs and their tokens to |dest|. Before handshake * completes, this function returns 0. If |dest| is NULL, this * function does not write anything, and returns the number of @@ -5253,9 +5636,6 @@ typedef struct ngtcp2_cid_token { * sizeof(:type:`ngtcp2_cid_token`) * n bytes available, where n is * the return value of `ngtcp2_conn_get_active_dcid` with |dest| == * NULL. - * - * Deprecated since v1.22.0. Use `ngtcp2_conn_get_active_dcid2` - * instead. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest); @@ -5266,7 +5646,7 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, * :type:`ngtcp2_cid_token2` is the convenient struct to store * Connection ID, its associated path, and stateless reset token. * - * This type has been available since v1.22.0. + * .. version-added:: 1.22.0 */ typedef struct ngtcp2_cid_token2 { /** @@ -5297,7 +5677,12 @@ typedef struct ngtcp2_cid_token2 { /** * @function * - * `ngtcp2_conn_get_active_dcid2` writes the all active Destination + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_active_dcid3` instead. + * + * `ngtcp2_conn_get_active_dcid2` writes all active Destination * Connection IDs and their tokens to |dest|. Before handshake * completes, this function returns 0. If |dest| is NULL, this * function does not write anything, and returns the number of @@ -5307,7 +5692,7 @@ typedef struct ngtcp2_cid_token2 { * the return value of `ngtcp2_conn_get_active_dcid2` with |dest| == * NULL. * - * This function has been available since v1.22.0. + * .. version-added:: 1.22.0 */ NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn, ngtcp2_cid_token2 *dest); @@ -5315,6 +5700,29 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn, /** * @function * + * `ngtcp2_conn_get_active_dcid3` writes all active Destination + * Connection IDs and their tokens to |dest|. Before handshake + * completes, this function returns 0. If |dest| is NULL, this + * function does not write anything, and returns the number of + * Destination Connection IDs that would otherwise be written to the + * provided buffer. The buffer pointed by |dest| must have + * sizeof(:type:`ngtcp2_cid_token2`) * n bytes available, where n is + * the return value of `ngtcp2_conn_get_active_dcid3` with |dest| == + * NULL. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid3(const ngtcp2_conn *conn, + ngtcp2_cid_token2 *dest); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_client_chosen_version2` instead. + * * `ngtcp2_conn_get_client_chosen_version` returns the client chosen * version. */ @@ -5323,6 +5731,22 @@ NGTCP2_EXTERN uint32_t ngtcp2_conn_get_client_chosen_version(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_client_chosen_version2` returns the client chosen + * version. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint32_t +ngtcp2_conn_get_client_chosen_version2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_negotiated_version2` instead. + * * `ngtcp2_conn_get_negotiated_version` returns the negotiated * version. * @@ -5330,6 +5754,19 @@ NGTCP2_EXTERN uint32_t ngtcp2_conn_get_client_chosen_version(ngtcp2_conn *conn); */ NGTCP2_EXTERN uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_negotiated_version2` returns the negotiated + * version. + * + * Until the version is negotiated, this function returns 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint32_t +ngtcp2_conn_get_negotiated_version2(const ngtcp2_conn *conn); + /** * @function * @@ -5358,6 +5795,11 @@ NGTCP2_EXTERN int ngtcp2_conn_tls_early_data_rejected(ngtcp2_conn *conn); /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_tls_early_data_rejected2`. + * * `ngtcp2_conn_get_tls_early_data_rejected` returns nonzero if * `ngtcp2_conn_tls_early_data_rejected` has been called. */ @@ -5366,6 +5808,22 @@ NGTCP2_EXTERN int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_tls_early_data_rejected2` returns nonzero if + * `ngtcp2_conn_tls_early_data_rejected` has been called. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN int +ngtcp2_conn_get_tls_early_data_rejected2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_conn_info2` instead. + * * `ngtcp2_conn_get_conn_info` assigns connection statistics data to * |*cinfo|. */ @@ -5373,6 +5831,17 @@ NGTCP2_EXTERN void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn, int conn_info_version, ngtcp2_conn_info *cinfo); +/** + * @function + * + * `ngtcp2_conn_get_conn_info2` assigns connection statistics data to + * |*cinfo|. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN void ngtcp2_conn_get_conn_info2_versioned( + const ngtcp2_conn *conn, int conn_info_version, ngtcp2_conn_info *cinfo); + /** * @function * @@ -5430,6 +5899,11 @@ NGTCP2_EXTERN void ngtcp2_conn_set_path_user_data(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_path2` instead. + * * `ngtcp2_conn_get_path` returns the current path. */ NGTCP2_EXTERN const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn); @@ -5437,6 +5911,20 @@ NGTCP2_EXTERN const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_path2` returns the current path. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_path *ngtcp2_conn_get_path2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_max_tx_udp_payload_size2` instead. + * * `ngtcp2_conn_get_max_tx_udp_payload_size` returns the maximum UDP * payload size that this local endpoint would send. This is the * value of :member:`ngtcp2_settings.max_tx_udp_payload_size` that is @@ -5447,6 +5935,24 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_max_tx_udp_payload_size2` returns the maximum UDP + * payload size that this local endpoint would send. This is the + * value of :member:`ngtcp2_settings.max_tx_udp_payload_size` that is + * passed to `ngtcp2_conn_client_new` or `ngtcp2_conn_server_new`. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN size_t +ngtcp2_conn_get_max_tx_udp_payload_size2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_path_max_tx_udp_payload_size2` instead. + * * `ngtcp2_conn_get_path_max_tx_udp_payload_size` returns the maximum * UDP payload size for the current path. If * :member:`ngtcp2_settings.no_tx_udp_payload_size_shaping` is set to @@ -5457,6 +5963,21 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn); NGTCP2_EXTERN size_t ngtcp2_conn_get_path_max_tx_udp_payload_size(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_path_max_tx_udp_payload_size2` returns the maximum + * UDP payload size for the current path. If + * :member:`ngtcp2_settings.no_tx_udp_payload_size_shaping` is set to + * nonzero, this function is equivalent to + * `ngtcp2_conn_get_max_tx_udp_payload_size2`. Otherwise, it returns + * the maximum UDP payload size that is probed for the current path. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN size_t +ngtcp2_conn_get_path_max_tx_udp_payload_size2(const ngtcp2_conn *conn); + /** * @function * @@ -5513,6 +6034,11 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_max_data_left2` instead. + * * `ngtcp2_conn_get_max_data_left` returns the number of bytes that * this local endpoint can send in this connection without violating * connection-level flow control. @@ -5522,6 +6048,22 @@ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_max_data_left2` returns the number of bytes that + * this local endpoint can send in this connection without violating + * connection-level flow control. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_data_left2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_max_stream_data_left2` instead. + * * `ngtcp2_conn_get_max_stream_data_left` returns the number of bytes * that this local endpoint can send to a stream identified by * |stream_id| without violating stream-level flow control. If no @@ -5533,6 +6075,24 @@ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_stream_data_left(ngtcp2_conn *conn, /** * @function * + * `ngtcp2_conn_get_max_stream_data_left2` returns the number of bytes + * that this local endpoint can send to a stream identified by + * |stream_id| without violating stream-level flow control. If no + * such stream is found, this function returns 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_stream_data_left2( + const ngtcp2_conn *conn, int64_t stream_id); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_streams_bidi_left2` instead. + * * `ngtcp2_conn_get_streams_bidi_left` returns the number of * bidirectional streams which the local endpoint can open without * violating stream concurrency limit. @@ -5542,6 +6102,23 @@ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_streams_bidi_left(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_streams_bidi_left2` returns the number of + * bidirectional streams which the local endpoint can open without + * violating stream concurrency limit. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint64_t +ngtcp2_conn_get_streams_bidi_left2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_streams_uni_left2` instead. + * * `ngtcp2_conn_get_streams_uni_left` returns the number of * unidirectional streams which the local endpoint can open without * violating stream concurrency limit. @@ -5551,12 +6128,40 @@ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_streams_uni_left(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_streams_uni_left2` returns the number of + * unidirectional streams which the local endpoint can open without + * violating stream concurrency limit. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint64_t +ngtcp2_conn_get_streams_uni_left2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_cwnd_left2` instead. + * * `ngtcp2_conn_get_cwnd_left` returns the cwnd minus the number of * bytes in flight on the current path. If the former is smaller than * the latter, this function returns 0. */ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_cwnd_left(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_cwnd_left2` returns the cwnd minus the number of + * bytes in flight on the current path. If the former is smaller than + * the latter, this function returns 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN uint64_t ngtcp2_conn_get_cwnd_left2(const ngtcp2_conn *conn); + /** * @function * @@ -5572,12 +6177,28 @@ ngtcp2_conn_set_initial_crypto_ctx(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_initial_crypto_ctx2` instead. + * * `ngtcp2_conn_get_initial_crypto_ctx` returns * :type:`ngtcp2_crypto_ctx` object for Initial packet encryption. */ NGTCP2_EXTERN const ngtcp2_crypto_ctx * ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_initial_crypto_ctx2` returns + * :type:`ngtcp2_crypto_ctx` object for Initial packet encryption. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_crypto_ctx * +ngtcp2_conn_get_initial_crypto_ctx2(const ngtcp2_conn *conn); + /** * @function * @@ -5592,12 +6213,28 @@ NGTCP2_EXTERN void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_crypto_ctx2` instead. + * * `ngtcp2_conn_get_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` * object for Handshake/1-RTT packet encryption. */ NGTCP2_EXTERN const ngtcp2_crypto_ctx * ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_crypto_ctx2` returns :type:`ngtcp2_crypto_ctx` + * object for Handshake/1-RTT packet encryption. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_crypto_ctx * +ngtcp2_conn_get_crypto_ctx2(const ngtcp2_conn *conn); + /** * @function * @@ -5613,6 +6250,11 @@ ngtcp2_conn_set_0rtt_crypto_ctx(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_0rtt_crypto_ctx2` instead. + * * `ngtcp2_conn_get_0rtt_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` * object for 0-RTT packet encryption. */ @@ -5622,11 +6264,37 @@ ngtcp2_conn_get_0rtt_crypto_ctx(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_0rtt_crypto_ctx2` returns + * :type:`ngtcp2_crypto_ctx` object for 0-RTT packet encryption. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_crypto_ctx * +ngtcp2_conn_get_0rtt_crypto_ctx2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_tls_native_handle2` instead. + * * `ngtcp2_conn_get_tls_native_handle` returns TLS native handle set * by `ngtcp2_conn_set_tls_native_handle`. */ NGTCP2_EXTERN void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_tls_native_handle2` returns TLS native handle set + * by `ngtcp2_conn_set_tls_native_handle`. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN void *ngtcp2_conn_get_tls_native_handle2(const ngtcp2_conn *conn); + /** * @function * @@ -5903,6 +6571,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_ccerr2` instead. + * * `ngtcp2_conn_get_ccerr` returns the received connection close * error. If no connection error is received, it returns * :type:`ngtcp2_ccerr` that is initialized by `ngtcp2_ccerr_default`. @@ -5912,6 +6585,23 @@ NGTCP2_EXTERN const ngtcp2_ccerr *ngtcp2_conn_get_ccerr(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_ccerr2` returns the received connection close + * error. If no connection error is received, it returns + * :type:`ngtcp2_ccerr` that is initialized by `ngtcp2_ccerr_default`. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN const ngtcp2_ccerr * +ngtcp2_conn_get_ccerr2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_is_local_stream2` instead. + * * `ngtcp2_conn_is_local_stream` returns nonzero if |stream_id| * denotes a locally initiated stream. */ @@ -5921,6 +6611,22 @@ NGTCP2_EXTERN int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, /** * @function * + * `ngtcp2_conn_is_local_stream2` returns nonzero if |stream_id| + * denotes a locally initiated stream. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN int ngtcp2_conn_is_local_stream2(const ngtcp2_conn *conn, + int64_t stream_id); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_is_server2` instead. + * * `ngtcp2_conn_is_server` returns nonzero if |conn| is initialized as * server. */ @@ -5929,11 +6635,37 @@ NGTCP2_EXTERN int ngtcp2_conn_is_server(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_is_server2` returns nonzero if |conn| is initialized + * as server. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN int ngtcp2_conn_is_server2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_after_retry2` instead. + * * `ngtcp2_conn_after_retry` returns nonzero if |conn| as a client has * received Retry packet from server, and successfully validated it. */ NGTCP2_EXTERN int ngtcp2_conn_after_retry(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_after_retry2` returns nonzero if |conn| as a client + * has received Retry packet from server, and successfully validated + * it. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN int ngtcp2_conn_after_retry2(const ngtcp2_conn *conn); + /** * @function * @@ -5953,6 +6685,11 @@ NGTCP2_EXTERN int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_stream_user_data2` instead. + * * `ngtcp2_conn_get_stream_user_data` returns stream_user_data * associated to the stream identified by |stream_id|. If the stream * is not found, or no stream data is associated to the stream, this @@ -5965,11 +6702,31 @@ NGTCP2_EXTERN int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, * - `ngtcp2_conn_open_uni_stream` * - `ngtcp2_conn_set_stream_user_data` * - * This function has been available since v1.17.0. + * .. version-added:: 1.17.0 */ NGTCP2_EXTERN void *ngtcp2_conn_get_stream_user_data(ngtcp2_conn *conn, int64_t stream_id); +/** + * @function + * + * `ngtcp2_conn_get_stream_user_data2` returns stream_user_data + * associated to the stream identified by |stream_id|. If the stream + * is not found, or no stream data is associated to the stream, this + * function returns NULL. + * + * The stream_user_data can be associated to the stream by one of the + * following functions: + * + * - `ngtcp2_conn_open_bidi_stream` + * - `ngtcp2_conn_open_uni_stream` + * - `ngtcp2_conn_set_stream_user_data` + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN void *ngtcp2_conn_get_stream_user_data2(const ngtcp2_conn *conn, + int64_t stream_id); + /** * @function * @@ -5986,6 +6743,11 @@ NGTCP2_EXTERN void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, /** * @function * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_send_quantum2` instead. + * * `ngtcp2_conn_get_send_quantum` returns the maximum number of bytes * that can be sent in one go without packet spacing. */ @@ -5994,6 +6756,21 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn); /** * @function * + * `ngtcp2_conn_get_send_quantum2` returns the maximum number of bytes + * that can be sent in one go without packet spacing. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN size_t ngtcp2_conn_get_send_quantum2(const ngtcp2_conn *conn); + +/** + * @function + * + * .. warning:: + * + * .. version-deprecated:: 1.23.0 + * Use `ngtcp2_conn_get_stream_loss_count2` instead. + * * `ngtcp2_conn_get_stream_loss_count` returns the number of packets * that contain STREAM frame for a stream identified by |stream_id| * and are declared to be lost. The number may include the spurious @@ -6003,6 +6780,20 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn); NGTCP2_EXTERN size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, int64_t stream_id); +/** + * @function + * + * `ngtcp2_conn_get_stream_loss_count2` returns the number of packets + * that contain STREAM frame for a stream identified by |stream_id| + * and are declared to be lost. The number may include the spurious + * losses. If no stream identified by |stream_id| is found, this + * function returns 0. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN size_t ngtcp2_conn_get_stream_loss_count2(const ngtcp2_conn *conn, + int64_t stream_id); + /** * @functypedef * @@ -6031,7 +6822,7 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_PADDING` if * `ngtcp2_conn_writev_datagram` is used) is recommended. * - * This callback function has been available since v1.15.0. + * .. version-added:: 1.15.0 */ typedef ngtcp2_ssize (*ngtcp2_write_pkt)(ngtcp2_conn *conn, ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, @@ -6046,14 +6837,15 @@ typedef ngtcp2_ssize (*ngtcp2_write_pkt)(ngtcp2_conn *conn, ngtcp2_path *path, * sent at once in GSO. This function returns the number of bytes * written to the buffer pointed by |buf| of length |buflen|. * |buflen| must be at least - * `ngtcp2_conn_get_path_max_tx_udp_payload_size(conn) - * ` bytes long. It is + * `ngtcp2_conn_get_path_max_tx_udp_payload_size2(conn) + * ` bytes long. It is * recommended to pass the buffer at least - * `ngtcp2_conn_get_max_tx_udp_payload_size(conn) - * ` bytes in order to send a - * PMTUD packet. This function only writes multiple packets if the - * first packet is `ngtcp2_conn_get_path_max_tx_udp_payload_size(conn) - * ` bytes long. The + * `ngtcp2_conn_get_max_tx_udp_payload_size2(conn) + * ` bytes in order to send + * a PMTUD packet. This function only writes multiple packets if the + * first packet is + * `ngtcp2_conn_get_path_max_tx_udp_payload_size2(conn) + * ` bytes long. The * application can adjust the length of the buffer to limit the number * of packets to aggregate (or use `ngtcp2_conn_write_aggregate_pkt2` * to control the number of packets to write directly). If this @@ -6068,15 +6860,15 @@ typedef ngtcp2_ssize (*ngtcp2_write_pkt)(ngtcp2_conn *conn, ngtcp2_path *path, * * This function is equivalent to call * `ngtcp2_conn_write_aggregate_pkt2` with |buflen| = min(|buflen|, - * `ngtcp2_conn_get_send_quantum(conn) - * `) and |num_pkts| = 0 followed by + * `ngtcp2_conn_get_send_quantum2(conn) + * `) and |num_pkts| = 0 followed by * `ngtcp2_conn_update_pkt_tx_time(conn) * `. * * This function returns the number of bytes written to the buffer, or * a negative error code returned by |write_pkt|. * - * This function has been available since v1.15.0. + * .. version-added:: 1.15.0 */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -6099,7 +6891,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned( * an application. It can experiment different GSO buffer size * strategy and number of GSO writes per event loop. * - * This function has been available since v1.17.0. + * .. version-added:: 1.17.0 */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -6112,7 +6904,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned( * `ngtcp2_conn_get_timestamp` returns the latest timestamp that is * known to |conn|. * - * This function has been available since v1.16.0. + * .. version-added:: 1.16.0 */ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_timestamp(const ngtcp2_conn *conn); @@ -6358,6 +7150,25 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, const uint32_t *offered_versions, size_t offered_versionslen); +/** + * @function + * + * `ngtcp2_secure_clear` writes |len| bytes of zeros into the buffer + * pointed by |data|. It does that by avoiding compiler + * optimizations. If the following functions are available, one of + * them is used: + * + * - ``SecureZeroMemory`` + * - ``explicit_bzero`` + * - ``memset_s`` + * + * Otherwise, it uses volatile function pointer to ``memset`` to fill + * zeros. + * + * .. version-added:: 1.23.0 + */ +NGTCP2_EXTERN void ngtcp2_secure_clear(void *data, size_t len); + /* * Versioned function wrappers */ @@ -6502,6 +7313,15 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, #define ngtcp2_conn_get_conn_info(CONN, CINFO) \ ngtcp2_conn_get_conn_info_versioned((CONN), NGTCP2_CONN_INFO_VERSION, (CINFO)) +/* + * `ngtcp2_conn_get_conn_info2` is a wrapper around + * `ngtcp2_conn_get_conn_info2_versioned` to set the correct struct + * version. + */ +#define ngtcp2_conn_get_conn_info2(CONN, CINFO) \ + ngtcp2_conn_get_conn_info2_versioned((CONN), NGTCP2_CONN_INFO_VERSION, \ + (CINFO)) + /* * `ngtcp2_conn_write_aggregate_pkt` is a wrapper around * `ngtcp2_conn_write_aggregate_pkt_versioned` to set the correct diff --git a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h index a1f09e7148bd84..7a47cdaba0bdb9 100644 --- a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h +++ b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h @@ -36,7 +36,7 @@ * * Version number of the ngtcp2 library release. */ -#define NGTCP2_VERSION "1.22.1" +#define NGTCP2_VERSION "1.23.0" /** * @macro @@ -46,6 +46,6 @@ * number, 8 bits for minor and 8 bits for patch. Version 1.2.3 * becomes 0x010203. */ -#define NGTCP2_VERSION_NUM 0x011601 +#define NGTCP2_VERSION_NUM 0x011700 #endif /* !defined(NGTCP2_VERSION_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c index 4a9ac5cf0aa7c9..2f194ab13105a3 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c @@ -410,7 +410,7 @@ int ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr, ngtcp2_ack *ack, ack->ack_delay = 0; } - num_acks = ngtcp2_min_size(num_acks, NGTCP2_MAX_ACK_RANGES); + num_acks = ngtcp2_min(num_acks, NGTCP2_MAX_ACK_RANGES); for (; ack->rangecnt < num_acks; ngtcp2_ksl_it_next(&it)) { rpkt = ngtcp2_ksl_it_get(&it); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c index fff7a9ef65bea1..ea72eb8314325b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c @@ -84,7 +84,7 @@ int ngtcp2_balloc_get(ngtcp2_balloc *balloc, void **pbuf, size_t n) { assert(((uintptr_t)balloc->buf.last & 0xFU) == 0); *pbuf = balloc->buf.last; - balloc->buf.last += (n + 0xFU) & ~(uintptr_t)0xFU; + balloc->buf.last += (n + 0xFU) & ~(size_t)0xFU; return 0; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c index 3db6a9f2bff088..cdeb29bb506523 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c @@ -62,6 +62,8 @@ #define NGTCP2_BBR_PACING_MARGIN_PERCENT 1 +#define NGTCP2_BBR_MAX_DRAIN_ROUNDS 3 + static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp initial_ts); @@ -350,6 +352,7 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, bbr->max_inflight = 0; bbr->bdp = 0; + bbr->drain_start_round = 0; bbr->undo_state = 0; bbr->undo_bw_shortterm = 0; @@ -403,8 +406,7 @@ static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr, bbr->full_bw_reached = 1; ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, - "bbr reached full bandwidth, full_bw=%" PRIu64, - bbr->full_bw); + "bbr reached full bandwidth, full_bw=", bbr->full_bw); } static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) { @@ -416,18 +418,18 @@ static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) { } bbr->full_bw_reached = 1; - bbr->inflight_longterm = ngtcp2_max_uint64( - bbr_bdp_multiple(bbr, bbr->cwnd_gain_h), bbr->inflight_latest); + bbr->inflight_longterm = + ngtcp2_max(bbr_bdp_multiple(bbr, bbr->cwnd_gain_h), bbr->inflight_latest); } static void bbr_init_pacing_rate(const ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { - cstat->pacing_interval_m = ngtcp2_max_uint64( - ((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS - : cstat->smoothed_rtt) - << 10) * - 100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd, - 1); + cstat->pacing_interval_m = + ngtcp2_max(((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS + : cstat->smoothed_rtt) + << 10) * + 100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd, + 1); } static void bbr_set_pacing_rate_with_gain(const ngtcp2_cc_bbr *bbr, @@ -441,7 +443,7 @@ static void bbr_set_pacing_rate_with_gain(const ngtcp2_cc_bbr *bbr, interval_m = (NGTCP2_SECONDS << 10) * 100 * 100 / pacing_gain_h / bbr->bw / (100 - NGTCP2_BBR_PACING_MARGIN_PERCENT); - interval_m = ngtcp2_max_uint64(interval_m, 1); + interval_m = ngtcp2_max(interval_m, 1); if (bbr->full_bw_reached || interval_m < cstat->pacing_interval_m) { cstat->pacing_interval_m = interval_m; @@ -508,9 +510,9 @@ static void bbr_update_control_parameters(ngtcp2_cc_bbr *bbr, static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat) { bbr->loss_round_start = 0; - bbr->bw_latest = ngtcp2_max_uint64(bbr->bw_latest, cstat->delivery_rate_sec); + bbr->bw_latest = ngtcp2_max(bbr->bw_latest, cstat->delivery_rate_sec); bbr->inflight_latest = - ngtcp2_max_uint64(bbr->inflight_latest, bbr->rst->rs.delivered); + ngtcp2_max(bbr->inflight_latest, bbr->rst->rs.delivered); if (bbr->rst->rs.prior_delivered >= bbr->loss_round_delivered) { bbr->loss_round_delivered = bbr->rst->delivered; @@ -570,16 +572,16 @@ static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, } static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr) { - bbr->bw_shortterm = ngtcp2_max_uint64( - bbr->bw_latest, - bbr->bw_shortterm * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); - bbr->inflight_shortterm = ngtcp2_max_uint64( + bbr->bw_shortterm = + ngtcp2_max(bbr->bw_latest, bbr->bw_shortterm * NGTCP2_BBR_BETA_NUMER / + NGTCP2_BBR_BETA_DENOM); + bbr->inflight_shortterm = ngtcp2_max( bbr->inflight_latest, bbr->inflight_shortterm * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); } static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr) { - bbr->bw = ngtcp2_min_uint64(bbr->max_bw, bbr->bw_shortterm); + bbr->bw = ngtcp2_min(bbr->max_bw, bbr->bw_shortterm); } static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat, @@ -661,7 +663,7 @@ static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr, extra = 0; } else { extra = bbr->extra_acked_delivered - expected_delivered; - extra = ngtcp2_min_uint64(extra, cstat->cwnd); + extra = ngtcp2_min(extra, cstat->cwnd); } if (bbr->full_bw_reached) { @@ -682,13 +684,16 @@ static void bbr_enter_drain(ngtcp2_cc_bbr *bbr) { bbr->state = NGTCP2_BBR_STATE_DRAIN; bbr->pacing_gain_h = NGTCP2_BBR_DRAIN_PACING_GAIN_H; bbr->cwnd_gain_h = NGTCP2_BBR_DEFAULT_CWND_GAIN_H; + bbr->drain_start_round = bbr->round_count; } static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { if (bbr->state == NGTCP2_BBR_STATE_DRAIN && - cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) { + (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100) || + bbr->round_count > + bbr->drain_start_round + NGTCP2_BBR_MAX_DRAIN_ROUNDS)) { bbr_enter_probe_bw(bbr, ts); } } @@ -810,8 +815,8 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat) { - uint64_t inflight = ngtcp2_min_uint64(bbr_inflight_with_headroom(bbr, cstat), - bbr_inflight(bbr, cstat, 100)); + uint64_t inflight = ngtcp2_min(bbr_inflight_with_headroom(bbr, cstat), + bbr_inflight(bbr, cstat, 100)); return cstat->bytes_in_flight <= inflight; } @@ -842,14 +847,13 @@ static uint64_t bbr_inflight_with_headroom(const ngtcp2_cc_bbr *bbr, return UINT64_MAX; } - headroom = - ngtcp2_max_uint64(cstat->max_tx_udp_payload_size, - bbr->inflight_longterm * NGTCP2_BBR_HEADROOM_NUMER / - NGTCP2_BBR_HEADROOM_DENOM); + headroom = ngtcp2_max((uint64_t)cstat->max_tx_udp_payload_size, + bbr->inflight_longterm * NGTCP2_BBR_HEADROOM_NUMER / + NGTCP2_BBR_HEADROOM_DENOM); mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); if (bbr->inflight_longterm > headroom) { - return ngtcp2_max_uint64(bbr->inflight_longterm - headroom, mpcwnd); + return ngtcp2_max(bbr->inflight_longterm - headroom, mpcwnd); } return mpcwnd; @@ -860,8 +864,8 @@ static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr, uint64_t growth_this_round = cstat->max_tx_udp_payload_size << bbr->bw_probe_up_rounds; - bbr->bw_probe_up_rounds = ngtcp2_min_size(bbr->bw_probe_up_rounds + 1, 30); - bbr->probe_up_cnt = ngtcp2_max_uint64(cstat->cwnd / growth_this_round, 1); + bbr->bw_probe_up_rounds = ngtcp2_min(bbr->bw_probe_up_rounds + 1, 30); + bbr->probe_up_cnt = ngtcp2_max(cstat->cwnd / growth_this_round, 1); } static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr, @@ -942,12 +946,12 @@ static int bbr_is_reno_coexistence_probe_time(const ngtcp2_cc_bbr *bbr, uint64_t reno_rounds = bbr_target_inflight(bbr, cstat) / cstat->max_tx_udp_payload_size; - return bbr->rounds_since_bw_probe >= ngtcp2_min_uint64(reno_rounds, 63); + return bbr->rounds_since_bw_probe >= ngtcp2_min(reno_rounds, 63); } static uint64_t bbr_target_inflight(const ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat) { - return ngtcp2_min_uint64(bbr->bdp, cstat->cwnd); + return ngtcp2_min(bbr->bdp, cstat->cwnd); } static int bbr_is_inflight_too_high(const ngtcp2_cc_bbr *bbr, @@ -964,7 +968,7 @@ static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr, bbr->bw_probe_samples = 0; if (!rs->is_app_limited) { - bbr->inflight_longterm = ngtcp2_max_uint64( + bbr->inflight_longterm = ngtcp2_max( rs->tx_in_flight, bbr_target_inflight(bbr, cstat) * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); } @@ -996,12 +1000,11 @@ static void bbr_handle_spurious_loss_detection(ngtcp2_cc_bbr *bbr, bbr_reset_full_bw(bbr); - bbr->bw_shortterm = - ngtcp2_max_uint64(bbr->bw_shortterm, bbr->undo_bw_shortterm); + bbr->bw_shortterm = ngtcp2_max(bbr->bw_shortterm, bbr->undo_bw_shortterm); bbr->inflight_shortterm = - ngtcp2_max_uint64(bbr->inflight_shortterm, bbr->undo_inflight_shortterm); + ngtcp2_max(bbr->inflight_shortterm, bbr->undo_inflight_shortterm); bbr->inflight_longterm = - ngtcp2_max_uint64(bbr->inflight_longterm, bbr->undo_inflight_longterm); + ngtcp2_max(bbr->inflight_longterm, bbr->undo_inflight_longterm); if (bbr->state != NGTCP2_BBR_STATE_PROBE_RTT && bbr->state != bbr->undo_state) { @@ -1087,7 +1090,7 @@ static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack, bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp; ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, - "bbr update min_rtt=%" PRIu64, bbr->min_rtt); + "bbr update min_rtt=", bbr->min_rtt); } } @@ -1160,7 +1163,7 @@ static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr, static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat) { bbr->rst->app_limited = - ngtcp2_max_uint64(bbr->rst->delivered + cstat->bytes_in_flight, 1); + ngtcp2_max(bbr->rst->delivered + cstat->bytes_in_flight, 1); } static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) { @@ -1196,7 +1199,7 @@ static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t gain_h) { return bbr->initial_cwnd; } - bbr->bdp = ngtcp2_max_uint64(bbr->bw * bbr->min_rtt / NGTCP2_SECONDS, 1); + bbr->bdp = ngtcp2_max(bbr->bw * bbr->min_rtt / NGTCP2_SECONDS, 1); return (uint64_t)(bbr->bdp * gain_h / 100); } @@ -1210,9 +1213,9 @@ static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr, uint64_t inflight) { bbr_update_offload_budget(bbr, cstat); - inflight = ngtcp2_max_uint64(inflight, bbr->offload_budget); + inflight = ngtcp2_max(inflight, bbr->offload_budget); inflight = - ngtcp2_max_uint64(inflight, min_pipe_cwnd(cstat->max_tx_udp_payload_size)); + ngtcp2_max(inflight, min_pipe_cwnd(cstat->max_tx_udp_payload_size)); if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) { inflight += 2 * cstat->max_tx_udp_payload_size; @@ -1251,12 +1254,12 @@ static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, const ngtcp2_conn_stat *cstat) { return; } - bbr->prior_cwnd = ngtcp2_max_uint64(bbr->prior_cwnd, cstat->cwnd); + bbr->prior_cwnd = ngtcp2_max(bbr->prior_cwnd, cstat->cwnd); } static void bbr_restore_cwnd(const ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { - cstat->cwnd = ngtcp2_max_uint64(cstat->cwnd, bbr->prior_cwnd); + cstat->cwnd = ngtcp2_max(cstat->cwnd, bbr->prior_cwnd); } static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, @@ -1265,14 +1268,13 @@ static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, bbr_bdp_multiple(bbr, NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H); uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); - return ngtcp2_max_uint64(probe_rtt_cwnd, mpcwnd); + return ngtcp2_max(probe_rtt_cwnd, mpcwnd); } static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) { - cstat->cwnd = - ngtcp2_min_uint64(cstat->cwnd, bbr_probe_rtt_cwnd(bbr, cstat)); + cstat->cwnd = ngtcp2_min(cstat->cwnd, bbr_probe_rtt_cwnd(bbr, cstat)); } } @@ -1284,14 +1286,14 @@ static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, if (bbr->full_bw_reached) { cstat->cwnd += ack->bytes_delivered; - cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, bbr->max_inflight); + cstat->cwnd = ngtcp2_min(cstat->cwnd, bbr->max_inflight); } else if (cstat->cwnd < bbr->max_inflight || bbr->rst->delivered < bbr->initial_cwnd) { cstat->cwnd += ack->bytes_delivered; } mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); - cstat->cwnd = ngtcp2_max_uint64(cstat->cwnd, mpcwnd); + cstat->cwnd = ngtcp2_max(cstat->cwnd, mpcwnd); bbr_bound_cwnd_for_probe_rtt(bbr, cstat); bbr_bound_cwnd_for_model(bbr, cstat); @@ -1310,10 +1312,10 @@ static void bbr_bound_cwnd_for_model(const ngtcp2_cc_bbr *bbr, cap = bbr_inflight_with_headroom(bbr, cstat); } - cap = ngtcp2_min_uint64(cap, bbr->inflight_shortterm); - cap = ngtcp2_max_uint64(cap, mpcwnd); + cap = ngtcp2_min(cap, bbr->inflight_shortterm); + cap = ngtcp2_max(cap, mpcwnd); - cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, cap); + cstat->cwnd = ngtcp2_min(cstat->cwnd, cap); } static void bbr_set_send_quantum(const ngtcp2_cc_bbr *bbr, @@ -1321,12 +1323,11 @@ static void bbr_set_send_quantum(const ngtcp2_cc_bbr *bbr, size_t send_quantum = 64 * 1024; (void)bbr; - send_quantum = - ngtcp2_min_size(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) / - cstat->pacing_interval_m)); + send_quantum = ngtcp2_min(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) / + cstat->pacing_interval_m)); cstat->send_quantum = - ngtcp2_max_size(send_quantum, 2 * cstat->max_tx_udp_payload_size); + ngtcp2_max(send_quantum, 2 * cstat->max_tx_udp_payload_size); } static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, @@ -1402,8 +1403,8 @@ static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc, bbr_save_cwnd(bbr, cstat); cstat->cwnd = cstat->bytes_in_flight + cstat->max_tx_udp_payload_size; - cstat->cwnd = ngtcp2_max_uint64( - cstat->cwnd, min_pipe_cwnd(cstat->max_tx_udp_payload_size)); + cstat->cwnd = + ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_tx_udp_payload_size)); } static void bbr_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h index 5177944b290781..81384e6d9f5cda 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h @@ -133,6 +133,7 @@ typedef struct ngtcp2_cc_bbr { uint64_t round_count_at_recovery; uint64_t max_inflight; uint64_t bdp; + uint64_t drain_start_round; int loss_round_start; int bw_probe_samples; int probe_rtt_expired; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c index 73dfde6904b93d..2d3c65dbf38581 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c @@ -36,9 +36,8 @@ #include "ngtcp2_unreachable.h" uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) { - uint64_t n = 2 * max_udp_payload_size; - n = ngtcp2_max_uint64(n, 14720); - return ngtcp2_min_uint64(10 * max_udp_payload_size, n); + size_t n = ngtcp2_max(2 * max_udp_payload_size, 14720); + return ngtcp2_min(10 * max_udp_payload_size, n); } /* 1.25 is the under-utilization avoidance factor described in @@ -48,9 +47,9 @@ uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) { static void init_pacing_rate(ngtcp2_conn_stat *cstat) { assert(cstat->cwnd); - cstat->pacing_interval_m = ngtcp2_max_uint64( - (NGTCP2_MILLISECONDS << 10) * 100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd, - 1); + cstat->pacing_interval_m = ngtcp2_max((NGTCP2_MILLISECONDS << 10) * 100 / + NGTCP2_CC_PACING_GAIN_H / cstat->cwnd, + 1); cstat->send_quantum = 10 * cstat->max_tx_udp_payload_size; } @@ -65,14 +64,13 @@ static void set_pacing_rate(ngtcp2_conn_stat *cstat) { << 10) * 100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd; - cstat->pacing_interval_m = ngtcp2_max_uint64(cstat->pacing_interval_m, 1); + cstat->pacing_interval_m = ngtcp2_max(cstat->pacing_interval_m, 1); - send_quantum = - ngtcp2_min_size(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) / - cstat->pacing_interval_m)); + send_quantum = ngtcp2_min(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) / + cstat->pacing_interval_m)); cstat->send_quantum = - ngtcp2_max_size(send_quantum, 10 * cstat->max_tx_udp_payload_size); + ngtcp2_max(send_quantum, 10 * cstat->max_tx_udp_payload_size); } ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num, @@ -134,9 +132,8 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, set_pacing_rate(cstat); - ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA, - "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64, - pkt->pkt_num, cstat->cwnd); + ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA, "pkn=", pkt->pkt_num, + " acked, slow start cwnd=", cstat->cwnd); return; } @@ -163,7 +160,7 @@ void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, cstat->congestion_recovery_start_ts = ts; cstat->cwnd >>= NGTCP2_LOSS_REDUCTION_FACTOR_BITS; min_cwnd = 2 * cstat->max_tx_udp_payload_size; - cstat->cwnd = ngtcp2_max_uint64(cstat->cwnd, min_cwnd); + cstat->cwnd = ngtcp2_max(cstat->cwnd, min_cwnd); cstat->ssthresh = cstat->cwnd; reno->pending_add = 0; @@ -171,8 +168,7 @@ void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, set_pacing_rate(cstat); ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA, - "reduce cwnd because of packet loss cwnd=%" PRIu64, - cstat->cwnd); + "reduce cwnd because of packet loss cwnd=", cstat->cwnd); } void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc, @@ -291,7 +287,7 @@ static uint64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic, time_delta_m = tx_m - cubic->current.k_m; } - time_delta_m = ngtcp2_min_uint64(time_delta_m, 3600 << 10); + time_delta_m = ngtcp2_min(time_delta_m, 3600 << 10); delta = ((((time_delta_m * time_delta_m) >> 10) * time_delta_m) >> 10) * cstat->max_tx_udp_payload_size * 4 / 10; @@ -326,15 +322,15 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, return; } - if (cstat->cwnd < cstat->ssthresh) { - /* slow-start */ - round_start = ack->pkt_delivered >= cubic->next_round_delivered; - if (round_start) { - cubic->next_round_delivered = cubic->rst->delivered; + round_start = ack->pkt_delivered >= cubic->next_round_delivered; + if (round_start) { + cubic->next_round_delivered = cubic->rst->delivered; - cubic->rst->is_cwnd_limited = 0; - } + cubic->rst->is_cwnd_limited = 0; + } + if (cstat->cwnd < cstat->ssthresh) { + /* slow-start */ if (!is_app_limited) { if (cubic->hs.css_round) { cstat->cwnd += ack->bytes_delivered / NGTCP2_HS_CSS_GROWTH_DIVISOR; @@ -345,8 +341,8 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, set_pacing_rate(cstat); ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, - "%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64, - ack->bytes_delivered, cstat->cwnd); + ack->bytes_delivered, + " bytes acked, slow start cwnd=", cstat->cwnd); } if (round_start) { @@ -360,7 +356,7 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, } cubic->hs.current_round_min_rtt = - ngtcp2_min_uint64(cubic->hs.current_round_min_rtt, ack->rtt); + ngtcp2_min(cubic->hs.current_round_min_rtt, ack->rtt); ++cubic->hs.rtt_sample_count; if (cubic->hs.css_round) { @@ -387,11 +383,10 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, if (cubic->hs.rtt_sample_count >= NGTCP2_HS_N_RTT_SAMPLE && cubic->hs.current_round_min_rtt != UINT64_MAX && cubic->hs.last_round_min_rtt != UINT64_MAX) { - rtt_thresh = - ngtcp2_max_uint64(NGTCP2_HS_MIN_RTT_THRESH, - ngtcp2_min_uint64(cubic->hs.last_round_min_rtt / - NGTCP2_HS_MIN_RTT_DIVISOR, - NGTCP2_HS_MAX_RTT_THRESH)); + rtt_thresh = ngtcp2_max( + NGTCP2_HS_MIN_RTT_THRESH, + ngtcp2_min(cubic->hs.last_round_min_rtt / NGTCP2_HS_MIN_RTT_DIVISOR, + NGTCP2_HS_MAX_RTT_THRESH)); if (cubic->hs.current_round_min_rtt >= cubic->hs.last_round_min_rtt + rtt_thresh) { @@ -462,11 +457,10 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, set_pacing_rate(cstat); - ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, - "%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64 - " k_m=%" PRIu64 " target=%" PRIu64 " w_est=%" PRIu64, - ack->bytes_delivered, cstat->cwnd, cubic->current.k_m, - target, cubic->current.w_est); + ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, ack->bytes_delivered, + " bytes acked, cubic-ca cwnd=", cstat->cwnd, + " k_m=", cubic->current.k_m, " target=", target, + " w_est=", cubic->current.w_est); } void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, @@ -502,19 +496,18 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, } cubic->current.w_max = - ngtcp2_max_uint64(cubic->current.w_max, 2 * cstat->max_tx_udp_payload_size); + ngtcp2_max(cubic->current.w_max, 2 * cstat->max_tx_udp_payload_size); cstat->ssthresh = cstat->cwnd * 7 / 10; if (cubic->rst->rs.delivered * 2 < cstat->cwnd) { flight_size = cstat->bytes_in_flight + ack->bytes_lost; - cstat->ssthresh = ngtcp2_min_uint64( - cstat->ssthresh, - ngtcp2_max_uint64(cubic->rst->rs.delivered, flight_size)); + cstat->ssthresh = ngtcp2_min( + cstat->ssthresh, ngtcp2_max(cubic->rst->rs.delivered, flight_size)); } cstat->ssthresh = - ngtcp2_max_uint64(cstat->ssthresh, 2 * cstat->max_tx_udp_payload_size); + ngtcp2_max(cstat->ssthresh, 2 * cstat->max_tx_udp_payload_size); cubic->current.cwnd_prior = cstat->cwnd; cstat->cwnd = cstat->ssthresh; @@ -531,8 +524,7 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, set_pacing_rate(cstat); ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, - "reduce cwnd because of packet loss cwnd=%" PRIu64, - cstat->cwnd); + "reduce cwnd because of packet loss cwnd=", cstat->cwnd); } void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc, @@ -552,7 +544,7 @@ void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc, ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "spurious congestion is detected and congestion state is " - "restored cwnd=%" PRIu64, + "restored cwnd=", cstat->cwnd); } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c index c470eb05b0648d..28bbde1233e1e4 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c @@ -58,13 +58,23 @@ are not processed. */ #define NGTCP2_MAX_ACK_PER_PKT 1 +/* NGTCP2_MAX_INITIAL_CRYPTO_OFFSET is the maximum offset of CRYPTO + data at Initial encryption level. */ +#define NGTCP2_MAX_INITIAL_CRYPTO_OFFSET (16 * 1024) +/* NGTCP2_MAX_HANDSHAKE_CRYPTO_OFFSET is the maximum offset of CRYPTO + data at Handshake encryption level. */ +#define NGTCP2_MAX_HANDSHAKE_CRYPTO_OFFSET (64 * 1024) +/* NGTCP2_MAX_1RTT_CRYPTO_OFFSET is the maximum offset of CRYPTO data + at 1RTT encryption level. */ +#define NGTCP2_MAX_1RTT_CRYPTO_OFFSET (256 * 1024) + ngtcp2_objalloc_def(strm, ngtcp2_strm, oplent) /* * conn_local_stream returns nonzero if |stream_id| indicates that it * is the stream initiated by local endpoint. */ -static int conn_local_stream(ngtcp2_conn *conn, int64_t stream_id) { +static int conn_local_stream(const ngtcp2_conn *conn, int64_t stream_id) { return (uint8_t)(stream_id & 1) == conn->server; } @@ -86,7 +96,7 @@ static void conn_update_timestamp(ngtcp2_conn *conn, ngtcp2_tstamp ts) { * conn_is_tls_handshake_completed returns nonzero if TLS handshake * has completed and 1 RTT keys are available. */ -static int conn_is_tls_handshake_completed(ngtcp2_conn *conn) { +static int conn_is_tls_handshake_completed(const ngtcp2_conn *conn) { return (conn->flags & NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED) && conn->pktns.crypto.rx.ckm && conn->pktns.crypto.tx.ckm; } @@ -854,7 +864,7 @@ static void conn_reset_conn_stat_cc(ngtcp2_conn *conn, cstat->pto_count = 0; cstat->loss_detection_timer = UINT64_MAX; cstat->max_tx_udp_payload_size = - ngtcp2_conn_get_path_max_tx_udp_payload_size(conn); + ngtcp2_conn_get_path_max_tx_udp_payload_size2(conn); cstat->cwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size); cstat->ssthresh = UINT64_MAX; cstat->congestion_recovery_start_ts = UINT64_MAX; @@ -898,15 +908,15 @@ static void delete_scid(ngtcp2_ksl *scids, const ngtcp2_mem *mem) { static ngtcp2_duration compute_pto(ngtcp2_duration smoothed_rtt, ngtcp2_duration rttvar, ngtcp2_duration max_ack_delay) { - ngtcp2_duration var = ngtcp2_max_uint64(4 * rttvar, NGTCP2_GRANULARITY); + ngtcp2_duration var = ngtcp2_max(4 * rttvar, NGTCP2_GRANULARITY); return smoothed_rtt + var + max_ack_delay; } /* * conn_compute_initial_pto computes PTO using the initial RTT. */ -static ngtcp2_duration conn_compute_initial_pto(ngtcp2_conn *conn, - ngtcp2_pktns *pktns) { +static ngtcp2_duration conn_compute_initial_pto(const ngtcp2_conn *conn, + const ngtcp2_pktns *pktns) { ngtcp2_duration initial_rtt = conn->local.settings.initial_rtt; ngtcp2_duration max_ack_delay; @@ -919,12 +929,9 @@ static ngtcp2_duration conn_compute_initial_pto(ngtcp2_conn *conn, return compute_pto(initial_rtt, initial_rtt / 2, max_ack_delay); } -/* - * conn_compute_pto computes the current PTO. - */ -static ngtcp2_duration conn_compute_pto(ngtcp2_conn *conn, - ngtcp2_pktns *pktns) { - ngtcp2_conn_stat *cstat = &conn->cstat; +ngtcp2_duration ngtcp2_conn_compute_pto(const ngtcp2_conn *conn, + const ngtcp2_pktns *pktns) { + const ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_duration max_ack_delay; if (pktns->id == NGTCP2_PKTNS_ID_APPLICATION && @@ -936,28 +943,23 @@ static ngtcp2_duration conn_compute_pto(ngtcp2_conn *conn, return compute_pto(cstat->smoothed_rtt, cstat->rttvar, max_ack_delay); } -ngtcp2_duration ngtcp2_conn_compute_pto(ngtcp2_conn *conn, - ngtcp2_pktns *pktns) { - return conn_compute_pto(conn, pktns); -} - /* * conn_compute_pv_timeout_pto returns path validation timeout using * the given |pto|. */ -static ngtcp2_duration conn_compute_pv_timeout_pto(ngtcp2_conn *conn, +static ngtcp2_duration conn_compute_pv_timeout_pto(const ngtcp2_conn *conn, ngtcp2_duration pto) { ngtcp2_duration initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - return 3 * ngtcp2_max_uint64(pto, initial_pto); + return 3 * ngtcp2_max(pto, initial_pto); } /* * conn_compute_pv_timeout returns path validation timeout. */ -static ngtcp2_duration conn_compute_pv_timeout(ngtcp2_conn *conn) { - return conn_compute_pv_timeout_pto(conn, - conn_compute_pto(conn, &conn->pktns)); +static ngtcp2_duration conn_compute_pv_timeout(const ngtcp2_conn *conn) { + return conn_compute_pv_timeout_pto( + conn, ngtcp2_conn_compute_pto(conn, &conn->pktns)); } static void conn_handle_tx_ecn(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, @@ -992,7 +994,7 @@ static void conn_handle_tx_ecn(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, conn->tx.ecn.validation_start_ts = ts; } else if (ts - conn->tx.ecn.validation_start_ts >= - 3 * conn_compute_pto(conn, pktns)) { + 3 * ngtcp2_conn_compute_pto(conn, pktns)) { conn->tx.ecn.state = NGTCP2_ECN_STATE_UNKNOWN; break; } @@ -1117,8 +1119,8 @@ static void conn_update_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { pktns->tx.skip_pkt.next_pkt_num = pktns->tx.last_pkt_num + gap; - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "next skip pkn=%" PRId64, - pktns->tx.skip_pkt.next_pkt_num); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, + "next skip pkn=", pktns->tx.skip_pkt.next_pkt_num); } static int conn_handle_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, @@ -1159,11 +1161,11 @@ static int conn_handle_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, } static size_t buflen_align(size_t buflen) { - return (buflen + 0x7) & (size_t)~0x7; + return (buflen + 0x7U) & ~(size_t)0x7U; } static void *buf_align(void *buf) { - return (void *)((uintptr_t)((uint8_t *)buf + 0x7) & (uintptr_t)~0x7); + return (void *)((uintptr_t)((uint8_t *)buf + 0x7U) & ~(uintptr_t)0x7U); } static void *buf_advance(void *buf, size_t n) { return (uint8_t *)buf + n; } @@ -1178,7 +1180,7 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, const ngtcp2_mem *mem, void *user_data, int server) { int rv; ngtcp2_scid *scident; - void *buf, *tokenbuf; + void *buf, *tokenbuf, *logbuf; size_t buflen; uint8_t fixed_bit_byte; size_t i; @@ -1275,6 +1277,11 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, buflen += sizeof(client_chosen_version); } + if (settings->log_write || settings->log_printf) { + buflen = buflen_align(buflen); + buflen += NGTCP2_LOG_BUFLEN; + } + buf = ngtcp2_mem_calloc(mem, 1, buflen); if (buf == NULL) { return NGTCP2_ERR_NOMEM; @@ -1312,8 +1319,18 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ngtcp2_static_ringbuf_path_challenge_init(&(*pconn)->rx.path_challenge); - ngtcp2_log_init(&(*pconn)->log, scid, settings->log_printf, - settings->initial_ts, user_data); + if (settings->log_write || settings->log_printf) { + buf = buf_align(buf); + logbuf = (char *)buf; + buf = buf_advance(buf, NGTCP2_LOG_BUFLEN); + } else { + logbuf = NULL; + } + + ngtcp2_log_init(&(*pconn)->log, scid, settings->log_write, + settings->log_printf, logbuf, settings->initial_ts, + user_data); + ngtcp2_qlog_init(&(*pconn)->qlog, settings->qlog_write, settings->initial_ts, user_data); if ((*pconn)->qlog.write) { @@ -1628,9 +1645,10 @@ int ngtcp2_conn_server_new_versioned( * the given stream. Both connection and stream level flow control * credits are considered. */ -static uint64_t conn_fc_credits(ngtcp2_conn *conn, ngtcp2_strm *strm) { - return ngtcp2_min_uint64(strm->tx.max_offset - strm->tx.offset, - conn->tx.max_offset - conn->tx.offset); +static uint64_t conn_fc_credits(const ngtcp2_conn *conn, + const ngtcp2_strm *strm) { + return ngtcp2_min(strm->tx.max_offset - strm->tx.offset, + conn->tx.max_offset - conn->tx.offset); } /* @@ -1638,10 +1656,11 @@ static uint64_t conn_fc_credits(ngtcp2_conn *conn, ngtcp2_strm *strm) { * sent to the given stream. |len| might be shorted because of * available flow control credits. */ -static uint64_t conn_enforce_flow_control(ngtcp2_conn *conn, ngtcp2_strm *strm, +static uint64_t conn_enforce_flow_control(const ngtcp2_conn *conn, + const ngtcp2_strm *strm, uint64_t len) { uint64_t fc_credits = conn_fc_credits(conn, strm); - return ngtcp2_min_uint64(len, fc_credits); + return ngtcp2_min(len, fc_credits); } static int delete_strms_each(void *data, void *ptr) { @@ -1780,10 +1799,10 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { * conn_compute_ack_delay computes ACK delay for outgoing protected * ACK. */ -static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) { - return ngtcp2_min_uint64( +static ngtcp2_duration conn_compute_ack_delay(const ngtcp2_conn *conn) { + return ngtcp2_min( conn->local.transport_params.max_ack_delay, - ngtcp2_max_uint64(conn->cstat.smoothed_rtt / 8, NGTCP2_NANOSECONDS)); + ngtcp2_max(conn->cstat.smoothed_rtt / 8, NGTCP2_NANOSECONDS)); } /* @@ -1880,9 +1899,9 @@ static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_pktns *pktns, * number. It returns the number of bytes to encode the packet * number. */ -static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) { +static size_t pktns_select_pkt_numlen(const ngtcp2_pktns *pktns) { int64_t pkt_num = pktns->tx.last_pkt_num + 1; - ngtcp2_rtb *rtb = &pktns->rtb; + const ngtcp2_rtb *rtb = &pktns->rtb; int64_t n = pkt_num - rtb->largest_acked_tx_pkt_num; if (NGTCP2_MAX_PKT_NUM / 2 < n) { @@ -1907,14 +1926,14 @@ static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) { * conn_cwnd_is_zero returns nonzero if the number of bytes the local * endpoint can sent at this time is zero. */ -static int conn_cwnd_is_zero(ngtcp2_conn *conn) { +static int conn_cwnd_is_zero(const ngtcp2_conn *conn) { uint64_t bytes_in_flight = conn->cstat.bytes_in_flight; uint64_t cwnd = conn->cstat.cwnd; if (bytes_in_flight >= cwnd) { ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, - "cwnd limited bytes_in_flight=%lu cwnd=%lu", - bytes_in_flight, cwnd); + "cwnd limited bytes_in_flight=", bytes_in_flight, + " cwnd=", cwnd); } return bytes_in_flight >= cwnd; @@ -1948,7 +1967,7 @@ static uint64_t conn_retry_early_payloadlen(ngtcp2_conn *conn) { /* Take the min because in conn_should_pad_pkt we take max in order to deal with unbreakable DATAGRAM. */ - return ngtcp2_min_uint64(len, NGTCP2_MIN_COALESCED_PAYLOADLEN); + return ngtcp2_min(len, NGTCP2_MIN_COALESCED_PAYLOADLEN); } return 0; @@ -2005,7 +2024,7 @@ static int conn_verify_dcid(ngtcp2_conn *conn, int *pnew_cid_used, return 0; } -static int conn_can_send_next_pkt(ngtcp2_conn *conn, size_t left, +static int conn_can_send_next_pkt(const ngtcp2_conn *conn, size_t left, uint64_t min_payloadlen) { /* TODO the next packet type should be taken into account */ return left >= @@ -2021,9 +2040,9 @@ static int conn_can_send_next_pkt(ngtcp2_conn *conn, size_t left, * buffer. |write_datalen| is the number of bytes which will be sent * in the next, coalesced 0-RTT packet. */ -static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, - uint64_t write_datalen, int ack_eliciting, - int require_padding) { +static int conn_should_pad_pkt(const ngtcp2_conn *conn, uint8_t type, + size_t left, uint64_t write_datalen, + int ack_eliciting, int require_padding) { uint64_t min_payloadlen; if (type == NGTCP2_PKT_INITIAL) { @@ -2056,7 +2075,7 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, PADDING in that packet. Take maximum in case that write_datalen includes DATAGRAM which cannot be split. */ min_payloadlen = - ngtcp2_max_uint64(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); + ngtcp2_max(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); } else { return 1; } @@ -2100,7 +2119,7 @@ static void conn_restart_timer_on_read(ngtcp2_conn *conn, ngtcp2_tstamp ts) { /* * conn_keep_alive_enabled returns nonzero if keep-alive is enabled. */ -static int conn_keep_alive_enabled(ngtcp2_conn *conn) { +static int conn_keep_alive_enabled(const ngtcp2_conn *conn) { return conn->keep_alive.last_ts != UINT64_MAX && conn->keep_alive.timeout != UINT64_MAX; } @@ -2109,7 +2128,7 @@ static int conn_keep_alive_enabled(ngtcp2_conn *conn) { * conn_keep_alive_expired returns nonzero if keep-alive timer has * expired. */ -static int conn_keep_alive_expired(ngtcp2_conn *conn, ngtcp2_tstamp ts) { +static int conn_keep_alive_expired(const ngtcp2_conn *conn, ngtcp2_tstamp ts) { return ngtcp2_tstamp_elapsed(conn->keep_alive.last_ts, conn->keep_alive.timeout, ts); } @@ -2117,7 +2136,7 @@ static int conn_keep_alive_expired(ngtcp2_conn *conn, ngtcp2_tstamp ts) { /* * conn_keep_alive_expiry returns the expiry time of keep-alive timer. */ -static ngtcp2_tstamp conn_keep_alive_expiry(ngtcp2_conn *conn) { +static ngtcp2_tstamp conn_keep_alive_expiry(const ngtcp2_conn *conn) { if ((conn->flags & NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED) || !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) || !conn_keep_alive_enabled(conn) || @@ -2191,7 +2210,7 @@ static int conn_pacing_pkt_tx_allowed(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return 1; } -static uint8_t conn_pkt_flags(ngtcp2_conn *conn) { +static uint8_t conn_pkt_flags(const ngtcp2_conn *conn) { if (conn->remote.transport_params && conn->remote.transport_params->grease_quic_bit && (conn->flags & NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT)) { @@ -2201,11 +2220,11 @@ static uint8_t conn_pkt_flags(ngtcp2_conn *conn) { return NGTCP2_PKT_FLAG_NONE; } -static uint8_t conn_pkt_flags_long(ngtcp2_conn *conn) { +static uint8_t conn_pkt_flags_long(const ngtcp2_conn *conn) { return NGTCP2_PKT_FLAG_LONG_FORM | conn_pkt_flags(conn); } -static uint8_t conn_pkt_flags_short(ngtcp2_conn *conn) { +static uint8_t conn_pkt_flags_short(const ngtcp2_conn *conn) { return (uint8_t)(conn_pkt_flags(conn) | ((conn->pktns.crypto.tx.ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE) ? NGTCP2_PKT_FLAG_KEY_PHASE @@ -2284,6 +2303,9 @@ static int conn_cut_crypto_frame(ngtcp2_conn *conn, ngtcp2_frame_chain *frc, } right_frc->fr.stream.type = NGTCP2_FRAME_CRYPTO; + right_frc->fr.stream.flags = 0; + right_frc->fr.stream.fin = 0; + right_frc->fr.stream.stream_id = 0; right_frc->fr.stream.offset = removed_frc->fr.stream.offset + removed_frc->fr.stream.data->len; right_frc->fr.stream.datacnt = 0; @@ -2412,7 +2434,7 @@ conn_crumble_initial_crypto(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, return (ngtcp2_ssize)datacnt; } -static size_t conn_dgram_padding(ngtcp2_conn *conn, ngtcp2_ppe *ppe) { +static size_t conn_dgram_padding(const ngtcp2_conn *conn, ngtcp2_ppe *ppe) { if (conn->local.settings.no_tx_udp_payload_size_shaping) { return ngtcp2_ppe_dgram_padding_size( ppe, conn->local.settings.max_tx_udp_payload_size); @@ -2421,7 +2443,7 @@ static size_t conn_dgram_padding(ngtcp2_conn *conn, ngtcp2_ppe *ppe) { return ngtcp2_ppe_dgram_padding(ppe); } -static size_t conn_min_pktlen(ngtcp2_conn *conn); +static size_t conn_min_pktlen(const ngtcp2_conn *conn); /* * conn_write_handshake_pkt writes handshake packet in the buffer @@ -2523,10 +2545,6 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, return 0; } - if (!ngtcp2_ppe_ensure_hp_sample(&ppe)) { - return 0; - } - lfr.ack.ranges = ack_ranges; if (ngtcp2_acktr_create_ack_frame(&pktns->acktr, &lfr.ack, type, ts, /* ack_delay = */ 0, @@ -3014,7 +3032,7 @@ static ngtcp2_ssize conn_write_client_initial(ngtcp2_conn *conn, * dcid_tx_left returns the maximum number of bytes that server is * allowed to send to an unvalidated path associated to |dcid|. */ -static uint64_t dcid_tx_left(ngtcp2_dcid *dcid) { +static uint64_t dcid_tx_left(const ngtcp2_dcid *dcid) { if (dcid->flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) { return SIZE_MAX; } @@ -3030,7 +3048,8 @@ static uint64_t dcid_tx_left(ngtcp2_dcid *dcid) { * conn_server_tx_left returns the maximum number of bytes that server * is allowed to send to an unvalidated path. */ -static uint64_t conn_server_tx_left(ngtcp2_conn *conn, ngtcp2_dcid *dcid) { +static uint64_t conn_server_tx_left(const ngtcp2_conn *conn, + const ngtcp2_dcid *dcid) { assert(conn->server); /* If pv->dcid has the current path, use conn->dcid.current. This @@ -3176,8 +3195,8 @@ static uint64_t conn_initial_stream_rx_offset(ngtcp2_conn *conn, * conn_should_send_max_stream_data returns nonzero if MAX_STREAM_DATA * frame should be send for |strm|. */ -static int conn_should_send_max_stream_data(ngtcp2_conn *conn, - ngtcp2_strm *strm) { +static int conn_should_send_max_stream_data(const ngtcp2_conn *conn, + const ngtcp2_strm *strm) { uint64_t inc = strm->rx.unsent_max_offset - strm->rx.max_offset; (void)conn; @@ -3188,7 +3207,7 @@ static int conn_should_send_max_stream_data(ngtcp2_conn *conn, * conn_should_send_max_data returns nonzero if MAX_DATA frame should * be sent. */ -static int conn_should_send_max_data(ngtcp2_conn *conn) { +static int conn_should_send_max_data(const ngtcp2_conn *conn) { uint64_t inc = conn->rx.unsent_max_offset - conn->rx.max_offset; return conn->rx.window < 4 * inc; @@ -3199,8 +3218,8 @@ static int conn_should_send_max_data(ngtcp2_conn *conn) { * additional connection ID the local endpoint has to provide to the * remote endpoint. */ -static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { - uint64_t n; +static size_t conn_required_num_new_connection_id(const ngtcp2_conn *conn) { + size_t n; size_t len = ngtcp2_ksl_len(&conn->scid.set); size_t lim; @@ -3221,12 +3240,13 @@ static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { /* len includes retired CID. We don't provide extra CID if doing so exceeds NGTCP2_MAX_SCID_POOL_SIZE. */ - n = conn->remote.transport_params->active_connection_id_limit + - conn->scid.num_retired; + n = (size_t)ngtcp2_min( + NGTCP2_MAX_SCID_POOL_SIZE, + conn->remote.transport_params->active_connection_id_limit + + conn->scid.num_retired) - + len; - n = ngtcp2_min_uint64(NGTCP2_MAX_SCID_POOL_SIZE, n) - len; - - return (size_t)ngtcp2_min_uint64(lim, n); + return ngtcp2_min(lim, n); } /* @@ -3374,7 +3394,7 @@ static int conn_remove_retired_connection_id(ngtcp2_conn *conn, * sends. It may underestimate the length because this does not take * into account header protection sample. */ -static size_t conn_min_pktlen(ngtcp2_conn *conn) { +static size_t conn_min_pktlen(const ngtcp2_conn *conn) { return conn->oscid.datalen + NGTCP2_MIN_PKT_EXPANDLEN; } @@ -3401,13 +3421,11 @@ static void conn_handle_unconfirmed_key_update_from_remote(ngtcp2_conn *conn, ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CRY, "key update confirmed"); } -static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn); - /* * strm_should_send_stream_data_blocked returns nonzero if * STREAM_DATA_BLOCKED frame should be sent to |strm|. */ -static int strm_should_send_stream_data_blocked(ngtcp2_strm *strm) { +static int strm_should_send_stream_data_blocked(const ngtcp2_strm *strm) { return strm->tx.offset == strm->tx.max_offset && strm->tx.last_blocked_offset != strm->tx.max_offset; } @@ -3416,7 +3434,7 @@ static int strm_should_send_stream_data_blocked(ngtcp2_strm *strm) { * conn_should_send_data_blocked returns nonzero if DATA_BLOCKED frame * should be sent. */ -static int conn_should_send_data_blocked(ngtcp2_conn *conn) { +static int conn_should_send_data_blocked(const ngtcp2_conn *conn) { return conn->tx.offset == conn->tx.max_offset && conn->tx.last_blocked_offset != conn->tx.max_offset; } @@ -3640,10 +3658,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, return 0; } - if (!ngtcp2_ppe_ensure_hp_sample(ppe)) { - return 0; - } - if (ngtcp2_ringbuf_len(&conn->rx.path_challenge.rb)) { pcent = ngtcp2_ringbuf_get(&conn->rx.path_challenge.rb, 0); @@ -4297,7 +4311,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); if (!ngtcp2_strm_is_tx_queued(strm)) { - strm->cycle = conn_tx_strmq_first_cycle(conn); + strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn); rv = ngtcp2_conn_tx_strmq_push(conn, strm); if (rv != 0) { return rv; @@ -4367,7 +4381,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (pkt_empty) { if (*pfrc == NULL && rv == 0 && stream_blocked && (write_more || !require_padding) && - ngtcp2_conn_get_max_data_left(conn)) { + ngtcp2_conn_get_max_data_left2(conn)) { if (write_more) { conn->pkt.pfrc = pfrc; conn->pkt.pkt_empty = pkt_empty; @@ -4408,7 +4422,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, break; } - if (*pfrc == NULL && ngtcp2_conn_get_max_data_left(conn) && + if (*pfrc == NULL && ngtcp2_conn_get_max_data_left2(conn) && stream_blocked) { return NGTCP2_ERR_STREAM_DATA_BLOCKED; } @@ -4528,8 +4542,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { --pktns->rtb.probe_pkt_left; - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td", - nwrite); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, + "probe pkt size=", nwrite); } conn_update_keep_alive_last_ts(conn, ts); @@ -4626,10 +4640,6 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( return 0; } - if (!ngtcp2_ppe_ensure_hp_sample(&ppe)) { - return 0; - } - ngtcp2_log_tx_pkt_hd(&conn->log, &hd); ngtcp2_qlog_pkt_sent_start(&conn->qlog); @@ -4731,8 +4741,8 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) { --pktns->rtb.probe_pkt_left; - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td", - nwrite); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, + "probe pkt size=", nwrite); } } } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) { @@ -4793,9 +4803,9 @@ static void conn_process_early_rtb(ngtcp2_conn *conn) { * handshake packets the local endpoint has to send, including new * packets and lost ones. */ -static int conn_handshake_remnants_left(ngtcp2_conn *conn) { - ngtcp2_pktns *in_pktns = conn->in_pktns; - ngtcp2_pktns *hs_pktns = conn->hs_pktns; +static int conn_handshake_remnants_left(const ngtcp2_conn *conn) { + const ngtcp2_pktns *in_pktns = conn->in_pktns; + const ngtcp2_pktns *hs_pktns = conn->hs_pktns; return !conn_is_tls_handshake_completed(conn) || (in_pktns && (in_pktns->rtb.num_pto_eliciting || @@ -4913,9 +4923,9 @@ static int conn_start_pmtud(ngtcp2_conn *conn) { assert(conn->remote.transport_params->max_udp_payload_size >= NGTCP2_MAX_UDP_PAYLOAD_SIZE); - hard_max_udp_payload_size = (size_t)ngtcp2_min_uint64( - conn->remote.transport_params->max_udp_payload_size, - (uint64_t)conn->local.settings.max_tx_udp_payload_size); + hard_max_udp_payload_size = + (size_t)ngtcp2_min(conn->remote.transport_params->max_udp_payload_size, + (uint64_t)conn->local.settings.max_tx_udp_payload_size); rv = ngtcp2_pmtud_new(&conn->pmtud, conn->dcid.current.max_udp_payload_size, @@ -4967,7 +4977,7 @@ static ngtcp2_ssize conn_write_pmtud_probe(ngtcp2_conn *conn, } ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "sending PMTUD probe packet len=%zu", probelen); + "sending PMTUD probe packet len=", probelen); lfr.ping.type = NGTCP2_FRAME_PING; @@ -4983,8 +4993,8 @@ static ngtcp2_ssize conn_write_pmtud_probe(ngtcp2_conn *conn, assert(nwrite); - ngtcp2_pmtud_probe_sent(conn->pmtud, conn_compute_pto(conn, &conn->pktns), - ts); + ngtcp2_pmtud_probe_sent(conn->pmtud, + ngtcp2_conn_compute_pto(conn, &conn->pktns), ts); return nwrite; } @@ -5062,26 +5072,27 @@ static int conn_abort_pv(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return conn_stop_pv(conn, ts); } -static size_t conn_shape_udp_payload(ngtcp2_conn *conn, const ngtcp2_dcid *dcid, +static size_t conn_shape_udp_payload(const ngtcp2_conn *conn, + const ngtcp2_dcid *dcid, size_t payloadlen) { if (conn->remote.transport_params && conn->remote.transport_params->max_udp_payload_size) { assert(conn->remote.transport_params->max_udp_payload_size >= NGTCP2_MAX_UDP_PAYLOAD_SIZE); - payloadlen = (size_t)ngtcp2_min_uint64( - (uint64_t)payloadlen, - conn->remote.transport_params->max_udp_payload_size); + payloadlen = + (size_t)ngtcp2_min((uint64_t)payloadlen, + conn->remote.transport_params->max_udp_payload_size); } payloadlen = - ngtcp2_min_size(payloadlen, conn->local.settings.max_tx_udp_payload_size); + ngtcp2_min(payloadlen, conn->local.settings.max_tx_udp_payload_size); if (conn->local.settings.no_tx_udp_payload_size_shaping) { return payloadlen; } - return ngtcp2_min_size(payloadlen, dcid->max_udp_payload_size); + return ngtcp2_min(payloadlen, dcid->max_udp_payload_size); } static void conn_reset_congestion_state(ngtcp2_conn *conn, ngtcp2_tstamp ts); @@ -5175,16 +5186,16 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, lfr.path_challenge.type = NGTCP2_FRAME_PATH_CHALLENGE; initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - timeout = conn_compute_pto(conn, &conn->pktns); - timeout = ngtcp2_max_uint64(timeout, initial_pto); + timeout = ngtcp2_conn_compute_pto(conn, &conn->pktns); + timeout = ngtcp2_max(timeout, initial_pto); expiry = ts + timeout * (1ULL << pv->round); - destlen = ngtcp2_min_size(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE); + destlen = ngtcp2_min(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE); if (conn->server) { if (!(pv->dcid.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { tx_left = conn_server_tx_left(conn, &pv->dcid); - destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, tx_left); + destlen = (size_t)ngtcp2_min((uint64_t)destlen, tx_left); if (destlen == 0) { return 0; } @@ -5295,11 +5306,11 @@ static ngtcp2_ssize conn_write_path_response(ngtcp2_conn *conn, } } - destlen = ngtcp2_min_size(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE); + destlen = ngtcp2_min(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE); if (conn->server && !(dcid->flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { tx_left = conn_server_tx_left(conn, dcid); - destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, tx_left); + destlen = (size_t)ngtcp2_min((uint64_t)destlen, tx_left); if (destlen == 0) { return 0; } @@ -5417,18 +5428,7 @@ static int conn_on_version_negotiation(ngtcp2_conn *conn, return rv; } -static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn) { - ngtcp2_strm *strm; - - if (ngtcp2_pq_empty(&conn->tx.strmq)) { - return 0; - } - - strm = ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx.strmq), ngtcp2_strm, pe); - return strm->cycle; -} - -uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn) { +uint64_t ngtcp2_conn_tx_strmq_first_cycle(const ngtcp2_conn *conn) { ngtcp2_strm *strm; if (ngtcp2_pq_empty(&conn->tx.strmq)) { @@ -5465,7 +5465,6 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_rtb *rtb = &conn->pktns.rtb; ngtcp2_rtb *in_rtb; - char cidbuf[sizeof(retry.odcid.data) * 2 + 1]; uint8_t *token; if (!in_pktns || (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY)) { @@ -5490,9 +5489,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, return rv; } - ngtcp2_log_infof( - &conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s", - ngtcp2_encode_hex_cstr(cidbuf, retry.odcid.data, retry.odcid.datalen)); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x", &retry.odcid); if (retry.tokenlen == 0) { return NGTCP2_ERR_PROTO; @@ -5596,7 +5593,7 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, (conn->server || (conn->flags & NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED))) { /* Reset PTO count but no less than 2 to avoid frequent probe packet transmission. */ - cstat->pto_count = ngtcp2_min_size(cstat->pto_count, 2); + cstat->pto_count = ngtcp2_min(cstat->pto_count, 2); } ngtcp2_conn_set_loss_detection_timer(conn, ts); @@ -5740,7 +5737,7 @@ static int conn_recv_max_stream_data(ngtcp2_conn *conn, * conn_recv_max_data processes received MAX_DATA frame |fr|. */ static void conn_recv_max_data(ngtcp2_conn *conn, const ngtcp2_max_data *fr) { - conn->tx.max_offset = ngtcp2_max_uint64(conn->tx.max_offset, fr->max_data); + conn->tx.max_offset = ngtcp2_max(conn->tx.max_offset, fr->max_data); } /* @@ -5925,9 +5922,9 @@ decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, const ngtcp2_crypto_cipher *hp, } if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) { - dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0F)); + dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0FU)); } else { - dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1F)); + dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1FU)); if (dest[0] & NGTCP2_SHORT_KEY_PHASE_BIT) { hd->flags |= NGTCP2_PKT_FLAG_KEY_PHASE; } @@ -6021,7 +6018,7 @@ static int conn_recv_connection_close(ngtcp2_conn *conn, } } - ccerr->reasonlen = ngtcp2_min_size(fr->reasonlen, NGTCP2_CCERR_MAX_REASONLEN); + ccerr->reasonlen = ngtcp2_min(fr->reasonlen, NGTCP2_CCERR_MAX_REASONLEN); ngtcp2_cpymem((uint8_t *)ccerr->reason, fr->reason, ccerr->reasonlen); return 0; @@ -6215,7 +6212,8 @@ static int conn_recv_path_response(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, * pktns_pkt_num_is_duplicate returns nonzero if |pkt_num| is * duplicated packet number. */ -static int pktns_pkt_num_is_duplicate(ngtcp2_pktns *pktns, int64_t pkt_num) { +static int pktns_pkt_num_is_duplicate(const ngtcp2_pktns *pktns, + int64_t pkt_num) { return ngtcp2_gaptr_is_pushed(&pktns->rx.pngap, (uint64_t)pkt_num, 1); } @@ -6331,7 +6329,8 @@ static int vneg_available_versions_includes(const uint8_t *available_versions, * NGTCP2_ERR_INVALID_ARGUMENT * Clearing fixed bit is not permitted. */ -static int conn_verify_fixed_bit(ngtcp2_conn *conn, ngtcp2_pkt_hd *hd) { +static int conn_verify_fixed_bit(const ngtcp2_conn *conn, + const ngtcp2_pkt_hd *hd) { if (!(hd->flags & NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR)) { return 0; } @@ -6449,7 +6448,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "buffering 1RTT packet len=%zu", pktlen); + "buffering 1RTT packet len=", pktlen); rv = conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt, pktlen, dgramlen, ts); @@ -6597,7 +6596,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, /* Buffer re-ordered 0-RTT packet. */ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "buffering 0-RTT packet len=%zu", pktlen); + "buffering 0-RTT packet len=", pktlen); rv = conn_buffer_pkt(conn, conn->in_pktns, path, pi, pkt, pktlen, dgramlen, ts); @@ -6622,8 +6621,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_log_infof( &conn->log, NGTCP2_LOG_EVENT_PKT, "Initial packet was ignored because it is included in UDP datagram " - "less than %d bytes: %zu bytes", - NGTCP2_MAX_UDP_PAYLOAD_SIZE, dgramlen); + "less than " stringify(NGTCP2_MAX_UDP_PAYLOAD_SIZE) " bytes: ", + dgramlen, " bytes"); return NGTCP2_ERR_DISCARD_PKT; } if (conn->local.settings.tokenlen) { @@ -6703,7 +6702,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return (ngtcp2_ssize)pktlen; } ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "buffering Handshake packet len=%zu", pktlen); + "buffering Handshake packet len=", pktlen); rv = conn_buffer_pkt(conn, conn->hs_pktns, path, pi, pkt, pktlen, dgramlen, ts); @@ -6757,8 +6756,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, hd.pkt_num = ngtcp2_pkt_adjust_pkt_num(pktns->acktr.max_pkt_num, hd.pkt_num, hd.pkt_numlen); if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) { - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, - "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, "pkn=", hd.pkt_num, + " is greater than maximum pkn"); return NGTCP2_ERR_DISCARD_PKT; } @@ -6806,8 +6805,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, conn->negotiated_version = hd.version; ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "the negotiated version is 0x%08x", - conn->negotiated_version); + "the negotiated version is 0x", + hexw(conn->negotiated_version, 8)); } payload = conn->crypto.decrypt_buf.base; @@ -6911,8 +6910,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, conn->negotiated_version = hd.version; ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "the negotiated version is 0x%08x", - conn->negotiated_version); + "the negotiated version is 0x", + hexw(conn->negotiated_version, 8)); } rv = conn_recv_crypto(conn, encryption_level, crypto, &fr.stream, ts); @@ -7072,8 +7071,8 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn, ++conn->cstat.pkt_recv; conn->cstat.bytes_recv += (uint64_t)nread; - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, - "read packet %td left %zu", nread, pktlen); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, "read packet ", nread, + " left ", pktlen); } return (ngtcp2_ssize)dgramlen; @@ -7085,6 +7084,7 @@ int ngtcp2_conn_init_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t max_rx_offset; uint64_t max_tx_offset; int local_stream = conn_local_stream(conn, stream_id); + int bidi = bidi_stream(stream_id); assert(conn->remote.transport_params); @@ -7112,6 +7112,15 @@ int ngtcp2_conn_init_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, max_tx_offset, stream_user_data, &conn->frc_objalloc, conn->mem); + if (!bidi) { + if (local_stream) { + ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_RD); + } else { + ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR); + strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED; + } + } + rv = ngtcp2_map_insert(&conn->strms, (ngtcp2_map_key_type)strm->stream_id, strm); if (rv != 0) { @@ -7229,6 +7238,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, uint64_t rx_offset; int rv; ngtcp2_ssize nwrite; + size_t max_offset; if (fr->datacnt == 0) { if (encryption_level != NGTCP2_ENCRYPTION_LEVEL_INITIAL && @@ -7245,6 +7255,27 @@ static int conn_recv_crypto(ngtcp2_conn *conn, return NGTCP2_ERR_FRAME_ENCODING; } + /* Apply the absolute upper bound against CRYPTO data offset because + some TLS stacks do not care much about the number of bytes they + store. */ + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: + max_offset = NGTCP2_MAX_INITIAL_CRYPTO_OFFSET; + break; + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: + max_offset = NGTCP2_MAX_HANDSHAKE_CRYPTO_OFFSET; + break; + case NGTCP2_ENCRYPTION_LEVEL_1RTT: + max_offset = NGTCP2_MAX_1RTT_CRYPTO_OFFSET; + break; + default: + ngtcp2_unreachable(); + } + + if (fr_end_offset > max_offset) { + return NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED; + } + rx_offset = ngtcp2_strm_rx_offset(crypto); if (fr_end_offset <= rx_offset) { @@ -7274,8 +7305,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, return 0; } - crypto->rx.last_offset = - ngtcp2_max_uint64(crypto->rx.last_offset, fr_end_offset); + crypto->rx.last_offset = ngtcp2_max(crypto->rx.last_offset, fr_end_offset); /* TODO Before dispatching incoming data to TLS stack, make sure that previous data in previous encryption level has been @@ -7328,7 +7358,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, * conn_max_data_violated returns nonzero if receiving |datalen| * violates connection flow control on local endpoint. */ -static int conn_max_data_violated(ngtcp2_conn *conn, uint64_t datalen) { +static int conn_max_data_violated(const ngtcp2_conn *conn, uint64_t datalen) { return conn->rx.max_offset - conn->rx.offset < datalen; } @@ -7438,11 +7468,6 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr, new_strm = 1; - if (!bidi) { - ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR); - strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED; - } - rv = conn_call_stream_open(conn, strm); if (rv != 0) { return rv; @@ -7505,8 +7530,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr, return NGTCP2_ERR_FINAL_SIZE; } - strm->rx.last_offset = - ngtcp2_max_uint64(strm->rx.last_offset, fr_end_offset); + strm->rx.last_offset = ngtcp2_max(strm->rx.last_offset, fr_end_offset); if (fr_end_offset <= rx_offset) { if (!new_strm && ngtcp2_ratelim_drain(&conn->glitch_rlim, 1, ts) != 0) { @@ -7600,7 +7624,7 @@ static int conn_reset_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, return 0; } - strm->cycle = conn_tx_strmq_first_cycle(conn); + strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn); return ngtcp2_conn_tx_strmq_push(conn, strm); } @@ -7624,7 +7648,7 @@ static int conn_stop_sending(ngtcp2_conn *conn, ngtcp2_strm *strm, return 0; } - strm->cycle = conn_tx_strmq_first_cycle(conn); + strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn); return ngtcp2_conn_tx_strmq_push(conn, strm); } @@ -8005,7 +8029,7 @@ static int conn_recv_max_streams(ngtcp2_conn *conn, return NGTCP2_ERR_FRAME_ENCODING; } - n = ngtcp2_min_uint64(fr->max_streams, NGTCP2_MAX_STREAMS); + n = ngtcp2_min(fr->max_streams, NGTCP2_MAX_STREAMS); if (fr->type == NGTCP2_FRAME_MAX_STREAMS_BIDI) { if (conn->local.bidi.max_streams < n) { @@ -8448,11 +8472,6 @@ static int conn_recv_stream_data_blocked(ngtcp2_conn *conn, return rv; } - if (!bidi) { - ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR); - strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED; - } - rv = conn_call_stream_open(conn, strm); if (rv != 0) { return rv; @@ -8636,8 +8655,9 @@ static int conn_recv_datagram(ngtcp2_conn *conn, ngtcp2_datagram *fr) { * conn_key_phase_changed returns nonzero if |hd| indicates that the * key phase has unexpected value. */ -static int conn_key_phase_changed(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) { - ngtcp2_pktns *pktns = &conn->pktns; +static int conn_key_phase_changed(const ngtcp2_conn *conn, + const ngtcp2_pkt_hd *hd) { + const ngtcp2_pktns *pktns = &conn->pktns; return !(pktns->crypto.rx.ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE) ^ !(hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE); @@ -8651,7 +8671,7 @@ static int conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts); static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { int rv; ngtcp2_tstamp confirmed_ts = conn->crypto.key_update.confirmed_ts; - ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); + ngtcp2_duration pto = ngtcp2_conn_compute_pto(conn, &conn->pktns); ngtcp2_pktns *pktns = &conn->pktns; ngtcp2_crypto_km *rx_ckm = pktns->crypto.rx.ckm; ngtcp2_crypto_km *tx_ckm = pktns->crypto.tx.ckm; @@ -8760,9 +8780,9 @@ static void conn_rotate_keys(ngtcp2_conn *conn, int64_t pkt_num, * conn_path_validation_in_progress returns nonzero if path validation * against |path| is underway. */ -static int conn_path_validation_in_progress(ngtcp2_conn *conn, +static int conn_path_validation_in_progress(const ngtcp2_conn *conn, const ngtcp2_path *path) { - ngtcp2_pv *pv = conn->pv; + const ngtcp2_pv *pv = conn->pv; return pv && ngtcp2_path_eq(&pv->dcid.ps.path, path); } @@ -8889,7 +8909,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, validated_path = ngtcp2_conn_find_path_history(conn, path, ts); if (!validated_path) { - pto = conn_compute_pto(conn, &conn->pktns); + pto = ngtcp2_conn_compute_pto(conn, &conn->pktns); rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout_pto(conn, pto), NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); @@ -9267,8 +9287,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, break; default: ngtcp2_log_rx_pkt_hd(&conn->log, &hd); - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, - "packet type 0x%02x was ignored", hd.type); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet type 0x", + hex(hd.type), " was ignored"); return (ngtcp2_ssize)pktlen; } } else { @@ -9315,8 +9335,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, hd.pkt_num = ngtcp2_pkt_adjust_pkt_num(pktns->acktr.max_pkt_num, hd.pkt_num, hd.pkt_numlen); if (hd.pkt_num > NGTCP2_MAX_PKT_NUM) { - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, - "pkn=%" PRId64 " is greater than maximum pkn", hd.pkt_num); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, "pkn=", hd.pkt_num, + " is greater than maximum pkn"); return NGTCP2_ERR_DISCARD_PKT; } @@ -9328,11 +9348,9 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_sockaddr_eq((const ngtcp2_sockaddr *)&conn->hs_local_addr, path->local.addr)) { ngtcp2_log_infof( - &conn->log, NGTCP2_LOG_EVENT_PKT, - "pkt=%" PRId64 + &conn->log, NGTCP2_LOG_EVENT_PKT, "pkt=", hd.pkt_num, " is discarded because it was received on handshake local " - "address after preferred address migration", - hd.pkt_num); + "address after preferred address migration"); return NGTCP2_ERR_DISCARD_PKT; } @@ -10012,8 +10030,8 @@ static int conn_recv_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path, ++conn->cstat.pkt_recv; conn->cstat.bytes_recv += (uint64_t)nread; - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, - "read packet %td left %zu", nread, pktlen); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, "read packet ", nread, + " left ", pktlen); } return 0; @@ -10186,8 +10204,7 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn, /* We have 1RTT packet and application rx key, but the handshake has not completed yet. */ ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "buffering 1RTT packet len=%zu", - pktlen - (size_t)nread); + "buffering 1RTT packet len=", pktlen - (size_t)nread); rv = conn_buffer_pkt(conn, &conn->pktns, path, pi, pkt + nread, pktlen - (size_t)nread, pktlen, ts); @@ -10266,8 +10283,8 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, conn_update_timestamp(conn, ts); - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu", - pktlen); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, + "recv packet len=", pktlen); if (pktlen == 0) { return 0; @@ -10401,9 +10418,9 @@ int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn, ngtcp2_tstamp ts) { * conn_check_pkt_num_exhausted returns nonzero if packet number is * exhausted in at least one of packet number space. */ -static int conn_check_pkt_num_exhausted(ngtcp2_conn *conn) { - ngtcp2_pktns *in_pktns = conn->in_pktns; - ngtcp2_pktns *hs_pktns = conn->hs_pktns; +static int conn_check_pkt_num_exhausted(const ngtcp2_conn *conn) { + const ngtcp2_pktns *in_pktns = conn->in_pktns; + const ngtcp2_pktns *hs_pktns = conn->hs_pktns; return (in_pktns && in_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) || (hs_pktns && hs_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) || @@ -10427,7 +10444,7 @@ conn_retransmit_retry_early(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, * packets to be sent for Initial or Handshake packet number space * left. */ -static int conn_handshake_probe_left(ngtcp2_conn *conn) { +static int conn_handshake_probe_left(const ngtcp2_conn *conn) { return (conn->in_pktns && conn->in_pktns->rtb.probe_pkt_left) || conn->hs_pktns->rtb.probe_pkt_left; } @@ -10438,7 +10455,8 @@ static int conn_handshake_probe_left(ngtcp2_conn *conn) { * are not reduced. This function is only used by client and should * only be called when early data is accepted by server. */ -static int conn_validate_early_transport_params_limits(ngtcp2_conn *conn) { +static int +conn_validate_early_transport_params_limits(const ngtcp2_conn *conn) { const ngtcp2_transport_params *params = conn->remote.transport_params; assert(!conn->server); @@ -10746,8 +10764,8 @@ conn_client_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt); send_stream = conn_retry_early_payloadlen(conn) == 0; if (send_stream) { - write_datalen = ngtcp2_min_uint64(datalen + NGTCP2_STREAM_OVERHEAD, - NGTCP2_MIN_COALESCED_PAYLOADLEN); + write_datalen = ngtcp2_min(datalen + NGTCP2_STREAM_OVERHEAD, + NGTCP2_MIN_COALESCED_PAYLOADLEN); if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) { wflags |= NGTCP2_WRITE_PKT_FLAG_MORE; @@ -10839,6 +10857,10 @@ void ngtcp2_conn_tls_handshake_completed(ngtcp2_conn *conn) { } int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn) { + return ngtcp2_conn_get_handshake_completed2(conn); +} + +int ngtcp2_conn_get_handshake_completed2(const ngtcp2_conn *conn) { return conn_is_tls_handshake_completed(conn) && (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED); } @@ -11198,7 +11220,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, static int conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_tstamp confirmed_ts = conn->crypto.key_update.confirmed_ts; - ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); + ngtcp2_duration pto = ngtcp2_conn_compute_pto(conn, &conn->pktns); assert(conn->state == NGTCP2_CS_POST_HANDSHAKE); @@ -11221,13 +11243,13 @@ int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return conn_initiate_key_update(conn, ts); } -ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(ngtcp2_conn *conn) { +ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(const ngtcp2_conn *conn) { return conn->cstat.loss_detection_timer; } -ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn) { +ngtcp2_tstamp ngtcp2_conn_internal_expiry(const ngtcp2_conn *conn) { ngtcp2_tstamp res = UINT64_MAX, ts; - ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); + ngtcp2_duration pto = ngtcp2_conn_compute_pto(conn, &conn->pktns); ngtcp2_scid *scid; if (conn->pv) { @@ -11235,38 +11257,38 @@ ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn) { } if (conn->pmtud) { - res = ngtcp2_min_uint64(res, conn->pmtud->expiry); + res = ngtcp2_min(res, conn->pmtud->expiry); } if (!ngtcp2_pq_empty(&conn->scid.used)) { scid = ngtcp2_struct_of(ngtcp2_pq_top(&conn->scid.used), ngtcp2_scid, pe); if (scid->retired_ts != UINT64_MAX) { - res = ngtcp2_min_uint64(res, scid->retired_ts + pto); + res = ngtcp2_min(res, scid->retired_ts + pto); } } ts = ngtcp2_dcidtr_earliest_retired_ts(&conn->dcid.dtr); if (ts != UINT64_MAX) { - res = ngtcp2_min_uint64(res, ts + pto); + res = ngtcp2_min(res, ts + pto); } if (conn->dcid.current.cid.datalen) { ts = ngtcp2_dcidtr_earliest_bound_ts(&conn->dcid.dtr); if (ts != UINT64_MAX) { - res = ngtcp2_min_uint64(res, ts + 3 * pto); + res = ngtcp2_min(res, ts + 3 * pto); } } if (conn->server && conn->early.ckm && conn->early.discard_started_ts != UINT64_MAX) { - res = ngtcp2_min_uint64(res, conn->early.discard_started_ts + 3 * pto); + res = ngtcp2_min(res, conn->early.discard_started_ts + 3 * pto); } return res; } -ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn) { - ngtcp2_acktr *acktr = &conn->pktns.acktr; +ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(const ngtcp2_conn *conn) { + const ngtcp2_acktr *acktr = &conn->pktns.acktr; if (!(acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) && acktr->first_unacked_ts != UINT64_MAX) { @@ -11275,7 +11297,7 @@ ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn) { return UINT64_MAX; } -static ngtcp2_tstamp conn_handshake_expiry(ngtcp2_conn *conn) { +static ngtcp2_tstamp conn_handshake_expiry(const ngtcp2_conn *conn) { if (conn_is_tls_handshake_completed(conn) || conn->local.settings.handshake_timeout == UINT64_MAX || conn->local.settings.initial_ts >= @@ -11288,14 +11310,18 @@ static ngtcp2_tstamp conn_handshake_expiry(ngtcp2_conn *conn) { } ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn) { - ngtcp2_tstamp res = ngtcp2_min_uint64(ngtcp2_conn_loss_detection_expiry(conn), - ngtcp2_conn_ack_delay_expiry(conn)); - res = ngtcp2_min_uint64(res, ngtcp2_conn_internal_expiry(conn)); - res = ngtcp2_min_uint64(res, ngtcp2_conn_lost_pkt_expiry(conn)); - res = ngtcp2_min_uint64(res, conn_keep_alive_expiry(conn)); - res = ngtcp2_min_uint64(res, conn_handshake_expiry(conn)); - res = ngtcp2_min_uint64(res, ngtcp2_conn_get_idle_expiry(conn)); - return ngtcp2_min_uint64(res, conn->tx.pacing.next_ts); + return ngtcp2_conn_get_expiry2(conn); +} + +ngtcp2_tstamp ngtcp2_conn_get_expiry2(const ngtcp2_conn *conn) { + ngtcp2_tstamp res = ngtcp2_min(ngtcp2_conn_loss_detection_expiry(conn), + ngtcp2_conn_ack_delay_expiry(conn)); + res = ngtcp2_min(res, ngtcp2_conn_internal_expiry(conn)); + res = ngtcp2_min(res, ngtcp2_conn_lost_pkt_expiry(conn)); + res = ngtcp2_min(res, conn_keep_alive_expiry(conn)); + res = ngtcp2_min(res, conn_handshake_expiry(conn)); + res = ngtcp2_min(res, ngtcp2_conn_get_idle_expiry(conn)); + return ngtcp2_min(res, conn->tx.pacing.next_ts); } int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { @@ -11304,7 +11330,7 @@ int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { conn_update_timestamp(conn, ts); - pto = conn_compute_pto(conn, &conn->pktns); + pto = ngtcp2_conn_compute_pto(conn, &conn->pktns); assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING)); @@ -11387,29 +11413,29 @@ void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn, acktr_cancel_expired_ack_delay_timer(&conn->pktns.acktr, ack_delay, ts); } -ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn) { +ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(const ngtcp2_conn *conn) { ngtcp2_tstamp res = UINT64_MAX, ts; if (conn->in_pktns) { ts = ngtcp2_rtb_lost_pkt_ts(&conn->in_pktns->rtb); if (ts != UINT64_MAX) { - ts += conn_compute_pto(conn, conn->in_pktns) * 3; - res = ngtcp2_min_uint64(res, ts); + ts += ngtcp2_conn_compute_pto(conn, conn->in_pktns) * 3; + res = ngtcp2_min(res, ts); } } if (conn->hs_pktns) { ts = ngtcp2_rtb_lost_pkt_ts(&conn->hs_pktns->rtb); if (ts != UINT64_MAX) { - ts += conn_compute_pto(conn, conn->hs_pktns) * 3; - res = ngtcp2_min_uint64(res, ts); + ts += ngtcp2_conn_compute_pto(conn, conn->hs_pktns) * 3; + res = ngtcp2_min(res, ts); } } ts = ngtcp2_rtb_lost_pkt_ts(&conn->pktns.rtb); if (ts != UINT64_MAX) { - ts += conn_compute_pto(conn, &conn->pktns) * 3; - res = ngtcp2_min_uint64(res, ts); + ts += ngtcp2_conn_compute_pto(conn, &conn->pktns) * 3; + res = ngtcp2_min(res, ts); } return res; @@ -11419,14 +11445,14 @@ void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_duration timeout; if (conn->in_pktns) { - timeout = conn_compute_pto(conn, conn->in_pktns) * 3; + timeout = ngtcp2_conn_compute_pto(conn, conn->in_pktns) * 3; ngtcp2_rtb_remove_expired_lost_pkt(&conn->in_pktns->rtb, timeout, ts); } if (conn->hs_pktns) { - timeout = conn_compute_pto(conn, conn->hs_pktns) * 3; + timeout = ngtcp2_conn_compute_pto(conn, conn->hs_pktns) * 3; ngtcp2_rtb_remove_expired_lost_pkt(&conn->hs_pktns->rtb, timeout, ts); } - timeout = conn_compute_pto(conn, &conn->pktns) * 3; + timeout = ngtcp2_conn_compute_pto(conn, &conn->pktns) * 3; ngtcp2_rtb_remove_expired_lost_pkt(&conn->pktns.rtb, timeout, ts); } @@ -11483,7 +11509,7 @@ static uint32_t select_preferred_version(const uint32_t *preferred_versions, * Validation against version negotiation parameters failed. */ static int -conn_client_validate_transport_params(ngtcp2_conn *conn, +conn_client_validate_transport_params(const ngtcp2_conn *conn, const ngtcp2_transport_params *params) { if (!params->original_dcid_present) { return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; @@ -11647,8 +11673,8 @@ int ngtcp2_conn_set_remote_transport_params( conn->negotiated_version; ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "the negotiated version is 0x%08x", - conn->negotiated_version); + "the negotiated version is 0x", + hexw(conn->negotiated_version, 8)); } else { rv = conn_client_validate_transport_params(conn, params); if (rv != 0) { @@ -11704,6 +11730,11 @@ int ngtcp2_conn_decode_and_set_remote_transport_params(ngtcp2_conn *conn, const ngtcp2_transport_params * ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn) { + return ngtcp2_conn_get_remote_transport_params2(conn); +} + +const ngtcp2_transport_params * +ngtcp2_conn_get_remote_transport_params2(const ngtcp2_conn *conn) { if (conn->remote.pending_transport_params) { return conn->remote.pending_transport_params; } @@ -11714,7 +11745,14 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn) { ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params(ngtcp2_conn *conn, uint8_t *dest, size_t destlen) { - ngtcp2_transport_params params, *src; + return ngtcp2_conn_encode_0rtt_transport_params2(conn, dest, destlen); +} + +ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params2(const ngtcp2_conn *conn, + uint8_t *dest, + size_t destlen) { + ngtcp2_transport_params params; + const ngtcp2_transport_params *src; if (conn->server) { src = &conn->local.transport_params; @@ -11787,14 +11825,14 @@ int ngtcp2_conn_set_0rtt_remote_transport_params( p->initial_max_data = params->initial_max_data; /* we might hit garbage, then set the sane default. */ p->active_connection_id_limit = - ngtcp2_max_uint64(NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT, - params->active_connection_id_limit); + ngtcp2_max(NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT, + params->active_connection_id_limit); p->max_datagram_frame_size = params->max_datagram_frame_size; /* we might hit garbage, then set the sane default. */ if (params->max_udp_payload_size) { - p->max_udp_payload_size = ngtcp2_max_uint64(NGTCP2_MAX_UDP_PAYLOAD_SIZE, - params->max_udp_payload_size); + p->max_udp_payload_size = + ngtcp2_max(NGTCP2_MAX_UDP_PAYLOAD_SIZE, params->max_udp_payload_size); } /* These parameters are treated specially. If server accepts early @@ -11895,12 +11933,23 @@ int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn) { const ngtcp2_transport_params * ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn) { + return ngtcp2_conn_get_local_transport_params2(conn); +} + +const ngtcp2_transport_params * +ngtcp2_conn_get_local_transport_params2(const ngtcp2_conn *conn) { return &conn->local.transport_params; } ngtcp2_ssize ngtcp2_conn_encode_local_transport_params(ngtcp2_conn *conn, uint8_t *dest, size_t destlen) { + return ngtcp2_conn_encode_local_transport_params2(conn, dest, destlen); +} + +ngtcp2_ssize ngtcp2_conn_encode_local_transport_params2(const ngtcp2_conn *conn, + uint8_t *dest, + size_t destlen) { return ngtcp2_transport_params_encode(dest, destlen, &conn->local.transport_params); } @@ -11910,7 +11959,7 @@ int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, int rv; ngtcp2_strm *strm; - if (ngtcp2_conn_get_streams_bidi_left(conn) == 0) { + if (ngtcp2_conn_get_streams_bidi_left2(conn) == 0) { return NGTCP2_ERR_STREAM_ID_BLOCKED; } @@ -11937,7 +11986,7 @@ int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, int64_t *pstream_id, int rv; ngtcp2_strm *strm; - if (ngtcp2_conn_get_streams_uni_left(conn) == 0) { + if (ngtcp2_conn_get_streams_uni_left2(conn) == 0) { return NGTCP2_ERR_STREAM_ID_BLOCKED; } @@ -11952,15 +12001,14 @@ int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, int64_t *pstream_id, ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm); return rv; } - ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_RD); - *pstream_id = conn->local.uni.next_stream_id; conn->local.uni.next_stream_id += 4; return 0; } -ngtcp2_strm *ngtcp2_conn_find_stream(ngtcp2_conn *conn, int64_t stream_id) { +ngtcp2_strm *ngtcp2_conn_find_stream(const ngtcp2_conn *conn, + int64_t stream_id) { return ngtcp2_map_find(&conn->strms, (uint64_t)stream_id); } @@ -12014,7 +12062,7 @@ conn_write_vmsg_wrapper(ngtcp2_conn *conn, ngtcp2_path *path, are not app-limited. */ !(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS)) { conn->rst.app_limited = - ngtcp2_max_uint64(conn->rst.delivered + cstat->bytes_in_flight, 1); + ngtcp2_max(conn->rst.delivered + cstat->bytes_in_flight, 1); } return nwrite; @@ -12243,7 +12291,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, return 0; } - origlen = (size_t)ngtcp2_min_uint64((uint64_t)origlen, server_tx_left); + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); } return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); @@ -12263,7 +12311,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, return 0; } - destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left); + destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); } if (conn->in_pktns) { @@ -12310,7 +12358,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, return 0; } - origlen = (size_t)ngtcp2_min_uint64((uint64_t)origlen, server_tx_left); + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); } return conn_write_ack_pkt(conn, pi, dest, origlen, NGTCP2_PKT_1RTT, ts); @@ -12399,8 +12447,8 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, if (conn->server && !(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); - origlen = (size_t)ngtcp2_min_uint64((uint64_t)origlen, server_tx_left); - destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left); + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); + destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); if (server_tx_left == 0 && conn->cstat.loss_detection_timer != UINT64_MAX) { @@ -12457,9 +12505,9 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } if (conn->pktns.rtb.probe_pkt_left) { - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_CON, - "transmit probe pkt left=%zu", - conn->pktns.rtb.probe_pkt_left); + ngtcp2_log_infof( + &conn->log, NGTCP2_LOG_EVENT_CON, + "transmit probe pkt left=", conn->pktns.rtb.probe_pkt_left); nwrite = conn_write_pkt(conn, pi, dest, destlen, (size_t)res, vmsg, NGTCP2_PKT_1RTT, wflags, ts); @@ -12608,7 +12656,7 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt( if (conn->server) { server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); - destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left); + destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); } if (conn->state == NGTCP2_CS_POST_HANDSHAKE || @@ -12670,7 +12718,7 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( if (conn->server) { server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); - destlen = (size_t)ngtcp2_min_uint64((uint64_t)destlen, server_tx_left); + destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); } if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)) { @@ -12688,7 +12736,7 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( if (conn->state != NGTCP2_CS_POST_HANDSHAKE && (!conn->server || !conn->pktns.crypto.tx.ckm)) { - return res; + goto fin; } assert(conn->pktns.crypto.tx.ckm); @@ -12714,6 +12762,7 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( return NGTCP2_ERR_NOBUF; } +fin: conn->state = NGTCP2_CS_CLOSING; return res; @@ -12806,10 +12855,18 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( } int ngtcp2_conn_in_closing_period(ngtcp2_conn *conn) { + return ngtcp2_conn_in_closing_period2(conn); +} + +int ngtcp2_conn_in_closing_period2(const ngtcp2_conn *conn) { return conn->state == NGTCP2_CS_CLOSING; } int ngtcp2_conn_in_draining_period(ngtcp2_conn *conn) { + return ngtcp2_conn_in_draining_period2(conn); +} + +int ngtcp2_conn_in_draining_period2(const ngtcp2_conn *conn) { return conn->state == NGTCP2_CS_DRAINING; } @@ -13009,7 +13066,7 @@ static int conn_extend_max_stream_offset(ngtcp2_conn *conn, ngtcp2_strm *strm, top = ngtcp2_conn_tx_strmq_top(conn); strm->cycle = top->cycle; } - strm->cycle = conn_tx_strmq_first_cycle(conn); + strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn); return ngtcp2_conn_tx_strmq_push(conn, strm); } @@ -13051,18 +13108,35 @@ void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, size_t n) { } const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn) { + return ngtcp2_conn_get_dcid2(conn); +} + +const ngtcp2_cid *ngtcp2_conn_get_dcid2(const ngtcp2_conn *conn) { return &conn->dcid.current.cid; } const ngtcp2_cid *ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn) { + return ngtcp2_conn_get_client_initial_dcid2(conn); +} + +const ngtcp2_cid * +ngtcp2_conn_get_client_initial_dcid2(const ngtcp2_conn *conn) { return &conn->rcid; } uint32_t ngtcp2_conn_get_client_chosen_version(ngtcp2_conn *conn) { + return ngtcp2_conn_get_client_chosen_version2(conn); +} + +uint32_t ngtcp2_conn_get_client_chosen_version2(const ngtcp2_conn *conn) { return conn->client_chosen_version; } uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn) { + return ngtcp2_conn_get_negotiated_version2(conn); +} + +uint32_t ngtcp2_conn_get_negotiated_version2(const ngtcp2_conn *conn) { return conn->negotiated_version; } @@ -13140,6 +13214,10 @@ int ngtcp2_conn_tls_early_data_rejected(ngtcp2_conn *conn) { } int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn) { + return ngtcp2_conn_get_tls_early_data_rejected2(conn); +} + +int ngtcp2_conn_get_tls_early_data_rejected2(const ngtcp2_conn *conn) { return (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) != 0; } @@ -13159,23 +13237,23 @@ void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, if (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) { assert(conn->remote.transport_params); - ack_delay = ngtcp2_min_uint64( - ack_delay, conn->remote.transport_params->max_ack_delay); + ack_delay = + ngtcp2_min(ack_delay, conn->remote.transport_params->max_ack_delay); } else if (ack_delay > 0 && rtt >= cstat->min_rtt && rtt < cstat->min_rtt + ack_delay) { /* Ignore RTT sample if adjusting ack_delay causes the sample less than min_rtt before handshake confirmation. */ ngtcp2_log_infof( &conn->log, NGTCP2_LOG_EVENT_LDC, - "ignore rtt sample because ack_delay is too large latest_rtt=%" PRIu64 - " min_rtt=%" PRIu64 " ack_delay=%" PRIu64, - rtt / NGTCP2_MILLISECONDS, cstat->min_rtt / NGTCP2_MILLISECONDS, - ack_delay / NGTCP2_MILLISECONDS); + "ignore rtt sample because ack_delay is too large latest_rtt=", + rtt / NGTCP2_MILLISECONDS, + " min_rtt=", cstat->min_rtt / NGTCP2_MILLISECONDS, + " ack_delay=", ack_delay / NGTCP2_MILLISECONDS); return; } cstat->latest_rtt = rtt; - cstat->min_rtt = ngtcp2_min_uint64(cstat->min_rtt, rtt); + cstat->min_rtt = ngtcp2_min(cstat->min_rtt, rtt); if (rtt >= cstat->min_rtt + ack_delay) { rtt -= ack_delay; @@ -13188,19 +13266,23 @@ void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, cstat->smoothed_rtt = (cstat->smoothed_rtt * 7 + rtt) / 8; } - ngtcp2_log_infof( - &conn->log, NGTCP2_LOG_EVENT_LDC, - "latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " smoothed_rtt=%" PRIu64 - " rttvar=%" PRIu64 " ack_delay=%" PRIu64, - cstat->latest_rtt / NGTCP2_MILLISECONDS, - cstat->min_rtt / NGTCP2_MILLISECONDS, - cstat->smoothed_rtt / NGTCP2_MILLISECONDS, - cstat->rttvar / NGTCP2_MILLISECONDS, ack_delay / NGTCP2_MILLISECONDS); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, + "latest_rtt=", cstat->latest_rtt / NGTCP2_MILLISECONDS, + " min_rtt=", cstat->min_rtt / NGTCP2_MILLISECONDS, + " smoothed_rtt=", cstat->smoothed_rtt / NGTCP2_MILLISECONDS, + " rttvar=", cstat->rttvar / NGTCP2_MILLISECONDS, + " ack_delay=", ack_delay / NGTCP2_MILLISECONDS); } void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn, int conn_info_version, ngtcp2_conn_info *cinfo) { + ngtcp2_conn_get_conn_info2_versioned(conn, conn_info_version, cinfo); +} + +void ngtcp2_conn_get_conn_info2_versioned(const ngtcp2_conn *conn, + int conn_info_version, + ngtcp2_conn_info *cinfo) { ngtcp2_conn_info_init_versioned(conn_info_version, cinfo, &conn->cstat); } @@ -13231,13 +13313,14 @@ static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn, } } -static ngtcp2_tstamp conn_get_earliest_pto_expiry(ngtcp2_conn *conn, +static ngtcp2_tstamp conn_get_earliest_pto_expiry(const ngtcp2_conn *conn, ngtcp2_tstamp ts) { - ngtcp2_pktns *const ns[] = {conn->in_pktns, conn->hs_pktns, &conn->pktns}; + const ngtcp2_pktns *const ns[] = {conn->in_pktns, conn->hs_pktns, + &conn->pktns}; size_t i; ngtcp2_tstamp earliest_ts = UINT64_MAX, t; - ngtcp2_conn_stat *cstat = &conn->cstat; - ngtcp2_tstamp *times = cstat->last_tx_pkt_ts; + const ngtcp2_conn_stat *cstat = &conn->cstat; + const ngtcp2_tstamp *times = cstat->last_tx_pkt_ts; ngtcp2_duration duration = compute_pto(cstat->smoothed_rtt, cstat->rttvar, /* max_ack_delay = */ 0) * (1ULL << cstat->pto_count); @@ -13284,9 +13367,8 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { cstat->loss_detection_timer = earliest_loss_time; ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, - "loss_detection_timer=%" PRIu64 - " nonzero crypto loss time", - cstat->loss_detection_timer); + "loss_detection_timer=", cstat->loss_detection_timer, + " nonzero crypto loss time"); return; } @@ -13311,8 +13393,8 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { cstat->loss_detection_timer > ts ? cstat->loss_detection_timer - ts : 0; ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, - "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64, - cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS); + "loss_detection_timer=", cstat->loss_detection_timer, + " timeout=", timeout / NGTCP2_MILLISECONDS); } void ngtcp2_conn_cancel_loss_detection_timer(ngtcp2_conn *conn) { @@ -13384,8 +13466,8 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ++cstat->pto_count; - ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu", - cstat->pto_count); + ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_LDC, + "pto_count=", cstat->pto_count); ngtcp2_conn_set_loss_detection_timer(conn, ts); @@ -13408,8 +13490,7 @@ static int conn_buffer_crypto_data(ngtcp2_conn *conn, const uint8_t **pdata, } if (!*pbufchain) { - rv = ngtcp2_buf_chain_new(pbufchain, ngtcp2_max_size(1024, datalen), - conn->mem); + rv = ngtcp2_buf_chain_new(pbufchain, ngtcp2_max(1024, datalen), conn->mem); if (rv != 0) { return rv; } @@ -13519,7 +13600,7 @@ int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm) { return ngtcp2_pq_push(&conn->tx.strmq, &strm->pe); } -static int conn_has_uncommitted_preferred_addr_cid(ngtcp2_conn *conn) { +static int conn_has_uncommitted_preferred_addr_cid(const ngtcp2_conn *conn) { return conn->server && !(conn->flags & NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED) && conn->oscid.datalen && @@ -13527,6 +13608,10 @@ static int conn_has_uncommitted_preferred_addr_cid(ngtcp2_conn *conn) { } size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest) { + return ngtcp2_conn_get_scid2(conn, dest); +} + +size_t ngtcp2_conn_get_scid2(const ngtcp2_conn *conn, ngtcp2_cid *dest) { ngtcp2_cid *origdest = dest; ngtcp2_ksl_it it; ngtcp2_scid *scid; @@ -13549,7 +13634,7 @@ size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest) { return (size_t)(dest - origdest); } -static size_t conn_get_num_active_dcid(ngtcp2_conn *conn) { +static size_t conn_get_num_active_dcid(const ngtcp2_conn *conn) { size_t n = 1; /* for conn->dcid.current */ ngtcp2_pv *pv = conn->pv; @@ -13579,10 +13664,10 @@ size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) { size_t n, i; if (!dest) { - return ngtcp2_conn_get_active_dcid2(conn, NULL); + return ngtcp2_conn_get_active_dcid3(conn, NULL); } - n = ngtcp2_conn_get_active_dcid2(conn, cid_tokens); + n = ngtcp2_conn_get_active_dcid3(conn, cid_tokens); for (i = 0; i < n; ++i) { dest[i].seq = cid_tokens[i].seq; @@ -13611,9 +13696,14 @@ static void copy_dcid_to_cid_token(ngtcp2_cid_token2 *dest, size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn, ngtcp2_cid_token2 *dest) { - ngtcp2_pv *pv = conn->pv; + return ngtcp2_conn_get_active_dcid3(conn, dest); +} + +size_t ngtcp2_conn_get_active_dcid3(const ngtcp2_conn *conn, + ngtcp2_cid_token2 *dest) { + const ngtcp2_pv *pv = conn->pv; ngtcp2_cid_token2 *orig = dest; - ngtcp2_dcid *dcid; + const ngtcp2_dcid *dcid; size_t len, i; if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { @@ -13667,16 +13757,28 @@ void ngtcp2_conn_set_path_user_data(ngtcp2_conn *conn, void *path_user_data) { } const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn) { + return ngtcp2_conn_get_path2(conn); +} + +const ngtcp2_path *ngtcp2_conn_get_path2(const ngtcp2_conn *conn) { return &conn->dcid.current.ps.path; } size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn) { + return ngtcp2_conn_get_max_tx_udp_payload_size2(conn); +} + +size_t ngtcp2_conn_get_max_tx_udp_payload_size2(const ngtcp2_conn *conn) { return conn->local.settings.max_tx_udp_payload_size; } size_t ngtcp2_conn_get_path_max_tx_udp_payload_size(ngtcp2_conn *conn) { + return ngtcp2_conn_get_path_max_tx_udp_payload_size2(conn); +} + +size_t ngtcp2_conn_get_path_max_tx_udp_payload_size2(const ngtcp2_conn *conn) { if (conn->local.settings.no_tx_udp_payload_size_shaping) { - return ngtcp2_conn_get_max_tx_udp_payload_size(conn); + return ngtcp2_conn_get_max_tx_udp_payload_size2(conn); } return conn->dcid.current.max_udp_payload_size; @@ -13823,12 +13925,21 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, } uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) { + return ngtcp2_conn_get_max_data_left2(conn); +} + +uint64_t ngtcp2_conn_get_max_data_left2(const ngtcp2_conn *conn) { return conn->tx.max_offset - conn->tx.offset; } uint64_t ngtcp2_conn_get_max_stream_data_left(ngtcp2_conn *conn, int64_t stream_id) { - ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); + return ngtcp2_conn_get_max_stream_data_left2(conn, stream_id); +} + +uint64_t ngtcp2_conn_get_max_stream_data_left2(const ngtcp2_conn *conn, + int64_t stream_id) { + const ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { return 0; @@ -13838,6 +13949,10 @@ uint64_t ngtcp2_conn_get_max_stream_data_left(ngtcp2_conn *conn, } uint64_t ngtcp2_conn_get_streams_bidi_left(ngtcp2_conn *conn) { + return ngtcp2_conn_get_streams_bidi_left2(conn); +} + +uint64_t ngtcp2_conn_get_streams_bidi_left2(const ngtcp2_conn *conn) { uint64_t n = ngtcp2_ord_stream_id(conn->local.bidi.next_stream_id); return n > conn->local.bidi.max_streams @@ -13846,6 +13961,10 @@ uint64_t ngtcp2_conn_get_streams_bidi_left(ngtcp2_conn *conn) { } uint64_t ngtcp2_conn_get_streams_uni_left(ngtcp2_conn *conn) { + return ngtcp2_conn_get_streams_uni_left2(conn); +} + +uint64_t ngtcp2_conn_get_streams_uni_left2(const ngtcp2_conn *conn) { uint64_t n = ngtcp2_ord_stream_id(conn->local.uni.next_stream_id); return n > conn->local.uni.max_streams ? 0 @@ -13853,6 +13972,10 @@ uint64_t ngtcp2_conn_get_streams_uni_left(ngtcp2_conn *conn) { } uint64_t ngtcp2_conn_get_cwnd_left(ngtcp2_conn *conn) { + return ngtcp2_conn_get_cwnd_left2(conn); +} + +uint64_t ngtcp2_conn_get_cwnd_left2(const ngtcp2_conn *conn) { uint64_t bytes_in_flight = conn->cstat.bytes_in_flight; uint64_t cwnd = conn->cstat.cwnd; @@ -13863,7 +13986,7 @@ uint64_t ngtcp2_conn_get_cwnd_left(ngtcp2_conn *conn) { return 0; } -ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { +ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(const ngtcp2_conn *conn) { ngtcp2_duration trpto; ngtcp2_duration idle_timeout; @@ -13884,11 +14007,11 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { return UINT64_MAX; } - trpto = 3 * conn_compute_pto(conn, conn_is_tls_handshake_completed(conn) - ? &conn->pktns - : conn->hs_pktns); + trpto = 3 * ngtcp2_conn_compute_pto( + conn, conn_is_tls_handshake_completed(conn) ? &conn->pktns + : conn->hs_pktns); - idle_timeout = ngtcp2_max_uint64(idle_timeout, trpto); + idle_timeout = ngtcp2_max(idle_timeout, trpto); if (conn->idle_ts >= UINT64_MAX - idle_timeout) { return UINT64_MAX; @@ -13898,9 +14021,13 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { } ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn) { - return conn_compute_pto(conn, conn_is_tls_handshake_completed(conn) - ? &conn->pktns - : conn->hs_pktns); + return ngtcp2_conn_get_pto2(conn); +} + +ngtcp2_duration ngtcp2_conn_get_pto2(const ngtcp2_conn *conn) { + return ngtcp2_conn_compute_pto(conn, conn_is_tls_handshake_completed(conn) + ? &conn->pktns + : conn->hs_pktns); } void ngtcp2_conn_set_initial_crypto_ctx(ngtcp2_conn *conn, @@ -13910,6 +14037,11 @@ void ngtcp2_conn_set_initial_crypto_ctx(ngtcp2_conn *conn, } const ngtcp2_crypto_ctx *ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn) { + return ngtcp2_conn_get_initial_crypto_ctx2(conn); +} + +const ngtcp2_crypto_ctx * +ngtcp2_conn_get_initial_crypto_ctx2(const ngtcp2_conn *conn) { assert(conn->in_pktns); return &conn->in_pktns->crypto.ctx; } @@ -13931,6 +14063,10 @@ void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn, } const ngtcp2_crypto_ctx *ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn) { + return ngtcp2_conn_get_crypto_ctx2(conn); +} + +const ngtcp2_crypto_ctx *ngtcp2_conn_get_crypto_ctx2(const ngtcp2_conn *conn) { return &conn->pktns.crypto.ctx; } @@ -13940,10 +14076,19 @@ void ngtcp2_conn_set_0rtt_crypto_ctx(ngtcp2_conn *conn, } const ngtcp2_crypto_ctx *ngtcp2_conn_get_0rtt_crypto_ctx(ngtcp2_conn *conn) { + return ngtcp2_conn_get_0rtt_crypto_ctx2(conn); +} + +const ngtcp2_crypto_ctx * +ngtcp2_conn_get_0rtt_crypto_ctx2(const ngtcp2_conn *conn) { return &conn->early.ctx; } void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn) { + return ngtcp2_conn_get_tls_native_handle2(conn); +} + +void *ngtcp2_conn_get_tls_native_handle2(const ngtcp2_conn *conn) { return conn->crypto.tls_native_handle; } @@ -13953,6 +14098,10 @@ void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, } const ngtcp2_ccerr *ngtcp2_conn_get_ccerr(ngtcp2_conn *conn) { + return ngtcp2_conn_get_ccerr2(conn); +} + +const ngtcp2_ccerr *ngtcp2_conn_get_ccerr2(const ngtcp2_conn *conn) { return &conn->rx.ccerr; } @@ -13961,6 +14110,10 @@ void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr) { } int ngtcp2_conn_get_tls_error(ngtcp2_conn *conn) { + return ngtcp2_conn_get_tls_error2(conn); +} + +int ngtcp2_conn_get_tls_error2(const ngtcp2_conn *conn) { return conn->crypto.tls_error; } @@ -13969,16 +14122,32 @@ void ngtcp2_conn_set_tls_alert(ngtcp2_conn *conn, uint8_t alert) { } uint8_t ngtcp2_conn_get_tls_alert(ngtcp2_conn *conn) { + return ngtcp2_conn_get_tls_alert2(conn); +} + +uint8_t ngtcp2_conn_get_tls_alert2(const ngtcp2_conn *conn) { return conn->crypto.tls_alert; } int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id) { + return ngtcp2_conn_is_local_stream2(conn, stream_id); +} + +int ngtcp2_conn_is_local_stream2(const ngtcp2_conn *conn, int64_t stream_id) { return conn_local_stream(conn, stream_id); } -int ngtcp2_conn_is_server(ngtcp2_conn *conn) { return conn->server; } +int ngtcp2_conn_is_server(ngtcp2_conn *conn) { + return ngtcp2_conn_is_server2(conn); +} + +int ngtcp2_conn_is_server2(const ngtcp2_conn *conn) { return conn->server; } int ngtcp2_conn_after_retry(ngtcp2_conn *conn) { + return ngtcp2_conn_after_retry2(conn); +} + +int ngtcp2_conn_after_retry2(const ngtcp2_conn *conn) { return (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) != 0; } @@ -13996,7 +14165,12 @@ int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, int64_t stream_id, } void *ngtcp2_conn_get_stream_user_data(ngtcp2_conn *conn, int64_t stream_id) { - ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); + return ngtcp2_conn_get_stream_user_data2(conn, stream_id); +} + +void *ngtcp2_conn_get_stream_user_data2(const ngtcp2_conn *conn, + int64_t stream_id) { + const ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { return NULL; @@ -14018,7 +14192,7 @@ void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) { conn->cstat.pacing_interval_m) >> 10); - d = ngtcp2_min_uint64(wait / 2, conn->tx.pacing.compensation); + d = ngtcp2_min(wait / 2, conn->tx.pacing.compensation); wait -= d; conn->tx.pacing.compensation -= d; @@ -14027,11 +14201,20 @@ void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn) { + return ngtcp2_conn_get_send_quantum2(conn); +} + +size_t ngtcp2_conn_get_send_quantum2(const ngtcp2_conn *conn) { return conn->cstat.send_quantum; } size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, int64_t stream_id) { - ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); + return ngtcp2_conn_get_stream_loss_count2(conn, stream_id); +} + +size_t ngtcp2_conn_get_stream_loss_count2(const ngtcp2_conn *conn, + int64_t stream_id) { + const ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { return 0; @@ -14056,7 +14239,7 @@ ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned( ngtcp2_write_pkt write_pkt, ngtcp2_tstamp ts) { ngtcp2_ssize nwrite; - buflen = ngtcp2_min_size(buflen, ngtcp2_conn_get_send_quantum(conn)); + buflen = ngtcp2_min(buflen, ngtcp2_conn_get_send_quantum2(conn)); nwrite = ngtcp2_conn_write_aggregate_pkt2_versioned( conn, path, pkt_info_version, pi, buf, buflen, pgsolen, write_pkt, 0, ts); @@ -14073,9 +14256,9 @@ ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen, ngtcp2_write_pkt write_pkt, size_t num_pkts, ngtcp2_tstamp ts) { - size_t max_udp_payloadlen = ngtcp2_conn_get_max_tx_udp_payload_size(conn); + size_t max_udp_payloadlen = ngtcp2_conn_get_max_tx_udp_payload_size2(conn); size_t path_max_udp_payloadlen = - ngtcp2_conn_get_path_max_tx_udp_payload_size(conn); + ngtcp2_conn_get_path_max_tx_udp_payload_size2(conn); ngtcp2_ssize nwrite; uint8_t *wbuf = buf; size_t wbuflen; @@ -14160,9 +14343,9 @@ ngtcp2_tstamp ngtcp2_conn_get_timestamp(const ngtcp2_conn *conn) { } const ngtcp2_path_history_entry * -ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path, +ngtcp2_conn_find_path_history(const ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_tstamp ts) { - ngtcp2_ringbuf *rb = &conn->path_history.rb; + const ngtcp2_ringbuf *rb = &conn->path_history.rb; size_t i, len = ngtcp2_ringbuf_len(rb); ngtcp2_path_history_entry *ent; @@ -14229,10 +14412,6 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close( return rv; } - if (!ngtcp2_ppe_ensure_hp_sample(&ppe)) { - return NGTCP2_ERR_NOBUF; - } - fr.connection_close = (ngtcp2_connection_close){ .type = NGTCP2_FRAME_CONNECTION_CLOSE, .error_code = error_code, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h index 47175736d422c7..548c296e8ae1d0 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h @@ -702,7 +702,8 @@ typedef struct ngtcp2_vmsg { * ngtcp2_conn_find_stream returns a stream whose stream ID is * |stream_id|. If no such stream is found, it returns NULL. */ -ngtcp2_strm *ngtcp2_conn_find_stream(ngtcp2_conn *conn, int64_t stream_id); +ngtcp2_strm *ngtcp2_conn_find_stream(const ngtcp2_conn *conn, + int64_t stream_id); /* * conn_init_stream initializes |strm|. Its stream ID is |stream_id|. @@ -804,7 +805,7 @@ int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm); * ngtcp2_conn_internal_expiry returns the minimum expiry time among * all timers in |conn|. */ -ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn); +ngtcp2_tstamp ngtcp2_conn_internal_expiry(const ngtcp2_conn *conn); ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, @@ -853,14 +854,14 @@ int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn); * ngtcp2_conn_lost_pkt_expiry returns the earliest expiry time of * lost packet. */ -ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn); +ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(const ngtcp2_conn *conn); /* * ngtcp2_conn_remove_lost_pkt removes the expired lost packet. */ void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts); -uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn); +uint64_t ngtcp2_conn_tx_strmq_first_cycle(const ngtcp2_conn *conn); /** * @function @@ -871,7 +872,7 @@ uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn); * `ngtcp2_conn_write_pkt` (or `ngtcp2_conn_writev_stream`) when it * expires. It returns UINT64_MAX if there is no expiry. */ -ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn); +ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(const ngtcp2_conn *conn); /** * @function @@ -892,7 +893,7 @@ void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn, * (or `ngtcp2_conn_writev_stream`) when it expires. It returns * UINT64_MAX if loss detection timer is not armed. */ -ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(ngtcp2_conn *conn); +ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(const ngtcp2_conn *conn); /** * @function @@ -901,34 +902,13 @@ ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(ngtcp2_conn *conn); * should be closed if it continues to be idle. If idle timeout is * disabled, this function returns ``UINT64_MAX``. */ -ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn); - -ngtcp2_duration ngtcp2_conn_compute_pto(ngtcp2_conn *conn, ngtcp2_pktns *pktns); - -/* - * ngtcp2_conn_track_retired_dcid_seq tracks the sequence number |seq| - * of unacknowledged retiring Destination Connection ID. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_CONNECTION_ID_LIMIT - * The number of unacknowledged retirement exceeds the limit. - */ -int ngtcp2_conn_track_retired_dcid_seq(ngtcp2_conn *conn, uint64_t seq); - -/* - * ngtcp2_conn_untrack_retired_dcid_seq deletes the sequence number - * |seq| of unacknowledged retiring Destination Connection ID. It is - * fine if such sequence number is not found. - */ -void ngtcp2_conn_untrack_retired_dcid_seq(ngtcp2_conn *conn, uint64_t seq); +ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(const ngtcp2_conn *conn); /* - * ngtcp2_conn_check_retired_dcid_tracked returns nonzero if |seq| has - * already been tracked. + * ngtcp2_conn_compute_pto computes the current PTO. */ -int ngtcp2_conn_check_retired_dcid_tracked(ngtcp2_conn *conn, uint64_t seq); +ngtcp2_duration ngtcp2_conn_compute_pto(const ngtcp2_conn *conn, + const ngtcp2_pktns *pktns); /* * ngtcp2_conn_server_negotiate_version negotiates QUIC version. It @@ -1107,7 +1087,7 @@ void ngtcp2_conn_add_path_history(ngtcp2_conn *conn, const ngtcp2_dcid *dcid, ngtcp2_tstamp ts); const ngtcp2_path_history_entry * -ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path, +ngtcp2_conn_find_path_history(const ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_tstamp ts); #endif /* !defined(NGTCP2_CONN_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c index a0cef0c8643a6e..42651cddbbaa9c 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c @@ -62,7 +62,7 @@ const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p) { return p + sizeof(*dest); } -static const uint8_t *get_uvarint(uint64_t *dest, const uint8_t *p) { +const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p) { uint16_t n16; uint32_t n32; uint64_t n64; @@ -74,21 +74,21 @@ static const uint8_t *get_uvarint(uint64_t *dest, const uint8_t *p) { case 1: memcpy(&n16, p, 2); n16 = ngtcp2_ntohs(n16); - n16 &= 0x3FFF; + n16 &= 0x3FFFU; *dest = n16; return p + 2; case 2: memcpy(&n32, p, 4); n32 = ngtcp2_ntohl(n32); - n32 &= 0x3FFFFFFF; + n32 &= 0x3FFFFFFFU; *dest = n32; return p + 4; case 3: memcpy(&n64, p, 8); n64 = ngtcp2_ntohl64(n64); - n64 &= 0x3FFFFFFFFFFFFFFF; + n64 &= 0x3FFFFFFFFFFFFFFFU; *dest = n64; return p + 8; @@ -97,14 +97,6 @@ static const uint8_t *get_uvarint(uint64_t *dest, const uint8_t *p) { } } -const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p) { - return get_uvarint(dest, p); -} - -const uint8_t *ngtcp2_get_varint(int64_t *dest, const uint8_t *p) { - return get_uvarint((uint64_t *)dest, p); -} - int64_t ngtcp2_get_pkt_num(const uint8_t *p, size_t pkt_numlen) { uint32_t l; uint16_t s; @@ -158,17 +150,17 @@ uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n) { } if (n < 16384) { rv = ngtcp2_put_uint16be(p, (uint16_t)n); - *p |= 0x40; + *p |= 0x40U; return rv; } if (n < 1073741824) { rv = ngtcp2_put_uint32be(p, (uint32_t)n); - *p |= 0x80; + *p |= 0x80U; return rv; } assert(n < 4611686018427387904ULL); rv = ngtcp2_put_uint64be(p, n); - *p |= 0xC0; + *p |= 0xC0U; return rv; } @@ -178,7 +170,7 @@ uint8_t *ngtcp2_put_uvarint30(uint8_t *p, uint32_t n) { assert(n < 1073741824); rv = ngtcp2_put_uint32be(p, n); - *p |= 0x80; + *p |= 0x80U; return rv; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h index ad924683b8dc10..7e7b9f465c5118 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h @@ -80,7 +80,15 @@ const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p); * lost in this cast, because the variable-length integer is 62 * bits. It returns |p| plus the number of bytes read from |p|. */ -const uint8_t *ngtcp2_get_varint(int64_t *dest, const uint8_t *p); +static inline const uint8_t *ngtcp2_get_varint(int64_t *dest, + const uint8_t *p) { + uint64_t n; + + p = ngtcp2_get_uvarint(&n, p); + *dest = (int64_t)n; + + return p; +} /* * ngtcp2_get_pkt_num reads encoded packet number from |p|. The diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c index 078568fde3b09e..f435870ba47d18 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c @@ -28,6 +28,7 @@ #include #include "ngtcp2_net.h" +#include "ngtcp2_str.h" int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret, size_t secretlen, @@ -90,13 +91,7 @@ void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem) { } if (ckm->secret.len) { -#ifdef WIN32 - SecureZeroMemory(ckm->secret.base, ckm->secret.len); -#elif defined(HAVE_EXPLICIT_BZERO) - explicit_bzero(ckm->secret.base, ckm->secret.len); -#elif defined(HAVE_MEMSET_S) - memset_s(ckm->secret.base, ckm->secret.len, 0, ckm->secret.len); -#endif /* defined(HAVE_MEMSET_S) */ + ngtcp2_secure_clear(ckm->secret.base, ckm->secret.len); } ngtcp2_mem_free(mem, ckm); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c index a312398bbfaf97..0360ba82cbd896 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c @@ -386,7 +386,7 @@ ngtcp2_tstamp ngtcp2_dcidtr_earliest_bound_ts(const ngtcp2_dcidtr *dtr) { assert(dcid->cid.datalen); assert(dcid->bound_ts != UINT64_MAX); - res = ngtcp2_min_uint64(res, dcid->bound_ts); + res = ngtcp2_min(res, dcid->bound_ts); } return res; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.c new file mode 100644 index 00000000000000..63899f7e03932b --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.c @@ -0,0 +1,112 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ngtcp2_fmt.h" + +#include + +#include "ngtcp2_str.h" + +char *ngtcp2_fmt_write_int64(char *dest, int64_t n) { + if (n < 0) { + *dest++ = '-'; + return ngtcp2_fmt_write_uint64(dest, 0 - (uint64_t)n); + } + + return ngtcp2_fmt_write_uint64(dest, (uint64_t)n); +} + +char *ngtcp2_fmt_write_uint64(char *dest, uint64_t n) { + return (char *)ngtcp2_encode_uint((uint8_t *)dest, n); +} + +char *ngtcp2_fmt_write_char(char *dest, char c) { + *dest++ = c; + + return dest; +} + +char *ngtcp2_fmt_write_str(char *dest, const char *s) { + return ngtcp2_cpymem(dest, s, strlen(s)); +} + +static char *fill_zero(char *dest, size_t len, size_t width) { + if (len < width) { + return (char *)ngtcp2_setmem((uint8_t *)dest, '0', width - len); + } + + return dest; +} + +char *ngtcp2_fmt_write_uint64w(char *dest, ngtcp2_fmt_uint64w f) { + size_t len = ngtcp2_encode_uintlen(f.n); + + return (char *)ngtcp2_encode_uint((uint8_t *)fill_zero(dest, len, f.width), + f.n); +} + +char *ngtcp2_fmt_write_hex(char *dest, ngtcp2_fmt_hex f) { + return (char *)ngtcp2_encode_uint_hex((uint8_t *)dest, f.n); +} + +char *ngtcp2_fmt_write_hexw(char *dest, ngtcp2_fmt_hexw f) { + size_t len = ngtcp2_encode_uint_hexlen(f.n); + + return (char *)ngtcp2_encode_uint_hex( + (uint8_t *)fill_zero(dest, len, f.width), f.n); +} + +char *ngtcp2_fmt_write_cid(char *dest, const ngtcp2_cid *cid) { + return (char *)ngtcp2_encode_hex((uint8_t *)dest, cid->data, cid->datalen); +} + +char *ngtcp2_fmt_write_stateless_reset_token( + char *dest, const ngtcp2_stateless_reset_token *token) { + return (char *)ngtcp2_encode_hex((uint8_t *)dest, token->data, + sizeof(token->data)); +} + +char * +ngtcp2_fmt_write_path_challenge_data(char *dest, + const ngtcp2_path_challenge_data *data) { + return (char *)ngtcp2_encode_hex((uint8_t *)dest, data->data, + sizeof(data->data)); +} + +char *ngtcp2_fmt_write_bhex(char *dest, ngtcp2_fmt_bhex f) { + return (char *)ngtcp2_encode_hex((uint8_t *)dest, f.data, f.len); +} + +char *ngtcp2_fmt_write_in_addr(char *dest, const ngtcp2_in_addr *addr) { + return (char *)ngtcp2_encode_ipv4((uint8_t *)dest, addr); +} + +char *ngtcp2_fmt_write_in6_addr(char *dest, const ngtcp2_in6_addr *addr) { + return (char *)ngtcp2_encode_ipv6((uint8_t *)dest, addr); +} + +char *ngtcp2_fmt_write_printable_ascii(char *dest, + const ngtcp2_fmt_printable_ascii f) { + return (char *)ngtcp2_encode_printable_ascii((uint8_t *)dest, f.data, f.len); +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.h new file mode 100644 index 00000000000000..9d01ffc80b903f --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_fmt.h @@ -0,0 +1,1211 @@ +/* + * ngtcp2 + * + * Copyright (c) 2026 ngtcp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGTCP2_FMT_H +#define NGTCP2_FMT_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* defined(HAVE_CONFIG_H) */ + +#include + +typedef struct ngtcp2_fmt_hex { + uint64_t n; +} ngtcp2_fmt_hex; + +static inline ngtcp2_fmt_hex ngtcp2_fmt_hex_init(uint64_t n) { + return (ngtcp2_fmt_hex){ + .n = n, + }; +} + +static inline ngtcp2_fmt_hex ngtcp2_fmt_hex_signed_init(int64_t n) { + return ngtcp2_fmt_hex_init((uint64_t)n); +} + +static inline ngtcp2_fmt_hex ngtcp2_fmt_hex_long_int_init(long int n) { + return ngtcp2_fmt_hex_init((unsigned long int)n); +} + +static inline ngtcp2_fmt_hex ngtcp2_fmt_hex_int_init(int n) { + return ngtcp2_fmt_hex_init((unsigned int)n); +} + +static inline ngtcp2_fmt_hex ngtcp2_fmt_hex_short_int_init(short int n) { + return ngtcp2_fmt_hex_init((unsigned short int)n); +} + +static inline ngtcp2_fmt_hex ngtcp2_fmt_hex_signed_char_init(signed char n) { + return ngtcp2_fmt_hex_init((unsigned char)n); +} + +static inline ngtcp2_fmt_hex ngtcp2_fmt_hex_char_init(char n) { + return ngtcp2_fmt_hex_init((unsigned char)n); +} + +/* hex formats integral |T| in unsigned hexadecimal notation. It + drops the leading zeros. */ +#define hex(T) \ + _Generic((T), \ + long long int: ngtcp2_fmt_hex_signed_init, \ + long int: ngtcp2_fmt_hex_long_int_init, \ + int: ngtcp2_fmt_hex_int_init, \ + short int: ngtcp2_fmt_hex_short_int_init, \ + signed char: ngtcp2_fmt_hex_signed_char_init, \ + char: ngtcp2_fmt_hex_char_init, \ + unsigned long long int: ngtcp2_fmt_hex_init, \ + unsigned long int: ngtcp2_fmt_hex_init, \ + unsigned int: ngtcp2_fmt_hex_init, \ + unsigned short int: ngtcp2_fmt_hex_init, \ + unsigned char: ngtcp2_fmt_hex_init)((T)) + +typedef struct ngtcp2_fmt_hexw { + uint64_t n; + size_t width; +} ngtcp2_fmt_hexw; + +static inline ngtcp2_fmt_hexw ngtcp2_fmt_hexw_init(uint64_t n, size_t width) { + return (ngtcp2_fmt_hexw){ + .n = n, + .width = width, + }; +} + +static inline ngtcp2_fmt_hexw ngtcp2_fmt_hexw_signed_init(int64_t n, + size_t width) { + return ngtcp2_fmt_hexw_init((uint64_t)n, width); +} + +static inline ngtcp2_fmt_hexw ngtcp2_fmt_hexw_long_int_init(long int n, + size_t width) { + return ngtcp2_fmt_hexw_init((unsigned long int)n, width); +} + +static inline ngtcp2_fmt_hexw ngtcp2_fmt_hexw_int_init(int n, size_t width) { + return ngtcp2_fmt_hexw_init((unsigned int)n, width); +} + +static inline ngtcp2_fmt_hexw ngtcp2_fmt_hexw_short_int_init(short int n, + size_t width) { + return ngtcp2_fmt_hexw_init((unsigned short int)n, width); +} + +static inline ngtcp2_fmt_hexw ngtcp2_fmt_hexw_signed_char_init(signed char n, + size_t width) { + return ngtcp2_fmt_hexw_init((unsigned char)n, width); +} + +static inline ngtcp2_fmt_hexw ngtcp2_fmt_hexw_char_init(char n, size_t width) { + return ngtcp2_fmt_hexw_init((unsigned char)n, width); +} + +/* hex formats integral |T| in unsigned hexadecimal notation. If the + produced value has fewer characters than |WIDTH|, it will be padded + with 0 on the left. */ +#define hexw(T, WIDTH) \ + _Generic((T), \ + long long int: ngtcp2_fmt_hexw_signed_init, \ + long int: ngtcp2_fmt_hexw_long_int_init, \ + int: ngtcp2_fmt_hexw_int_init, \ + short int: ngtcp2_fmt_hexw_short_int_init, \ + signed char: ngtcp2_fmt_hexw_signed_char_init, \ + char: ngtcp2_fmt_hexw_char_init, \ + unsigned long long int: ngtcp2_fmt_hexw_init, \ + unsigned long int: ngtcp2_fmt_hexw_init, \ + unsigned int: ngtcp2_fmt_hexw_init, \ + unsigned short int: ngtcp2_fmt_hexw_init, \ + unsigned char: ngtcp2_fmt_hexw_init)((T), (WIDTH)) + +typedef struct ngtcp2_fmt_uint64w { + uint64_t n; + size_t width; +} ngtcp2_fmt_uint64w; + +/* uintw formats integral |n|. If the produced value has fewer + characters than |width|, it will be padded with 0 on the left. */ +static inline ngtcp2_fmt_uint64w uintw(uint64_t n, size_t width) { + return (ngtcp2_fmt_uint64w){ + .n = n, + .width = width, + }; +} + +typedef struct ngtcp2_fmt_bhex { + const uint8_t *data; + size_t len; +} ngtcp2_fmt_bhex; + +/* bhex formats the binary data [|data|, |data| + |len|) in + hexadecimal notation. */ +static inline ngtcp2_fmt_bhex bhex(const uint8_t *data, size_t len) { + return (ngtcp2_fmt_bhex){ + .data = data, + .len = len, + }; +} + +/* lbhex formats the binary data [|B|, |B| + sizeof(|B|)) in + hexadecimal notation. To make it work, |B| must be an array that + is not decayed to the pointer. */ +#define lbhex(B) bhex((B), sizeof(B)) + +typedef struct ngtcp2_fmt_printable_ascii { + const uint8_t *data; + size_t len; +} ngtcp2_fmt_printable_ascii; + +/* ascii formats the binary data [|data|, |data| + |len|) in such a + way that the printable ASCII characters are copied as is, and the + other characters are converted to '.'. */ +static inline ngtcp2_fmt_printable_ascii ascii(const uint8_t *data, + size_t len) { + return (ngtcp2_fmt_printable_ascii){ + .data = data, + .len = len, + }; +} + +#define ngtcp2_fmt_stringify(M) #M + +/* stringify converts macro |M| to string literal.*/ +#define stringify(M) ngtcp2_fmt_stringify(M) + +char *ngtcp2_fmt_write_int64(char *dest, int64_t n); +char *ngtcp2_fmt_write_uint64(char *dest, uint64_t n); +char *ngtcp2_fmt_write_char(char *dest, char c); +char *ngtcp2_fmt_write_str(char *dest, const char *s); +char *ngtcp2_fmt_write_uint64w(char *dest, ngtcp2_fmt_uint64w f); +char *ngtcp2_fmt_write_hex(char *dest, ngtcp2_fmt_hex f); +char *ngtcp2_fmt_write_hexw(char *dest, ngtcp2_fmt_hexw f); +char *ngtcp2_fmt_write_cid(char *dest, const ngtcp2_cid *cid); +char *ngtcp2_fmt_write_stateless_reset_token( + char *dest, const ngtcp2_stateless_reset_token *token); +char * +ngtcp2_fmt_write_path_challenge_data(char *dest, + const ngtcp2_path_challenge_data *data); +char *ngtcp2_fmt_write_bhex(char *dest, ngtcp2_fmt_bhex f); +char *ngtcp2_fmt_write_in_addr(char *dest, const ngtcp2_in_addr *addr); +char *ngtcp2_fmt_write_in6_addr(char *dest, const ngtcp2_in6_addr *addr); +char *ngtcp2_fmt_write_printable_ascii(char *dest, + const ngtcp2_fmt_printable_ascii f); + +#define NGTCP2_FMT_WRITE_TYPE(DEST, T) \ + _Generic((T), \ + long long int: ngtcp2_fmt_write_int64, \ + long int: ngtcp2_fmt_write_int64, \ + int: ngtcp2_fmt_write_int64, \ + short int: ngtcp2_fmt_write_int64, \ + signed char: ngtcp2_fmt_write_int64, \ + char: ngtcp2_fmt_write_char, \ + unsigned long long int: ngtcp2_fmt_write_uint64, \ + unsigned long int: ngtcp2_fmt_write_uint64, \ + unsigned int: ngtcp2_fmt_write_uint64, \ + unsigned short int: ngtcp2_fmt_write_uint64, \ + unsigned char: ngtcp2_fmt_write_uint64, \ + char *: ngtcp2_fmt_write_str, \ + const char *: ngtcp2_fmt_write_str, \ + ngtcp2_cid *: ngtcp2_fmt_write_cid, \ + const ngtcp2_cid *: ngtcp2_fmt_write_cid, \ + ngtcp2_stateless_reset_token *: ngtcp2_fmt_write_stateless_reset_token, \ + const ngtcp2_stateless_reset_token \ + *: ngtcp2_fmt_write_stateless_reset_token, \ + ngtcp2_path_challenge_data *: ngtcp2_fmt_write_path_challenge_data, \ + const ngtcp2_path_challenge_data *: ngtcp2_fmt_write_path_challenge_data, \ + ngtcp2_in_addr *: ngtcp2_fmt_write_in_addr, \ + const ngtcp2_in_addr *: ngtcp2_fmt_write_in_addr, \ + ngtcp2_in6_addr *: ngtcp2_fmt_write_in6_addr, \ + const ngtcp2_in6_addr *: ngtcp2_fmt_write_in6_addr, \ + ngtcp2_fmt_uint64w: ngtcp2_fmt_write_uint64w, \ + ngtcp2_fmt_hex: ngtcp2_fmt_write_hex, \ + ngtcp2_fmt_hexw: ngtcp2_fmt_write_hexw, \ + ngtcp2_fmt_bhex: ngtcp2_fmt_write_bhex, \ + ngtcp2_fmt_printable_ascii: ngtcp2_fmt_write_printable_ascii)((DEST), (T)) + +/* ngtcp2_fmt_format formats arguments and writes them into the buffer + pointed by |BUF|. It also writes the terminal NUL byte. The + function assumes that the buffer is the large enough. It assigns + the number of bytes written, excluding the terminal NUL, to + |*PNWRITE|. */ + +/* Generated by fmtgen.py */ +#define NGTCP2_FMT_SELECT_WRITE_PACK( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, \ + _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, \ + _33, _34, _35, _36, _37, _38, _39, _40, PACK, ...) \ + PACK + +#define ngtcp2_fmt_format(BUF, PNWRITE, ...) \ + do { \ + char *fmt_destp = (char *)(BUF); \ + NGTCP2_FMT_SELECT_WRITE_PACK( \ + __VA_ARGS__, NGTCP2_FMT_WRITE_PACK_40, NGTCP2_FMT_WRITE_PACK_39, \ + NGTCP2_FMT_WRITE_PACK_38, NGTCP2_FMT_WRITE_PACK_37, \ + NGTCP2_FMT_WRITE_PACK_36, NGTCP2_FMT_WRITE_PACK_35, \ + NGTCP2_FMT_WRITE_PACK_34, NGTCP2_FMT_WRITE_PACK_33, \ + NGTCP2_FMT_WRITE_PACK_32, NGTCP2_FMT_WRITE_PACK_31, \ + NGTCP2_FMT_WRITE_PACK_30, NGTCP2_FMT_WRITE_PACK_29, \ + NGTCP2_FMT_WRITE_PACK_28, NGTCP2_FMT_WRITE_PACK_27, \ + NGTCP2_FMT_WRITE_PACK_26, NGTCP2_FMT_WRITE_PACK_25, \ + NGTCP2_FMT_WRITE_PACK_24, NGTCP2_FMT_WRITE_PACK_23, \ + NGTCP2_FMT_WRITE_PACK_22, NGTCP2_FMT_WRITE_PACK_21, \ + NGTCP2_FMT_WRITE_PACK_20, NGTCP2_FMT_WRITE_PACK_19, \ + NGTCP2_FMT_WRITE_PACK_18, NGTCP2_FMT_WRITE_PACK_17, \ + NGTCP2_FMT_WRITE_PACK_16, NGTCP2_FMT_WRITE_PACK_15, \ + NGTCP2_FMT_WRITE_PACK_14, NGTCP2_FMT_WRITE_PACK_13, \ + NGTCP2_FMT_WRITE_PACK_12, NGTCP2_FMT_WRITE_PACK_11, \ + NGTCP2_FMT_WRITE_PACK_10, NGTCP2_FMT_WRITE_PACK_9, \ + NGTCP2_FMT_WRITE_PACK_8, NGTCP2_FMT_WRITE_PACK_7, \ + NGTCP2_FMT_WRITE_PACK_6, NGTCP2_FMT_WRITE_PACK_5, \ + NGTCP2_FMT_WRITE_PACK_4, NGTCP2_FMT_WRITE_PACK_3, \ + NGTCP2_FMT_WRITE_PACK_2, \ + NGTCP2_FMT_WRITE_PACK_1)(fmt_destp, __VA_ARGS__); \ + *fmt_destp = '\0'; \ + *(PNWRITE) = (size_t)(fmt_destp - (char *)(BUF)); \ + } while (0) + +#define NGTCP2_FMT_WRITE_PACK_1(DEST, _1) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)) +#define NGTCP2_FMT_WRITE_PACK_2(DEST, _1, _2) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)) +#define NGTCP2_FMT_WRITE_PACK_3(DEST, _1, _2, _3) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)) +#define NGTCP2_FMT_WRITE_PACK_4(DEST, _1, _2, _3, _4) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)) +#define NGTCP2_FMT_WRITE_PACK_5(DEST, _1, _2, _3, _4, _5) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)) +#define NGTCP2_FMT_WRITE_PACK_6(DEST, _1, _2, _3, _4, _5, _6) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)) +#define NGTCP2_FMT_WRITE_PACK_7(DEST, _1, _2, _3, _4, _5, _6, _7) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)) +#define NGTCP2_FMT_WRITE_PACK_8(DEST, _1, _2, _3, _4, _5, _6, _7, _8) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)) +#define NGTCP2_FMT_WRITE_PACK_9(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)) +#define NGTCP2_FMT_WRITE_PACK_10(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)) +#define NGTCP2_FMT_WRITE_PACK_11(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)) +#define NGTCP2_FMT_WRITE_PACK_12(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)) +#define NGTCP2_FMT_WRITE_PACK_13(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)) +#define NGTCP2_FMT_WRITE_PACK_14(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)) +#define NGTCP2_FMT_WRITE_PACK_15(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)) +#define NGTCP2_FMT_WRITE_PACK_16(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)) +#define NGTCP2_FMT_WRITE_PACK_17(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)) +#define NGTCP2_FMT_WRITE_PACK_18(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)) +#define NGTCP2_FMT_WRITE_PACK_19(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)) +#define NGTCP2_FMT_WRITE_PACK_20(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)) +#define NGTCP2_FMT_WRITE_PACK_21(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)) +#define NGTCP2_FMT_WRITE_PACK_22(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)) +#define NGTCP2_FMT_WRITE_PACK_23(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)) +#define NGTCP2_FMT_WRITE_PACK_24(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)) +#define NGTCP2_FMT_WRITE_PACK_25(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)) +#define NGTCP2_FMT_WRITE_PACK_26(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25, _26) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)) +#define NGTCP2_FMT_WRITE_PACK_27(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25, _26, _27) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)) +#define NGTCP2_FMT_WRITE_PACK_28( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)) +#define NGTCP2_FMT_WRITE_PACK_29( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)) +#define NGTCP2_FMT_WRITE_PACK_30( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)) +#define NGTCP2_FMT_WRITE_PACK_31( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)) +#define NGTCP2_FMT_WRITE_PACK_32(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25, _26, _27, \ + _28, _29, _30, _31, _32) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)) +#define NGTCP2_FMT_WRITE_PACK_33(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25, _26, _27, \ + _28, _29, _30, _31, _32, _33) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)) +#define NGTCP2_FMT_WRITE_PACK_34(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25, _26, _27, \ + _28, _29, _30, _31, _32, _33, _34) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_34)) +#define NGTCP2_FMT_WRITE_PACK_35(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25, _26, _27, \ + _28, _29, _30, _31, _32, _33, _34, _35) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_34)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_35)) +#define NGTCP2_FMT_WRITE_PACK_36(DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ + _10, _11, _12, _13, _14, _15, _16, _17, _18, \ + _19, _20, _21, _22, _23, _24, _25, _26, _27, \ + _28, _29, _30, _31, _32, _33, _34, _35, _36) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_34)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_35)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_36)) +#define NGTCP2_FMT_WRITE_PACK_37( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, \ + _32, _33, _34, _35, _36, _37) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_34)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_35)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_36)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_37)) +#define NGTCP2_FMT_WRITE_PACK_38( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, \ + _32, _33, _34, _35, _36, _37, _38) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_34)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_35)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_36)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_37)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_38)) +#define NGTCP2_FMT_WRITE_PACK_39( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, \ + _32, _33, _34, _35, _36, _37, _38, _39) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_34)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_35)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_36)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_37)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_38)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_39)) +#define NGTCP2_FMT_WRITE_PACK_40( \ + DEST, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, \ + _32, _33, _34, _35, _36, _37, _38, _39, _40) \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_1)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_2)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_3)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_4)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_5)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_6)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_7)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_8)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_9)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_10)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_11)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_12)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_13)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_14)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_15)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_16)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_17)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_18)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_19)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_20)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_21)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_22)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_23)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_24)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_25)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_26)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_27)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_28)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_29)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_30)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_31)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_32)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_33)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_34)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_35)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_36)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_37)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_38)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_39)); \ + (DEST) = NGTCP2_FMT_WRITE_TYPE((DEST), (_40)) + +#endif /* !defined(NGTCP2_FMT_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h index c73100dbcbaa4f..4b3c300060a45b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h @@ -71,10 +71,10 @@ int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, (NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES * sizeof(ngtcp2_vec)) /* NGTCP2_FRAME_CHAIN_FLAG_NONE indicates no flag is set. */ -#define NGTCP2_FRAME_CHAIN_FLAG_NONE 0x0 +#define NGTCP2_FRAME_CHAIN_FLAG_NONE 0x0U /* NGTCP2_FRAME_CHAIN_FLAG_MALLOC indicates that ngtcp2_frame_chain is allocated by ngtcp2_mem_malloc. */ -#define NGTCP2_FRAME_CHAIN_FLAG_MALLOC 0x1 +#define NGTCP2_FRAME_CHAIN_FLAG_MALLOC 0x1U typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c index 267bd07225d72b..a2ec5ffa376acd 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c @@ -35,11 +35,11 @@ void ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) { } static int gaptr_gap_init(ngtcp2_gaptr *gaptr) { - return ngtcp2_ksl_insert(&gaptr->gap, NULL, - &(ngtcp2_range){ - .end = UINT64_MAX, - }, - NULL); + static const ngtcp2_range end = { + .end = UINT64_MAX, + }; + + return ngtcp2_ksl_insert(&gaptr->gap, NULL, &end, NULL); } void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c index 80000f42f9b834..b88985234e56ca 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c @@ -55,13 +55,12 @@ void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, assert(keylen >= sizeof(uint64_t)); - aligned_keylen = (keylen + 0x7U) & ~0x7U; + aligned_keylen = (keylen + 0x7U) & ~(size_t)0x7U; assert(aligned_keylen <= UINT16_MAX); - ngtcp2_objalloc_init(&ksl->blkalloc, - (ksl_blklen(aligned_keylen) + 0xFU) & ~(uintptr_t)0xFU, - mem); + ngtcp2_objalloc_init( + &ksl->blkalloc, (ksl_blklen(aligned_keylen) + 0xFU) & ~(size_t)0xFU, mem); ksl->root = NULL; ksl->front = ksl->back = NULL; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h index 8024a360cdb4fc..9ef201a8dbb95d 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h @@ -382,8 +382,8 @@ static inline int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { const ngtcp2_range *a = (const ngtcp2_range *)lhs, *b = (const ngtcp2_range *)rhs; - return a->begin < b->begin && !(ngtcp2_max_uint64(a->begin, b->begin) < - ngtcp2_min_uint64(a->end, b->end)); + return a->begin < b->begin && + !(ngtcp2_max(a->begin, b->begin) < ngtcp2_min(a->end, b->end)); } /* diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c index 191c64430b5b28..51a9d70d13c47d 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c @@ -39,17 +39,19 @@ #include "ngtcp2_net.h" void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, - ngtcp2_printf log_printf, ngtcp2_tstamp ts, - void *user_data) { + ngtcp2_log_write log_write, ngtcp2_printf log_printf, + char *buf, ngtcp2_tstamp ts, void *user_data) { if (scid) { - ngtcp2_encode_hex_cstr(log->scid, scid->data, scid->datalen); + *ngtcp2_encode_hex((uint8_t *)log->scid, scid->data, scid->datalen) = '\0'; } else { log->scid[0] = '\0'; } + log->log_write = log_write; log->log_printf = log_printf; log->events = 0xFF; log->ts = log->last_ts = ts; log->user_data = user_data; + log->buf = buf; } /* @@ -90,10 +92,9 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, * Frame type in hex string. */ -#define NGTCP2_LOG_PKT "%s %" PRId64 " %s" #define NGTCP2_LOG_TP "remote transport_parameters" -#define NGTCP2_LOG_PKT_HD_FIELDS(DIR) (DIR), hd->pkt_num, strpkttype(hd) +#define NGTCP2_LOG_PKT(DIR, HD) (DIR), " ", (HD)->pkt_num, " ", strpkttype((HD)) static const char *strerrorcode(uint64_t error_code) { switch (error_code) { @@ -177,12 +178,10 @@ static const char *strpkttype_type_flags(uint8_t type, uint8_t flags) { static void log_fr_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stream *fr, const char *dir) { ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " STREAM(0x%02" PRIx64 ") id=0x%" PRIx64 - " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id, fr->fin, - fr->offset, ngtcp2_vec_len(fr->data, fr->datacnt), - (fr->stream_id & 0x2) != 0); + log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), " STREAM(0x", + hex(fr->type | fr->flags), ") id=0x", hex(fr->stream_id), " fin=", fr->fin, + " offset=", fr->offset, " len=", ngtcp2_vec_len(fr->data, fr->datacnt), + " uni=", (fr->stream_id & 0x2) != 0); } static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -191,246 +190,198 @@ static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, size_t i; ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") largest_ack=%" PRId64 - " ack_delay=%" PRIu64 "(%" PRIu64 ") ack_range_count=%zu", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->largest_ack, - fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, fr->ack_delay, fr->rangecnt); + log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), " ACK(0x", + hex(fr->type), ") largest_ack=", fr->largest_ack, + " ack_delay=", fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, "(", + fr->ack_delay, ") ack_range_count=", fr->rangecnt); largest_ack = fr->largest_ack; min_ack = fr->largest_ack - (int64_t)fr->first_ack_range; - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64 - "..%" PRId64 "] len=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, largest_ack, - min_ack, fr->first_ack_range); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " ACK(0x", hex(fr->type), ") range=[", largest_ack, "..", + min_ack, "] len=", fr->first_ack_range); for (i = 0; i < fr->rangecnt; ++i) { const ngtcp2_ack_range *range = &fr->ranges[i]; largest_ack = min_ack - (int64_t)range->gap - 2; min_ack = largest_ack - (int64_t)range->len; - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64 - "..%" PRId64 "] gap=%" PRIu64 - " len=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, largest_ack, - min_ack, range->gap, range->len); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " ACK(0x", hex(fr->type), ") range=[", largest_ack, + "..", min_ack, "] gap=", range->gap, + " len=", range->len); } if (fr->type == NGTCP2_FRAME_ACK_ECN) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") ect0=%" PRIu64 - " ect1=%" PRIu64 " ce=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->ecn.ect0, - fr->ecn.ect1, fr->ecn.ce); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " ACK(0x", hex(fr->type), ") ect0=", fr->ecn.ect0, + " ect1=", fr->ecn.ect1, " ce=", fr->ecn.ce); } } static void log_fr_padding(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_padding *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " PADDING(0x%02" PRIx64 ") len=%zu", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->len); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " PADDING(0x", hex(fr->type), ") len=", fr->len); } static void log_fr_reset_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_reset_stream *fr, const char *dir) { ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " RESET_STREAM(0x%02" PRIx64 ") id=0x%" PRIx64 - " app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id, - strapperrorcode(fr->app_error_code), fr->app_error_code, fr->final_size); + log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), " RESET_STREAM(0x", + hex(fr->type), ") id=0x", hex(fr->stream_id), + " app_error_code=", strapperrorcode(fr->app_error_code), "(0x", + hex(fr->app_error_code), ") final_size=", fr->final_size); } static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_connection_close *fr, const char *dir) { - char reason[256]; - size_t reasonlen = ngtcp2_min_size(sizeof(reason) - 1, fr->reasonlen); + size_t reasonlen = ngtcp2_min(64, fr->reasonlen); - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02" PRIx64 ") error_code=%s(0x%" PRIx64 - ") " - "frame_type=0x%" PRIx64 " reason_len=%zu reason=[%s]", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, - fr->type == NGTCP2_FRAME_CONNECTION_CLOSE ? strerrorcode(fr->error_code) - : strapperrorcode(fr->error_code), - fr->error_code, fr->frame_type, fr->reasonlen, - ngtcp2_encode_printable_ascii_cstr(reason, fr->reason, reasonlen)); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " CONNECTION_CLOSE(0x", hex(fr->type), ") error_code=", + fr->type == NGTCP2_FRAME_CONNECTION_CLOSE + ? strerrorcode(fr->error_code) + : strapperrorcode(fr->error_code), + "(0x", hex(fr->error_code), ") frame_type=0x", + hex(fr->frame_type), " reason_len=", fr->reasonlen, + " reason=[", ascii(fr->reason, reasonlen), "]"); } static void log_fr_max_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_data *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " MAX_DATA(0x%02" PRIx64 - ") max_data=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_data); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " MAX_DATA(0x", hex(fr->type), + ") max_data=", fr->max_data); } static void log_fr_max_stream_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_stream_data *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02" PRIx64 - ") id=0x%" PRIx64 - " max_stream_data=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id, - fr->max_stream_data); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " MAX_STREAM_DATA(0x", hex(fr->type), ") id=0x", + hex(fr->stream_id), + " max_stream_data=", fr->max_stream_data); } static void log_fr_max_streams(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_streams *fr, const char *dir) { - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " MAX_STREAMS(0x%02" PRIx64 ") max_streams=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_streams); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " MAX_STREAMS(0x", hex(fr->type), + ") max_streams=", fr->max_streams); } static void log_fr_ping(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_ping *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " PING(0x%02" PRIx64 ")", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " PING(0x", hex(fr->type), ")"); } static void log_fr_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_data_blocked *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02" PRIx64 - ") offset=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->offset); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " DATA_BLOCKED(0x", hex(fr->type), + ") offset=", fr->offset); } static void log_fr_stream_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stream_data_blocked *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02" PRIx64 - ") id=0x%" PRIx64 " offset=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id, - fr->offset); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " STREAM_DATA_BLOCKED(0x", hex(fr->type), ") id=0x", + hex(fr->stream_id), " offset=", fr->offset); } static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_streams_blocked *fr, const char *dir) { - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02" PRIx64 ") max_streams=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->max_streams); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " STREAMS_BLOCKED(0x", hex(fr->type), + ") max_streams=", fr->max_streams); } static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_new_connection_id *fr, const char *dir) { - char buf[sizeof(fr->token.data) * 2 + 1]; - char cid[sizeof(fr->cid.data) * 2 + 1]; - - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64 - " cid=0x%s retire_prior_to=%" PRIu64 - " stateless_reset_token=0x%s", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq, - ngtcp2_encode_hex_cstr(cid, fr->cid.data, fr->cid.datalen), - fr->retire_prior_to, - ngtcp2_encode_hex_cstr(buf, fr->token.data, sizeof(fr->token.data))); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " NEW_CONNECTION_ID(0x", hex(fr->type), + ") seq=", fr->seq, " cid=0x", &fr->cid, + " retire_prior_to=", fr->retire_prior_to, + " stateless_reset_token=0x", &fr->token); } static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stop_sending *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " STOP_SENDING(0x%02" PRIx64 - ") id=0x%" PRIx64 - " app_error_code=%s(0x%" PRIx64 ")", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->stream_id, - strapperrorcode(fr->app_error_code), fr->app_error_code); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " STOP_SENDING(0x", hex(fr->type), ") id=0x", + hex(fr->stream_id), + " app_error_code=", strapperrorcode(fr->app_error_code), + "(0x", hex(fr->app_error_code), ")"); } static void log_fr_path_challenge(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_path_challenge *fr, const char *dir) { - char buf[sizeof(fr->data.data) * 2 + 1]; - - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, - ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data))); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " PATH_CHALLENGE(0x", hex(fr->type), ") data=0x", + &fr->data); } static void log_fr_path_response(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_path_response *fr, const char *dir) { - char buf[sizeof(fr->data.data) * 2 + 1]; - - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, - ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data))); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " PATH_RESPONSE(0x", hex(fr->type), ") data=0x", + &fr->data); } static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stream *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " CRYPTO(0x%02" PRIx64 ") offset=%" PRIu64 - " len=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->offset, - ngtcp2_vec_len(fr->data, fr->datacnt)); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " CRYPTO(0x", hex(fr->type), ") offset=", fr->offset, + " len=", ngtcp2_vec_len(fr->data, fr->datacnt)); } +#define NGTCP2_LOG_MAX_TOKENLEN 64 + static void log_fr_new_token(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_new_token *fr, const char *dir) { - /* Show at most first 64 bytes of token. If token is longer than 64 - bytes, log first 64 bytes and then append "*" */ - char buf[128 + 1 + 1]; - char *p; - - if (fr->tokenlen > 64) { - p = ngtcp2_encode_hex_cstr(buf, fr->token, 64); - p[128] = '*'; - p[129] = '\0'; - } else { - p = ngtcp2_encode_hex_cstr(buf, fr->token, fr->tokenlen); - } + /* Show at most first NGTCP2_LOG_MAX_TOKENLEN bytes of token. If + token is longer than that, log first those bytes and then append + "*" */ + size_t tokenlen = ngtcp2_min(fr->tokenlen, NGTCP2_LOG_MAX_TOKENLEN); ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, p, fr->tokenlen); + log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), " NEW_TOKEN(0x", + hex(fr->type), ") token=0x", bhex(fr->token, tokenlen), + fr->tokenlen > NGTCP2_LOG_MAX_TOKENLEN ? "*" : "", " len=", fr->tokenlen); } static void log_fr_retire_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_retire_connection_id *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02" PRIx64 - ") seq=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " RETIRE_CONNECTION_ID(0x", hex(fr->type), + ") seq=", fr->seq); } static void log_fr_handshake_done(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_handshake_done *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02" PRIx64 ")", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " HANDSHAKE_DONE(0x", hex(fr->type), ")"); } static void log_fr_datagram(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_datagram *fr, const char *dir) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " DATAGRAM(0x%02" PRIx64 ") len=%" PRIu64, - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, - ngtcp2_vec_len(fr->data, fr->datacnt)); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, NGTCP2_LOG_PKT(dir, hd), + " DATAGRAM(0x", hex(fr->type), + ") len=", ngtcp2_vec_len(fr->data, fr->datacnt)); } static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -511,7 +462,8 @@ static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_frame *fr) { - if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_FRM)) { + if ((!log->log_write && !log->log_printf) || + !(log->events & NGTCP2_LOG_EVENT_FRM)) { return; } @@ -520,7 +472,8 @@ void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, void ngtcp2_log_tx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_frame *fr) { - if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_FRM)) { + if ((!log->log_write && !log->log_printf) || + !(log->events & NGTCP2_LOG_EVENT_FRM)) { return; } @@ -531,56 +484,50 @@ void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const uint32_t *sv, size_t nsv) { size_t i; - if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { + if ((!log->log_write && !log->log_printf) || + !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } for (i = 0; i < nsv; ++i) { - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " v=0x%08x", - NGTCP2_LOG_PKT_HD_FIELDS("rx"), sv[i]); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT("rx", hd), + " v=0x", hexw(sv[i], 8)); } } void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset2 *sr) { - char buf[sizeof(sr->token.data) * 2 + 1]; - ngtcp2_pkt_hd shd; - ngtcp2_pkt_hd *hd = &shd; + ngtcp2_pkt_hd hd; - if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { + if ((!log->log_write && !log->log_printf) || + !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } - shd = (ngtcp2_pkt_hd){ + hd = (ngtcp2_pkt_hd){ .type = NGTCP2_PKT_STATELESS_RESET, }; - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " token=0x%s randlen=%zu", - NGTCP2_LOG_PKT_HD_FIELDS("rx"), - ngtcp2_encode_hex_cstr(buf, sr->token.data, sizeof(sr->token.data)), - sr->randlen); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT("rx", &hd), + " token=0x", &sr->token, " randlen=", sr->randlen); } void ngtcp2_log_remote_tp(ngtcp2_log *log, const ngtcp2_transport_params *params) { - char token[sizeof(params->stateless_reset_token) * 2 + 1]; - char addr[16 * 2 + 7 + 1]; - char cid[NGTCP2_MAX_CIDLEN * 2 + 1]; size_t i; const ngtcp2_sockaddr_in *sa_in; const ngtcp2_sockaddr_in6 *sa_in6; const uint8_t *p; uint32_t version; - if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_CRY)) { + if ((!log->log_write && !log->log_printf) || + !(log->events & NGTCP2_LOG_EVENT_CRY)) { return; } if (params->stateless_reset_token_present) { - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " stateless_reset_token=0x%s", - ngtcp2_encode_hex_cstr(token, params->stateless_reset_token, - sizeof(params->stateless_reset_token))); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " stateless_reset_token=0x", + lbhex(params->stateless_reset_token)); } if (params->preferred_addr_present) { @@ -589,10 +536,9 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log, ngtcp2_log_infof_raw( log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s", - ngtcp2_encode_ipv4_cstr(addr, (const uint8_t *)&sa_in->sin_addr)); + NGTCP2_LOG_TP " preferred_address.ipv4_addr=", &sa_in->sin_addr); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " preferred_address.ipv4_port=%u", + NGTCP2_LOG_TP " preferred_address.ipv4_port=", ngtcp2_ntohs(sa_in->sin_port)); } @@ -601,97 +547,86 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log, ngtcp2_log_infof_raw( log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s", - ngtcp2_encode_ipv6_cstr(addr, (const uint8_t *)&sa_in6->sin6_addr)); + NGTCP2_LOG_TP " preferred_address.ipv6_addr=", &sa_in6->sin6_addr); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " preferred_address.ipv6_port=%u", + NGTCP2_LOG_TP " preferred_address.ipv6_port=", ngtcp2_ntohs(sa_in6->sin6_port)); } - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " preferred_address.cid=0x%s", - ngtcp2_encode_hex_cstr(cid, params->preferred_addr.cid.data, - params->preferred_addr.cid.datalen)); - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s", - ngtcp2_encode_hex_cstr( - token, params->preferred_addr.stateless_reset_token, - sizeof(params->preferred_addr.stateless_reset_token))); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " preferred_address.cid=0x", + ¶ms->preferred_addr.cid); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP + " preferred_address.stateless_reset_token=0x", + lbhex(params->preferred_addr.stateless_reset_token)); } if (params->original_dcid_present) { ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP - " original_destination_connection_id=0x%s", - ngtcp2_encode_hex_cstr(cid, params->original_dcid.data, - params->original_dcid.datalen)); + NGTCP2_LOG_TP " original_destination_connection_id=0x", + ¶ms->original_dcid); } if (params->retry_scid_present) { ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " retry_source_connection_id=0x%s", - ngtcp2_encode_hex_cstr(cid, params->retry_scid.data, - params->retry_scid.datalen)); + NGTCP2_LOG_TP " retry_source_connection_id=0x", + ¶ms->retry_scid); } if (params->initial_scid_present) { ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " initial_source_connection_id=0x%s", - ngtcp2_encode_hex_cstr(cid, params->initial_scid.data, - params->initial_scid.datalen)); + NGTCP2_LOG_TP " initial_source_connection_id=0x", + ¶ms->initial_scid); } ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP - " initial_max_stream_data_bidi_local=%" PRIu64, + NGTCP2_LOG_TP " initial_max_stream_data_bidi_local=", params->initial_max_stream_data_bidi_local); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP - " initial_max_stream_data_bidi_remote=%" PRIu64, + NGTCP2_LOG_TP " initial_max_stream_data_bidi_remote=", params->initial_max_stream_data_bidi_remote); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " initial_max_stream_data_uni=%" PRIu64, + NGTCP2_LOG_TP " initial_max_stream_data_uni=", params->initial_max_stream_data_uni); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " initial_max_data=", params->initial_max_data); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " initial_max_data=%" PRIu64, - params->initial_max_data); - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " initial_max_streams_bidi=%" PRIu64, + NGTCP2_LOG_TP " initial_max_streams_bidi=", params->initial_max_streams_bidi); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " initial_max_streams_uni=", params->initial_max_streams_uni); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " initial_max_streams_uni=%" PRIu64, - params->initial_max_streams_uni); - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " max_idle_timeout=%" PRIu64, + NGTCP2_LOG_TP " max_idle_timeout=", params->max_idle_timeout / NGTCP2_MILLISECONDS); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " max_udp_payload_size=", params->max_udp_payload_size); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " ack_delay_exponent=", params->ack_delay_exponent); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " max_udp_payload_size=%" PRIu64, - params->max_udp_payload_size); - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " ack_delay_exponent=%" PRIu64, - params->ack_delay_exponent); - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " max_ack_delay=%" PRIu64, + NGTCP2_LOG_TP " max_ack_delay=", params->max_ack_delay / NGTCP2_MILLISECONDS); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " active_connection_id_limit=%" PRIu64, + NGTCP2_LOG_TP " active_connection_id_limit=", params->active_connection_id_limit); ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " disable_active_migration=%d", + NGTCP2_LOG_TP " disable_active_migration=", params->disable_active_migration); - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " max_datagram_frame_size=%" PRIu64, - params->max_datagram_frame_size); - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " grease_quic_bit=%d", - params->grease_quic_bit); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " max_datagram_frame_size=", params->max_datagram_frame_size); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP " grease_quic_bit=", params->grease_quic_bit); if (params->version_info_present) { ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP - " version_information.chosen_version=0x%08x", - params->version_info.chosen_version); + NGTCP2_LOG_TP " version_information.chosen_version=0x", + hexw(params->version_info.chosen_version, 8)); assert(!(params->version_info.available_versionslen & 0x3)); @@ -700,48 +635,42 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log, i += sizeof(uint32_t)) { p = ngtcp2_get_uint32be(&version, p); - ngtcp2_log_infof_raw( - log, NGTCP2_LOG_EVENT_CRY, - NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x", - i >> 2, version); + ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_TP + " version_information.available_versions[", + i >> 2, "]=0x", hexw(version, 8)); } } } void ngtcp2_log_pkt_lost(ngtcp2_log *log, int64_t pkt_num, uint8_t type, uint8_t flags, ngtcp2_tstamp sent_ts) { - if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_LDC)) { + if ((!log->log_write && !log->log_printf) || + !(log->events & NGTCP2_LOG_EVENT_LDC)) { return; } - ngtcp2_log_infof(log, NGTCP2_LOG_EVENT_LDC, - "pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num, - strpkttype_type_flags(type, flags), sent_ts); + ngtcp2_log_infof(log, NGTCP2_LOG_EVENT_LDC, "pkn=", pkt_num, + " lost type=", strpkttype_type_flags(type, flags), + " sent_ts=", sent_ts); } static void log_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const char *dir) { - char dcid[sizeof(hd->dcid.data) * 2 + 1]; - char scid[sizeof(hd->scid.data) * 2 + 1]; - - if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { + if ((!log->log_write && !log->log_printf) || + !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } if (hd->type == NGTCP2_PKT_1RTT) { - ngtcp2_log_infof( - log, NGTCP2_LOG_EVENT_PKT, "%s pkn=%" PRId64 " dcid=0x%s type=%s k=%d", - dir, hd->pkt_num, - ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen), - strpkttype(hd), (hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE) != 0); + ngtcp2_log_infof(log, NGTCP2_LOG_EVENT_PKT, dir, " pkn=", hd->pkt_num, + " dcid=0x", &hd->dcid, " type=", strpkttype(hd), + " k=", (hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE) != 0); } else { - ngtcp2_log_infof( - log, NGTCP2_LOG_EVENT_PKT, - "%s pkn=%" PRId64 " dcid=0x%s scid=0x%s version=0x%08x type=%s len=%zu", - dir, hd->pkt_num, - ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen), - ngtcp2_encode_hex_cstr(scid, hd->scid.data, hd->scid.datalen), - hd->version, strpkttype(hd), hd->len); + ngtcp2_log_infof(log, NGTCP2_LOG_EVENT_PKT, dir, " pkn=", hd->pkt_num, + " dcid=0x", &hd->dcid, " scid=0x", &hd->scid, + " version=0x", hexw(hd->version, 8), + " type=", strpkttype(hd), " len=", hd->len); } } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h index b8bccb9d09ebca..c014cea1984af4 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h @@ -32,8 +32,12 @@ #include #include "ngtcp2_pkt.h" +#include "ngtcp2_fmt.h" + +#define NGTCP2_LOG_BUFLEN 1024 typedef struct ngtcp2_log { + ngtcp2_log_write log_write; /* log_printf is a sink to write log. NULL means no logging output. */ ngtcp2_printf log_printf; @@ -50,6 +54,7 @@ typedef struct ngtcp2_log { void *user_data; /* scid is SCID encoded as NULL-terminated hex string. */ char scid[NGTCP2_MAX_CIDLEN * 2 + 1]; + char *buf; } ngtcp2_log; /** @@ -96,8 +101,8 @@ typedef enum ngtcp2_log_event { } ngtcp2_log_event; void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, - ngtcp2_printf log_printf, ngtcp2_tstamp ts, - void *user_data); + ngtcp2_log_write log_write, ngtcp2_printf log_printf, + char *buf, ngtcp2_tstamp ts, void *user_data); void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_frame *fr); @@ -119,8 +124,6 @@ void ngtcp2_log_rx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd); void ngtcp2_log_tx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd); -#define NGTCP2_LOG_HD "I%08" PRIu64 " 0x%s %s" - uint64_t ngtcp2_log_timestamp(const ngtcp2_log *log); static inline const char *ngtcp2_log_event_str(ngtcp2_log_event ev) { @@ -145,45 +148,33 @@ static inline const char *ngtcp2_log_event_str(ngtcp2_log_event ev) { } } -#define ngtcp2_log_infof_raw(LOG, EV, FMT, ...) \ - (LOG)->log_printf((LOG)->user_data, NGTCP2_LOG_HD " " FMT, \ - ngtcp2_log_timestamp(LOG), (LOG)->scid, \ - ngtcp2_log_event_str(EV), __VA_ARGS__); +#define NGTCP2_LOG_HD(LOG, EV) \ + "I", uintw(ngtcp2_log_timestamp(LOG), 8), " 0x", (LOG)->scid, " ", \ + ngtcp2_log_event_str(EV), " " -/** - * @function - * - * `ngtcp2_log_infof` writes info level log with printf like - * formatting. - */ -#define ngtcp2_log_infof(LOG, EV, FMT, ...) \ +#define ngtcp2_log_infof_raw(LOG, EV, ...) \ do { \ - if (!(LOG)->log_printf || !((LOG)->events & (EV))) { \ - break; \ - } \ + size_t log_nwrite; \ \ - ngtcp2_log_infof_raw((LOG), (EV), FMT, __VA_ARGS__); \ + ngtcp2_fmt_format((LOG)->buf, &log_nwrite, NGTCP2_LOG_HD((LOG), (EV)), \ + __VA_ARGS__); \ + if ((LOG)->log_write) { \ + (LOG)->log_write((LOG)->user_data, (LOG)->buf, log_nwrite); \ + } else { \ + (LOG)->log_printf((LOG)->user_data, "%s", (LOG)->buf); \ + } \ } while (0) -#define ngtcp2_log_info_raw(LOG, EV, FMT) \ - (LOG)->log_printf((LOG)->user_data, NGTCP2_LOG_HD " " FMT, \ - ngtcp2_log_timestamp(LOG), (LOG)->scid, \ - ngtcp2_log_event_str(EV)) - -/** - * @function - * - * `ngtcp2_log_info` writes info level log. FMT should not contain - * formatting directive. This function exists to workaround the issue - * that __VA_ARGS__ cannot be empty. - */ -#define ngtcp2_log_info(LOG, EV, FMT) \ +#define ngtcp2_log_infof(LOG, EV, ...) \ do { \ - if (!(LOG)->log_printf || !((LOG)->events & (EV))) { \ + if ((!(LOG)->log_write && !(LOG)->log_printf) || \ + !((LOG)->events & (EV))) { \ break; \ } \ \ - ngtcp2_log_info_raw((LOG), (EV), FMT); \ + ngtcp2_log_infof_raw((LOG), (EV), __VA_ARGS__); \ } while (0) +#define ngtcp2_log_info(LOG, EV, ARG) ngtcp2_log_infof((LOG), (EV), (ARG)) + #endif /* !defined(NGTCP2_LOG_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h index 12cba12719ac7b..ea98c9e1276114 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h @@ -62,27 +62,81 @@ #define ngtcp2_max_def(SUFFIX, T) \ static inline T ngtcp2_max_##SUFFIX(T a, T b) { return a < b ? b : a; } -ngtcp2_max_def(int8, int8_t) -ngtcp2_max_def(int16, int16_t) -ngtcp2_max_def(int32, int32_t) -ngtcp2_max_def(int64, int64_t) -ngtcp2_max_def(uint8, uint8_t) -ngtcp2_max_def(uint16, uint16_t) -ngtcp2_max_def(uint32, uint32_t) -ngtcp2_max_def(uint64, uint64_t) -ngtcp2_max_def(size, size_t) +ngtcp2_max_def(long_long_int, long long int) +ngtcp2_max_def(long_int, long int) +ngtcp2_max_def(int, int) +ngtcp2_max_def(short_int, short int) +ngtcp2_max_def(signed_char, signed char) +ngtcp2_max_def(char, char) +ngtcp2_max_def(unsigned_long_long_int, unsigned long long int) +ngtcp2_max_def(unsigned_long_int, unsigned long int) +ngtcp2_max_def(unsigned_int, unsigned int) +ngtcp2_max_def(unsigned_short_int, unsigned short int) +ngtcp2_max_def(unsigned_char, unsigned char) + +#define ngtcp2_max(A, B) \ + _Generic((A), \ + long long int: ngtcp2_max_long_long_int, \ + long int: ngtcp2_max_long_int, \ + int: _Generic((B), \ + long long int: ngtcp2_max_long_long_int, \ + long int: ngtcp2_max_long_int, \ + int: ngtcp2_max_int, \ + short int: ngtcp2_max_short_int, \ + signed char: ngtcp2_max_signed_char, \ + char: ngtcp2_max_char, \ + unsigned long long int: ngtcp2_max_unsigned_long_long_int, \ + unsigned long int: ngtcp2_max_unsigned_long_int, \ + unsigned int: ngtcp2_max_unsigned_int, \ + unsigned short int: ngtcp2_max_unsigned_short_int, \ + unsigned char: ngtcp2_max_unsigned_char), \ + short int: ngtcp2_max_short_int, \ + signed char: ngtcp2_max_signed_char, \ + char: ngtcp2_max_char, \ + unsigned long long int: ngtcp2_max_unsigned_long_long_int, \ + unsigned long int: ngtcp2_max_unsigned_long_int, \ + unsigned int: ngtcp2_max_unsigned_int, \ + unsigned short int: ngtcp2_max_unsigned_short_int, \ + unsigned char: ngtcp2_max_unsigned_char)((A), (B)) #define ngtcp2_min_def(SUFFIX, T) \ static inline T ngtcp2_min_##SUFFIX(T a, T b) { return a < b ? a : b; } -ngtcp2_min_def(int8, int8_t) -ngtcp2_min_def(int16, int16_t) -ngtcp2_min_def(int32, int32_t) -ngtcp2_min_def(int64, int64_t) -ngtcp2_min_def(uint8, uint8_t) -ngtcp2_min_def(uint16, uint16_t) -ngtcp2_min_def(uint32, uint32_t) -ngtcp2_min_def(uint64, uint64_t) -ngtcp2_min_def(size, size_t) +ngtcp2_min_def(long_long_int, long long int) +ngtcp2_min_def(long_int, long int) +ngtcp2_min_def(int, int) +ngtcp2_min_def(short_int, short int) +ngtcp2_min_def(signed_char, signed char) +ngtcp2_min_def(char, char) +ngtcp2_min_def(unsigned_long_long_int, unsigned long long int) +ngtcp2_min_def(unsigned_long_int, unsigned long int) +ngtcp2_min_def(unsigned_int, unsigned int) +ngtcp2_min_def(unsigned_short_int, unsigned short int) +ngtcp2_min_def(unsigned_char, unsigned char) + +#define ngtcp2_min(A, B) \ + _Generic((A), \ + long long int: ngtcp2_min_long_long_int, \ + long int: ngtcp2_min_long_int, \ + int: _Generic((B), \ + long long int: ngtcp2_min_long_long_int, \ + long int: ngtcp2_min_long_int, \ + int: ngtcp2_min_int, \ + short int: ngtcp2_min_short_int, \ + signed char: ngtcp2_min_signed_char, \ + char: ngtcp2_min_char, \ + unsigned long long int: ngtcp2_min_unsigned_long_long_int, \ + unsigned long int: ngtcp2_min_unsigned_long_int, \ + unsigned int: ngtcp2_min_unsigned_int, \ + unsigned short int: ngtcp2_min_unsigned_short_int, \ + unsigned char: ngtcp2_min_unsigned_char), \ + short int: ngtcp2_min_short_int, \ + signed char: ngtcp2_min_signed_char, \ + char: ngtcp2_min_char, \ + unsigned long long int: ngtcp2_min_unsigned_long_long_int, \ + unsigned long int: ngtcp2_min_unsigned_long_int, \ + unsigned int: ngtcp2_min_unsigned_int, \ + unsigned short int: ngtcp2_min_unsigned_short_int, \ + unsigned char: ngtcp2_min_unsigned_char)((A), (B)) #endif /* !defined(NGTCP2_MACRO_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h index 35a807f9fed29f..5fdeb98532053b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h @@ -67,11 +67,11 @@ # define ngtcp2_htonl64(N) (N) # else /* !defined(WORDS_BIGENDIAN) */ # if HAVE_DECL_BSWAP_64 -# define ngtcp2_bswap64 bswap_64 +# define ngtcp2_bswap64(N) bswap_64(N) # elif defined(WIN32) -# define ngtcp2_bswap64 _byteswap_uint64 +# define ngtcp2_bswap64(N) _byteswap_uint64(N) # elif defined(__APPLE__) -# define ngtcp2_bswap64 OSSwapInt64 +# define ngtcp2_bswap64(N) OSSwapInt64(N) # else /* !(HAVE_DECL_BSWAP_64 || defined(WIN32) || defined(__APPLE__)) */ # define ngtcp2_bswap64(N) \ ((uint64_t)(ngtcp2_ntohl((uint32_t)(N))) << 32 | \ @@ -83,59 +83,19 @@ #endif /* !HAVE_DECL_BE64TOH */ #ifdef WIN32 -/* Windows requires ws2_32 library for ntonl family functions. We - define inline functions for those function so that we don't have - dependency on that lib. */ - -# ifdef _MSC_VER -# define STIN static __inline -# else /* !defined(_MSC_VER) */ -# define STIN static inline -# endif /* !defined(_MSC_VER) */ - -STIN uint32_t ngtcp2_htonl(uint32_t hostlong) { - uint32_t res; - unsigned char *p = (unsigned char *)&res; - *p++ = (unsigned char)(hostlong >> 24); - *p++ = (hostlong >> 16) & 0xFFU; - *p++ = (hostlong >> 8) & 0xFFU; - *p = hostlong & 0xFFU; - return res; -} - -STIN uint16_t ngtcp2_htons(uint16_t hostshort) { - uint16_t res; - unsigned char *p = (unsigned char *)&res; - *p++ = (unsigned char)(hostshort >> 8); - *p = hostshort & 0xFFU; - return res; -} - -STIN uint32_t ngtcp2_ntohl(uint32_t netlong) { - uint32_t res; - unsigned char *p = (unsigned char *)&netlong; - res = (uint32_t)(*p++ << 24); - res += (uint32_t)(*p++ << 16); - res += (uint32_t)(*p++ << 8); - res += *p; - return res; -} - -STIN uint16_t ngtcp2_ntohs(uint16_t netshort) { - uint16_t res; - unsigned char *p = (unsigned char *)&netshort; - res = (uint16_t)(*p++ << 8); - res += *p; - return res; -} - +/* Windows requires ws2_32 library for ntonl family of functions. + Instead of using them, use _byteswap_* functions. This is fine + because all platforms that can run Windows these days are little + endian. */ +# define ngtcp2_htonl(N) _byteswap_ulong(N) +# define ngtcp2_htons(N) _byteswap_ushort(N) +# define ngtcp2_ntohl(N) _byteswap_ulong(N) +# define ngtcp2_ntohs(N) _byteswap_ushort(N) #else /* !defined(WIN32) */ - -# define ngtcp2_htonl htonl -# define ngtcp2_htons htons -# define ngtcp2_ntohl ntohl -# define ngtcp2_ntohs ntohs - +# define ngtcp2_htonl(N) htonl(N) +# define ngtcp2_htons(N) htons(N) +# define ngtcp2_ntohl(N) ntohl(N) +# define ngtcp2_ntohs(N) ntohs(N) #endif /* !defined(WIN32) */ #endif /* !defined(NGTCP2_NET_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h index 4b6df53857a5b8..38eabb323ba72b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h @@ -69,7 +69,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); inline static void ngtcp2_objalloc_##NAME##_init( \ ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \ ngtcp2_objalloc_init( \ - objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem); \ + objalloc, ((sizeof(TYPE) + 0xFU) & ~(size_t)0xFU) * nmemb, mem); \ } \ \ TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc); \ @@ -123,7 +123,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); inline static void ngtcp2_objalloc_##NAME##_init( \ ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \ ngtcp2_objalloc_init( \ - objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem); \ + objalloc, ((sizeof(TYPE) + 0xFU) & ~(size_t)0xFU) * nmemb, mem); \ } \ \ inline static TYPE *ngtcp2_objalloc_##NAME##_get( \ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c index f86e65118df7d8..d146145843b73f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c @@ -408,8 +408,9 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_long(uint8_t *out, size_t outlen, p = out; *p = (uint8_t)(NGTCP2_HEADER_FORM_BIT | - (ngtcp2_pkt_versioned_type(hd->version, hd->type) << 4) | - (uint8_t)(hd->pkt_numlen - 1)); + (uint32_t)(ngtcp2_pkt_versioned_type(hd->version, hd->type) + << 4) | + (uint32_t)(hd->pkt_numlen - 1)); if (!(hd->flags & NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR)) { *p |= NGTCP2_FIXED_BIT_MASK; @@ -775,7 +776,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, } /* TODO We might not decode all ranges. It could be very large. */ - max_rangecnt = ngtcp2_min_size(NGTCP2_MAX_ACK_RANGES, rangecnt); + max_rangecnt = ngtcp2_min(NGTCP2_MAX_ACK_RANGES, rangecnt); p = payload + 1; @@ -2114,7 +2115,7 @@ ngtcp2_ssize ngtcp2_pkt_write_version_negotiation( p = dest; - *p++ = 0xC0 | unused_random; + *p++ = 0xC0U | unused_random; p = ngtcp2_put_uint32be(p, 0); *p++ = (uint8_t)dcidlen; @@ -2186,22 +2187,22 @@ int ngtcp2_pkt_decode_retry(ngtcp2_pkt_retry *dest, const uint8_t *payload, int64_t ngtcp2_pkt_adjust_pkt_num(int64_t max_pkt_num, int64_t pkt_num, size_t pkt_numlen) { - int64_t expected = max_pkt_num + 1; - int64_t win = (int64_t)1 << (pkt_numlen * 8); - int64_t hwin = win / 2; - int64_t mask = win - 1; - int64_t cand = (expected & ~mask) | pkt_num; + uint64_t expected = (uint64_t)max_pkt_num + 1; + uint64_t win = 1ULL << (pkt_numlen * 8); + uint64_t hwin = win / 2; + uint64_t mask = win - 1; + uint64_t cand = (expected & ~mask) | (uint64_t)pkt_num; - if (cand <= expected - hwin) { - assert(cand <= (int64_t)NGTCP2_MAX_VARINT - win); - return cand + win; + if (cand + hwin <= expected) { + assert(cand <= NGTCP2_MAX_VARINT - win); + return (int64_t)(cand + win); } if (cand > expected + hwin && cand >= win) { - return cand - win; + return (int64_t)(cand - win); } - return cand; + return (int64_t)cand; } int ngtcp2_pkt_validate_ack(const ngtcp2_ack *fr, int64_t min_pkt_num) { @@ -2267,7 +2268,7 @@ ngtcp2_pkt_write_stateless_reset2(uint8_t *dest, size_t destlen, p = dest; - randlen = ngtcp2_min_size(destlen - sizeof(token->data), randlen); + randlen = ngtcp2_min(destlen - sizeof(token->data), randlen); p = ngtcp2_cpymem(p, rand, randlen); p = ngtcp2_cpymem(p, token->data, sizeof(token->data)); @@ -2365,7 +2366,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_retry( return NGTCP2_ERR_NOBUF; } - *p &= 0xF0; + *p &= 0xF0U; *p |= unused; p += nwrite; @@ -2439,22 +2440,22 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, left -= n; if (left > 8 + 1073741823 && len > 1073741823) { - len = ngtcp2_min_uint64(len, 4611686018427387903UL); - return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 8)); + len = ngtcp2_min(len, 4611686018427387903UL); + return (size_t)ngtcp2_min(len, (uint64_t)(left - 8)); } if (left > 4 + 16383 && len > 16383) { - len = ngtcp2_min_uint64(len, 1073741823); - return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 4)); + len = ngtcp2_min(len, 1073741823); + return (size_t)ngtcp2_min(len, (uint64_t)(left - 4)); } if (left > 2 + 63 && len > 63) { - len = ngtcp2_min_uint64(len, 16383); - return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 2)); + len = ngtcp2_min(len, 16383); + return (size_t)ngtcp2_min(len, (uint64_t)(left - 2)); } - len = ngtcp2_min_uint64(len, 63); - return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 1)); + len = ngtcp2_min(len, 63); + return (size_t)ngtcp2_min(len, (uint64_t)(left - 1)); } size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { @@ -2470,23 +2471,23 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { if (left > 8 + 1073741823 && len > 1073741823) { #if SIZE_MAX == UINT64_MAX - len = ngtcp2_min_size(len, 4611686018427387903UL); + len = ngtcp2_min(len, 4611686018427387903UL); #endif /* SIZE_MAX == UINT64_MAX */ - return ngtcp2_min_size(len, left - 8); + return ngtcp2_min(len, left - 8); } if (left > 4 + 16383 && len > 16383) { - len = ngtcp2_min_size(len, 1073741823); - return ngtcp2_min_size(len, left - 4); + len = ngtcp2_min(len, 1073741823); + return ngtcp2_min(len, left - 4); } if (left > 2 + 63 && len > 63) { - len = ngtcp2_min_size(len, 16383); - return ngtcp2_min_size(len, left - 2); + len = ngtcp2_min(len, 16383); + return ngtcp2_min(len, left - 2); } - len = ngtcp2_min_size(len, 63); - return ngtcp2_min_size(len, left - 1); + len = ngtcp2_min(len, 63); + return ngtcp2_min(len, left - 1); } size_t ngtcp2_pkt_datagram_framelen(size_t len) { @@ -2869,7 +2870,7 @@ size_t ngtcp2_pkt_remove_vec_partial(ngtcp2_vec *removed_data, ngtcp2_vec *data, } len = 1 + ngtcp2_pcg32_rand_n( - pcg, (uint32_t)ngtcp2_min_size(30, removed_data->len - 1)); + pcg, (uint32_t)ngtcp2_min(30, removed_data->len - 1)); assert(len < removed_data->len); ngtcp2_vec_split_at(&data[datacnt], removed_data, len); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h index bfdb065b74ca91..b6c818d491a596 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h @@ -32,20 +32,20 @@ #include /* QUIC header macros */ -#define NGTCP2_HEADER_FORM_BIT 0x80 -#define NGTCP2_FIXED_BIT_MASK 0x40 -#define NGTCP2_PKT_NUMLEN_MASK 0x03 +#define NGTCP2_HEADER_FORM_BIT 0x80U +#define NGTCP2_FIXED_BIT_MASK 0x40U +#define NGTCP2_PKT_NUMLEN_MASK 0x03U /* Long header specific macros */ -#define NGTCP2_LONG_TYPE_MASK 0x30 -#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0C +#define NGTCP2_LONG_TYPE_MASK 0x30U +#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0CU /* Short header specific macros */ -#define NGTCP2_SHORT_RESERVED_BIT_MASK 0x18 -#define NGTCP2_SHORT_KEY_PHASE_BIT 0x04 +#define NGTCP2_SHORT_RESERVED_BIT_MASK 0x18U +#define NGTCP2_SHORT_KEY_PHASE_BIT 0x04U /* NGTCP2_SR_TYPE is a Type field of Stateless Reset. */ -#define NGTCP2_SR_TYPE 0x1F +#define NGTCP2_SR_TYPE 0x1FU /* NGTCP2_MIN_LONG_HEADERLEN is the minimum length of long header. That is (1|1|TT|RR|PP)<1> + VERSION<4> + DCIL<1> + SCIL<1> + @@ -53,9 +53,9 @@ #define NGTCP2_MIN_LONG_HEADERLEN (1 + 4 + 1 + 1 + 1 + 1) /* STREAM frame specific macros */ -#define NGTCP2_STREAM_FIN_BIT 0x01 -#define NGTCP2_STREAM_LEN_BIT 0x02 -#define NGTCP2_STREAM_OFF_BIT 0x04 +#define NGTCP2_STREAM_FIN_BIT 0x01U +#define NGTCP2_STREAM_LEN_BIT 0x02U +#define NGTCP2_STREAM_OFF_BIT 0x04U /* NGTCP2_MIN_QUIC_PKTLEN is the minimum length of a valid QUIC packet. */ @@ -109,29 +109,29 @@ /* NGTCP2_PKT_TYPE_INITIAL_V1 is Initial long header packet type for QUIC v1. */ -#define NGTCP2_PKT_TYPE_INITIAL_V1 0x0 +#define NGTCP2_PKT_TYPE_INITIAL_V1 0x0U /* NGTCP2_PKT_TYPE_0RTT_V1 is 0RTT long header packet type for QUIC v1. */ -#define NGTCP2_PKT_TYPE_0RTT_V1 0x1 +#define NGTCP2_PKT_TYPE_0RTT_V1 0x1U /* NGTCP2_PKT_TYPE_HANDSHAKE_V1 is Handshake long header packet type for QUIC v1. */ -#define NGTCP2_PKT_TYPE_HANDSHAKE_V1 0x2 +#define NGTCP2_PKT_TYPE_HANDSHAKE_V1 0x2U /* NGTCP2_PKT_TYPE_RETRY_V1 is Retry long header packet type for QUIC v1. */ -#define NGTCP2_PKT_TYPE_RETRY_V1 0x3 +#define NGTCP2_PKT_TYPE_RETRY_V1 0x3U /* NGTCP2_PKT_TYPE_INITIAL_V2 is Initial long header packet type for QUIC v2. */ -#define NGTCP2_PKT_TYPE_INITIAL_V2 0x1 +#define NGTCP2_PKT_TYPE_INITIAL_V2 0x1U /* NGTCP2_PKT_TYPE_0RTT_V2 is 0RTT long header packet type for QUIC v2. */ -#define NGTCP2_PKT_TYPE_0RTT_V2 0x2 +#define NGTCP2_PKT_TYPE_0RTT_V2 0x2U /* NGTCP2_PKT_TYPE_HANDSHAKE_V2 is Handshake long header packet type for QUIC v2. */ -#define NGTCP2_PKT_TYPE_HANDSHAKE_V2 0x3 +#define NGTCP2_PKT_TYPE_HANDSHAKE_V2 0x3U /* NGTCP2_PKT_TYPE_RETRY_V2 is Retry long header packet type for QUIC v2. */ -#define NGTCP2_PKT_TYPE_RETRY_V2 0x0 +#define NGTCP2_PKT_TYPE_RETRY_V2 0x0U /* NGTCP2_MIN_STREAM_DATALEN is the minimum length of STREAM frame to avoid too small frame. It is not always enforced for various @@ -153,32 +153,32 @@ typedef struct ngtcp2_pkt_retry { uint8_t tag[NGTCP2_RETRY_TAGLEN]; } ngtcp2_pkt_retry; -#define NGTCP2_FRAME_PADDING 0x00 -#define NGTCP2_FRAME_PING 0x01 -#define NGTCP2_FRAME_ACK 0x02 -#define NGTCP2_FRAME_ACK_ECN 0x03 -#define NGTCP2_FRAME_RESET_STREAM 0x04 -#define NGTCP2_FRAME_STOP_SENDING 0x05 -#define NGTCP2_FRAME_CRYPTO 0x06 -#define NGTCP2_FRAME_NEW_TOKEN 0x07 -#define NGTCP2_FRAME_STREAM 0x08 -#define NGTCP2_FRAME_MAX_DATA 0x10 -#define NGTCP2_FRAME_MAX_STREAM_DATA 0x11 -#define NGTCP2_FRAME_MAX_STREAMS_BIDI 0x12 -#define NGTCP2_FRAME_MAX_STREAMS_UNI 0x13 -#define NGTCP2_FRAME_DATA_BLOCKED 0x14 -#define NGTCP2_FRAME_STREAM_DATA_BLOCKED 0x15 -#define NGTCP2_FRAME_STREAMS_BLOCKED_BIDI 0x16 -#define NGTCP2_FRAME_STREAMS_BLOCKED_UNI 0x17 -#define NGTCP2_FRAME_NEW_CONNECTION_ID 0x18 -#define NGTCP2_FRAME_RETIRE_CONNECTION_ID 0x19 -#define NGTCP2_FRAME_PATH_CHALLENGE 0x1A -#define NGTCP2_FRAME_PATH_RESPONSE 0x1B -#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1C -#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1D -#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1E -#define NGTCP2_FRAME_DATAGRAM 0x30 -#define NGTCP2_FRAME_DATAGRAM_LEN 0x31 +#define NGTCP2_FRAME_PADDING 0x00U +#define NGTCP2_FRAME_PING 0x01U +#define NGTCP2_FRAME_ACK 0x02U +#define NGTCP2_FRAME_ACK_ECN 0x03U +#define NGTCP2_FRAME_RESET_STREAM 0x04U +#define NGTCP2_FRAME_STOP_SENDING 0x05U +#define NGTCP2_FRAME_CRYPTO 0x06U +#define NGTCP2_FRAME_NEW_TOKEN 0x07U +#define NGTCP2_FRAME_STREAM 0x08U +#define NGTCP2_FRAME_MAX_DATA 0x10U +#define NGTCP2_FRAME_MAX_STREAM_DATA 0x11U +#define NGTCP2_FRAME_MAX_STREAMS_BIDI 0x12U +#define NGTCP2_FRAME_MAX_STREAMS_UNI 0x13U +#define NGTCP2_FRAME_DATA_BLOCKED 0x14U +#define NGTCP2_FRAME_STREAM_DATA_BLOCKED 0x15U +#define NGTCP2_FRAME_STREAMS_BLOCKED_BIDI 0x16U +#define NGTCP2_FRAME_STREAMS_BLOCKED_UNI 0x17U +#define NGTCP2_FRAME_NEW_CONNECTION_ID 0x18U +#define NGTCP2_FRAME_RETIRE_CONNECTION_ID 0x19U +#define NGTCP2_FRAME_PATH_CHALLENGE 0x1AU +#define NGTCP2_FRAME_PATH_RESPONSE 0x1BU +#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1CU +#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1DU +#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1EU +#define NGTCP2_FRAME_DATAGRAM 0x30U +#define NGTCP2_FRAME_DATAGRAM_LEN 0x31U typedef struct ngtcp2_frame_hd { uint64_t type; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c index ebd113f6746217..3827cba9afe910 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c @@ -134,7 +134,7 @@ static void pmtud_next_probe(ngtcp2_pmtud *pmtud) { void ngtcp2_pmtud_probe_success(ngtcp2_pmtud *pmtud, size_t payloadlen) { pmtud->max_udp_payload_size = - ngtcp2_max_size(pmtud->max_udp_payload_size, payloadlen); + ngtcp2_max(pmtud->max_udp_payload_size, payloadlen); assert(pmtud->mtu_idx < pmtud->probeslen); @@ -156,8 +156,8 @@ void ngtcp2_pmtud_handle_expiry(ngtcp2_pmtud *pmtud, ngtcp2_tstamp ts) { return; } - pmtud->min_fail_udp_payload_size = ngtcp2_min_size( - pmtud->min_fail_udp_payload_size, pmtud->probes[pmtud->mtu_idx]); + pmtud->min_fail_udp_payload_size = + ngtcp2_min(pmtud->min_fail_udp_payload_size, pmtud->probes[pmtud->mtu_idx]); pmtud_next_probe(pmtud); } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c index 3054732db047e6..81bc3296de85ae 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c @@ -44,6 +44,14 @@ void ngtcp2_ppe_init(ngtcp2_ppe *ppe, uint8_t *out, size_t outlen, ppe->cc = cc; } +/* + * ppe_sample_offset returns the offset to sample for packet number + * encryption. + */ +static size_t ppe_sample_offset(ngtcp2_ppe *ppe) { + return ppe->pkt_num_offset + 4; +} + int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { ngtcp2_ssize rv; ngtcp2_buf *buf = &ppe->buf; @@ -78,6 +86,10 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { buf->last += rv; + if (ngtcp2_buf_cap(buf) < ppe_sample_offset(ppe) + NGTCP2_HP_SAMPLELEN) { + return NGTCP2_ERR_NOBUF; + } + ppe->pkt_numlen = hd->pkt_numlen; ppe->hdlen = (size_t)rv; ppe->pkt_num = hd->pkt_num; @@ -105,14 +117,6 @@ int ngtcp2_ppe_encode_frame(ngtcp2_ppe *ppe, ngtcp2_frame *fr) { return 0; } -/* - * ppe_sample_offset returns the offset to sample for packet number - * encryption. - */ -static size_t ppe_sample_offset(ngtcp2_ppe *ppe) { - return ppe->pkt_num_offset + 4; -} - ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { ngtcp2_buf *buf = &ppe->buf; ngtcp2_crypto_cc *cc = ppe->cc; @@ -154,9 +158,9 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { p = buf->begin; if (*p & NGTCP2_HEADER_FORM_BIT) { - *p = (uint8_t)(*p ^ (mask[0] & 0x0F)); + *p = (uint8_t)(*p ^ (mask[0] & 0x0FU)); } else { - *p = (uint8_t)(*p ^ (mask[0] & 0x1F)); + *p = (uint8_t)(*p ^ (mask[0] & 0x1FU)); } p = buf->begin + ppe->pkt_num_offset; @@ -187,21 +191,21 @@ size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) { ngtcp2_buf *buf = &ppe->buf; size_t pktlen = ngtcp2_buf_len(buf) + cc->aead.max_overhead; size_t len = 0; - size_t max_samplelen; + size_t min_pktlen; - n = ngtcp2_min_size(n, ngtcp2_buf_cap(buf)); + n = ngtcp2_min(n, ngtcp2_buf_cap(buf)); if (pktlen < n) { len = n - pktlen; } /* Ensure header protection sample */ - max_samplelen = - ngtcp2_buf_len(buf) + cc->aead.max_overhead - ppe_sample_offset(ppe); - - if (max_samplelen < NGTCP2_HP_SAMPLELEN) { - len = ngtcp2_max_size(len, NGTCP2_HP_SAMPLELEN - max_samplelen); + min_pktlen = ppe_sample_offset(ppe) + NGTCP2_HP_SAMPLELEN; + if (pktlen < min_pktlen) { + len = ngtcp2_max(len, min_pktlen - pktlen); } + /* ngtcp2_ppe_encode_hd ensures that the buffer has enough capacity + for the padding required for header protection sample. */ assert(ngtcp2_buf_left(buf) >= len + cc->aead.max_overhead); if (len == 0) { @@ -220,24 +224,34 @@ size_t ngtcp2_ppe_dgram_padding(ngtcp2_ppe *ppe) { size_t ngtcp2_ppe_dgram_padding_size(ngtcp2_ppe *ppe, size_t n) { ngtcp2_crypto_cc *cc = ppe->cc; ngtcp2_buf *buf = &ppe->buf; - size_t dgramlen = - ppe->dgram_offset + ngtcp2_buf_len(buf) + cc->aead.max_overhead; + size_t pktlen = ngtcp2_buf_len(buf) + cc->aead.max_overhead; + size_t dgramlen = ppe->dgram_offset + pktlen; size_t len; + size_t min_pktlen; - n = ngtcp2_min_size(n, ppe->dgram_offset + ngtcp2_buf_cap(buf)); + n = ngtcp2_min(n, ppe->dgram_offset + ngtcp2_buf_cap(buf)); - if (dgramlen >= n) { + if (dgramlen < n) { + len = n - dgramlen; + } else { + len = 0; + } + + /* Ensure header protection sample */ + min_pktlen = ppe_sample_offset(ppe) + NGTCP2_HP_SAMPLELEN; + if (pktlen < min_pktlen) { + len = ngtcp2_max(len, min_pktlen - pktlen); + } + + /* ngtcp2_ppe_encode_hd ensures that the buffer has enough capacity + for the padding required for header protection sample. */ + assert(ngtcp2_buf_left(buf) >= len + cc->aead.max_overhead); + + if (len == 0) { return 0; } - len = n - dgramlen; buf->last = ngtcp2_setmem(buf->last, 0, len); return len; } - -int ngtcp2_ppe_ensure_hp_sample(ngtcp2_ppe *ppe) { - ngtcp2_buf *buf = &ppe->buf; - - return ngtcp2_buf_left(buf) >= (4 - ppe->pkt_numlen) + NGTCP2_HP_SAMPLELEN; -} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.h index 9874b36800540d..ba9edc698ad20a 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.h @@ -125,7 +125,9 @@ size_t ngtcp2_ppe_dgram_padding(ngtcp2_ppe *ppe); * of a UDP datagram payload is at least |n| bytes long. If it is * unable to add PADDING in that way, this function still adds PADDING * frame as much as possible. This function should be called just - * before calling ngtcp2_ppe_final(). + * before calling ngtcp2_ppe_final(). This function also ensures that + * the packet has enough space for header protection sample by + * possibly adding extra padding more than |n|. * * This function returns the number of bytes added as padding. */ @@ -138,20 +140,11 @@ size_t ngtcp2_ppe_dgram_padding_size(ngtcp2_ppe *ppe, size_t n); * PADDING at least |n| bytes, this function still adds PADDING frames * as much as possible. This function also adds PADDING frames so * that the minimum padding requirement of header protection is met. - * Those padding may be larger than |n| bytes. It is recommended to - * make sure that ngtcp2_ppe_ensure_hp_sample succeeds after writing - * QUIC packet header. This function should be called just before - * calling ngtcp2_ppe_final(). + * Those padding may be larger than |n| bytes. This function should + * be called just before calling ngtcp2_ppe_final(). * * This function returns the number of bytes added as padding. */ size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n); -/* - * ngtcp2_ppe_ensure_hp_sample returns nonzero if the buffer has - * enough space for header protection sample. This should be called - * right after packet header is written. - */ -int ngtcp2_ppe_ensure_hp_sample(ngtcp2_ppe *ppe); - #endif /* !defined(NGTCP2_PPE_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pq.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pq.c index 162bed00156755..87d261dd750bd5 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pq.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pq.c @@ -30,11 +30,10 @@ #include "ngtcp2_macro.h" void ngtcp2_pq_init(ngtcp2_pq *pq, ngtcp2_pq_less less, const ngtcp2_mem *mem) { - pq->q = NULL; - pq->mem = mem; - pq->length = 0; - pq->capacity = 0; - pq->less = less; + *pq = (ngtcp2_pq){ + .mem = mem, + .less = less, + }; } void ngtcp2_pq_free(ngtcp2_pq *pq) { @@ -74,7 +73,7 @@ int ngtcp2_pq_push(ngtcp2_pq *pq, ngtcp2_pq_entry *item) { void *nq; size_t ncapacity; - ncapacity = ngtcp2_max_size(4, pq->capacity * 2); + ncapacity = ngtcp2_max(4, pq->capacity * 2); nq = ngtcp2_mem_realloc(pq->mem, pq->q, ncapacity * sizeof(ngtcp2_pq_entry *)); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c index 972c27f395a28d..12b81eb80332e1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c @@ -148,7 +148,7 @@ int ngtcp2_pv_validation_timed_out(ngtcp2_pv *pv, ngtcp2_tstamp ts) { ent = ngtcp2_ringbuf_get(&pv->ents.rb, ngtcp2_ringbuf_len(&pv->ents.rb) - 1); t = pv->started_ts + pv->timeout; - t = ngtcp2_max_uint64(t, ent->expiry); + t = ngtcp2_max(t, ent->expiry); return t <= ts; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c index 42609481ec4757..9f233b6cd83819 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c @@ -1120,6 +1120,9 @@ void ngtcp2_qlog_stateless_reset_pkt_received( ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset2 *sr) { uint8_t buf[256]; uint8_t *p = buf; + static const ngtcp2_pkt_hd hd = { + .type = NGTCP2_PKT_STATELESS_RESET, + }; if (!qlog->write) { return; @@ -1130,9 +1133,7 @@ void ngtcp2_qlog_stateless_reset_pkt_received( p = qlog_write_time(qlog, p); p = write_verbatim( p, ",\"name\":\"transport:packet_received\",\"data\":{\"header\":"); - p = write_pkt_hd(p, &(ngtcp2_pkt_hd){ - .type = NGTCP2_PKT_STATELESS_RESET, - }); + p = write_pkt_hd(p, &hd); *p++ = ','; p = write_pair_hex(p, "stateless_reset_token", sr->token.data, sizeof(sr->token.data)); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_range.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_range.c index a949a657338e29..8cb43830fb3d8b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_range.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_range.c @@ -35,8 +35,8 @@ void ngtcp2_range_init(ngtcp2_range *r, uint64_t begin, uint64_t end) { ngtcp2_range ngtcp2_range_intersect(const ngtcp2_range *a, const ngtcp2_range *b) { ngtcp2_range r; - uint64_t begin = ngtcp2_max_uint64(a->begin, b->begin); - uint64_t end = ngtcp2_min_uint64(a->end, b->end); + uint64_t begin = ngtcp2_max(a->begin, b->begin); + uint64_t end = ngtcp2_min(a->end, b->end); if (begin < end) { ngtcp2_range_init(&r, begin, end); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c index 20eae1d8819133..e45351be2b55aa 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c @@ -161,8 +161,7 @@ static int rob_write_data(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, } } - n = (size_t)ngtcp2_min_uint64((uint64_t)len, - d->range.begin + rob->chunk - offset); + n = (size_t)ngtcp2_min((uint64_t)len, d->range.begin + rob->chunk - offset); memcpy(d->begin + (offset - d->range.begin), data, n); offset += n; data += n; @@ -317,9 +316,8 @@ size_t ngtcp2_rob_data_at(const ngtcp2_rob *rob, const uint8_t **pdest, *pdest = d->begin + (offset - d->range.begin); - return ( - size_t)(ngtcp2_min_uint64(g->range.begin, d->range.begin + rob->chunk) - - offset); + return (size_t)(ngtcp2_min(g->range.begin, d->range.begin + rob->chunk) - + offset); } void ngtcp2_rob_pop(ngtcp2_rob *rob, uint64_t offset, size_t len) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c index 89b395cd954b0d..7792ebe41ba67f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c @@ -35,12 +35,12 @@ void ngtcp2_rs_init(ngtcp2_rs *rs) { *rs = (ngtcp2_rs){ .interval = UINT64_MAX, .prior_ts = UINT64_MAX, - .last_end_seq = -1, + .last_acked_pkt_id = -1, }; } void ngtcp2_rst_init(ngtcp2_rst *rst) { - rst->last_seq = -1; + rst->pkt_id = -1; ngtcp2_rst_reset(rst); } @@ -76,7 +76,7 @@ void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, ent->rst.is_app_limited = rst->app_limited != 0; ent->rst.tx_in_flight = cstat->bytes_in_flight; ent->rst.lost = rst->lost; - ent->rst.end_seq = ++rst->last_seq; + ent->rst.pkt_id = ++rst->pkt_id; } void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) { @@ -90,7 +90,7 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) { return; } - rs->interval = ngtcp2_max_uint64(rs->send_elapsed, rs->ack_elapsed); + rs->interval = ngtcp2_max(rs->send_elapsed, rs->ack_elapsed); rs->delivered = rst->delivered - rs->prior_delivered; @@ -106,7 +106,7 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) { } static int is_newest_pkt(const ngtcp2_rtb_entry *ent, const ngtcp2_rs *rs) { - return ent->rst.end_seq > rs->last_end_seq; + return ent->rst.pkt_id > rs->last_acked_pkt_id; } void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, @@ -122,7 +122,7 @@ void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, rs->is_app_limited = ent->rst.is_app_limited; rs->send_elapsed = ent->ts - ent->rst.first_sent_ts; rs->ack_elapsed = rst->delivered_ts - ent->rst.delivered_ts; - rs->last_end_seq = ent->rst.end_seq; + rs->last_acked_pkt_id = ent->rst.pkt_id; rst->first_sent_ts = ent->ts; } } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h index b0bc2d06c9ca50..86346f49295add 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h @@ -50,7 +50,7 @@ typedef struct ngtcp2_rs { uint64_t lost; ngtcp2_duration send_elapsed; ngtcp2_duration ack_elapsed; - int64_t last_end_seq; + int64_t last_acked_pkt_id; int is_app_limited; } ngtcp2_rs; @@ -67,11 +67,11 @@ typedef struct ngtcp2_rst { ngtcp2_tstamp first_sent_ts; uint64_t app_limited; uint64_t lost; - /* last_seq is the sequence number of packets across all packet - number spaces. If we would adopt single packet number sequence - across all packet number spaces, we can replace this with a - packet number. */ - int64_t last_seq; + /* pkt_id is the identifier of packets across all packet number + spaces. If we would adopt single packet number sequence across + all packet number spaces, we can replace this with a packet + number. */ + int64_t pkt_id; int is_cwnd_limited; } ngtcp2_rst; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c index 67aaa0493028f9..e8d05a3feadce9 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c @@ -482,9 +482,8 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { - ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC, - "pkn=%" PRId64 " has already been reclaimed on PTO", - ent->hd.pkt_num); + ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=", ent->hd.pkt_num, + " has already been reclaimed on PTO"); assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)); assert(UINT64_MAX == ent->lost_ts); } else { @@ -596,7 +595,7 @@ static int process_acked_pkt(ngtcp2_rtb_entry *ent, ngtcp2_conn *conn, if (conn->dcid.current.max_udp_payload_size < ent->pktlen) { conn->dcid.current.max_udp_payload_size = ent->pktlen; conn->cstat.max_tx_udp_payload_size = - ngtcp2_conn_get_path_max_tx_udp_payload_size(conn); + ngtcp2_conn_get_path_max_tx_udp_payload_size2(conn); } if (ngtcp2_pmtud_finished(conn->pmtud)) { @@ -903,8 +902,8 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, } if (cc_ack.largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) { - cc_ack.rtt = ngtcp2_max_uint64(pkt_ts - cc_ack.largest_pkt_sent_ts, - NGTCP2_NANOSECONDS); + cc_ack.rtt = + ngtcp2_max(pkt_ts - cc_ack.largest_pkt_sent_ts, NGTCP2_NANOSECONDS); ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts); } @@ -999,7 +998,7 @@ static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, if (loss_time == UINT64_MAX) { loss_time = ent->ts + loss_delay; } else { - loss_time = ngtcp2_min_uint64(loss_time, ent->ts + loss_delay); + loss_time = ngtcp2_min(loss_time, ent->ts + loss_delay); } cstat->loss_time[pktns->id] = loss_time; @@ -1013,8 +1012,8 @@ static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, static ngtcp2_duration compute_pkt_loss_delay(const ngtcp2_conn_stat *cstat) { /* 9/8 is kTimeThreshold */ ngtcp2_duration loss_delay = - ngtcp2_max_uint64(cstat->latest_rtt, cstat->smoothed_rtt) * 9 / 8; - return ngtcp2_max_uint64(loss_delay, NGTCP2_GRANULARITY); + ngtcp2_max(cstat->latest_rtt, cstat->smoothed_rtt) * 9 / 8; + return ngtcp2_max(loss_delay, NGTCP2_GRANULARITY); } /* @@ -1056,8 +1055,8 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack, uint64_t bytes_lost = 0; ngtcp2_duration max_ack_delay; - pkt_thres = ngtcp2_max_uint64(pkt_thres, NGTCP2_PKT_THRESHOLD); - pkt_thres = ngtcp2_min_uint64(pkt_thres, 256); + pkt_thres = ngtcp2_max(pkt_thres, NGTCP2_PKT_THRESHOLD); + pkt_thres = ngtcp2_min(pkt_thres, 256); cstat->loss_time[pktns->id] = UINT64_MAX; loss_delay = compute_pkt_loss_delay(cstat); @@ -1082,12 +1081,11 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack, congestion_period = (cstat->smoothed_rtt + - ngtcp2_max_uint64(4 * cstat->rttvar, NGTCP2_GRANULARITY) + - max_ack_delay) * + ngtcp2_max(4 * cstat->rttvar, NGTCP2_GRANULARITY) + max_ack_delay) * NGTCP2_PERSISTENT_CONGESTION_THRESHOLD; - start_ts = ngtcp2_max_uint64(conn->handshake_confirmed_ts, - cstat->first_rtt_sample_ts); + start_ts = + ngtcp2_max(conn->handshake_confirmed_ts, cstat->first_rtt_sample_ts); for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { ent = ngtcp2_ksl_it_get(&it); @@ -1172,9 +1170,8 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_cc_ack *cc_ack, if (pktns->id == NGTCP2_PKTNS_ID_APPLICATION && loss_window && loss_window >= congestion_period) { ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC, - "persistent congestion loss_window=%" PRIu64 - " congestion_period=%" PRIu64, - loss_window, congestion_period); + "persistent congestion loss_window=", loss_window, + " congestion_period=", congestion_period); /* Reset min_rtt, srtt, and rttvar here. Next new RTT sample will be used to recalculate these values. */ @@ -1222,7 +1219,7 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) { assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED); ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC, - "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); + "removing stale lost pkn=", ent->hd.pkt_num); --rtb->num_lost_pkts; @@ -1265,7 +1262,7 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, } ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC, - "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); + "removing stale lost pkn=", ent->hd.pkt_num); --rtb->num_lost_pkts; @@ -1417,9 +1414,8 @@ int ngtcp2_rtb_reclaim_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn, assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE)); if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { - ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC, - "pkn=%" PRId64 " has already been reclaimed on PTO", - ent->hd.pkt_num); + ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=", ent->hd.pkt_num, + " has already been reclaimed on PTO"); ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc, rtb->frc_objalloc, rtb->mem); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h index 62bcb381fa15bb..664498be962803 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h @@ -115,7 +115,7 @@ struct ngtcp2_rtb_entry { ngtcp2_tstamp first_sent_ts; uint64_t tx_in_flight; uint64_t lost; - int64_t end_seq; + int64_t pkt_id; int is_app_limited; } rst; /* flags is bitwise-OR of zero or more of diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_settings.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_settings.c index f774504282e6b1..31c52b4d957199 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_settings.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_settings.c @@ -37,6 +37,7 @@ void ngtcp2_settings_default_versioned(int settings_version, switch (settings_version) { case NGTCP2_SETTINGS_VERSION: + case NGTCP2_SETTINGS_V3: settings->glitch_ratelim_burst = NGTCP2_DEFAULT_GLITCH_RATELIM_BURST; settings->glitch_ratelim_rate = NGTCP2_DEFAULT_GLITCH_RATELIM_RATE; /* fall through */ @@ -86,6 +87,9 @@ size_t ngtcp2_settingslen_version(int settings_version) { switch (settings_version) { case NGTCP2_SETTINGS_VERSION: return sizeof(settings); + case NGTCP2_SETTINGS_V3: + return offsetof(ngtcp2_settings, glitch_ratelim_rate) + + sizeof(settings.glitch_ratelim_rate); case NGTCP2_SETTINGS_V2: return offsetof(ngtcp2_settings, pmtud_probeslen) + sizeof(settings.pmtud_probeslen); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c index 2726571a504070..dd5ef5a1af6f6c 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c @@ -25,8 +25,10 @@ #include "ngtcp2_str.h" #include +#include #include "ngtcp2_macro.h" +#include "ngtcp2_unreachable.h" void *ngtcp2_cpymem(void *dest, const void *src, size_t n) { memcpy(dest, src, n); @@ -38,6 +40,22 @@ uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n) { return dest + n; } +void ngtcp2_secure_clear(void *data, size_t len) { +#ifdef WIN32 + SecureZeroMemory(data, len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(data, len); +#elif defined(HAVE_MEMSET_S) + memset_s(data, len, 0, len); +#else /* !defined(WIN32) && !defined(HAVE_EXPLICIT_BZERO) && \ + !defined(HAVE_MEMSET_S) */ + static void *(*volatile memset_ptr)(void *, int, size_t) = memset; + + memset_ptr(data, 0, len); +#endif /* !defined(WIN32) && !defined(HAVE_EXPLICIT_BZERO) && \ + !defined(HAVE_MEMSET_S) */ +} + const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n) { memcpy(dest, src, n); return (uint8_t *)src + n; @@ -50,53 +68,98 @@ uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) { for (i = 0; i < len; ++i) { *dest++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4]; - *dest++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xF]; + *dest++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xFU]; } return dest; } -char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len) { - uint8_t *p = ngtcp2_encode_hex((uint8_t *)dest, data, len); +size_t ngtcp2_encode_uint_hexlen(uint64_t n) { + size_t i; + uint8_t d; + + if (n == 0) { + return 1; + } + + for (i = 0; i < sizeof(n); ++i) { + d = (uint8_t)(n >> (sizeof(n) - 1 - i) * 8); + if (!d) { + continue; + } + + if (d >> 4) { + return (sizeof(n) - i) * 2; + } + + return (sizeof(n) - i) * 2 - 1; + } + + ngtcp2_unreachable(); +} + +uint8_t *ngtcp2_encode_uint_hex(uint8_t *dest, uint64_t n) { + size_t i; + uint8_t d; + + if (n == 0) { + *dest++ = '0'; + + return dest; + } + + for (i = 0; i < sizeof(n); ++i) { + d = (uint8_t)(n >> (sizeof(n) - 1 - i) * 8); + if (d) { + if (d >> 4) { + *dest++ = (uint8_t)LOWER_XDIGITS[d >> 4]; + } - *p = '\0'; + *dest++ = (uint8_t)LOWER_XDIGITS[d & 0xFU]; + ++i; + + break; + } + } + + for (; i < sizeof(n); ++i) { + d = (uint8_t)(n >> (sizeof(n) - 1 - i) * 8); + + *dest++ = (uint8_t)LOWER_XDIGITS[d >> 4]; + *dest++ = (uint8_t)LOWER_XDIGITS[d & 0xFU]; + } return dest; } -char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data, - size_t len) { +uint8_t *ngtcp2_encode_printable_ascii(uint8_t *dest, const uint8_t *data, + size_t len) { size_t i; - char *p = dest; uint8_t c; for (i = 0; i < len; ++i) { c = data[i]; if (0x20 <= c && c <= 0x7E) { - *p++ = (char)c; + *dest++ = c; } else { - *p++ = '.'; + *dest++ = '.'; } } - *p = '\0'; - return dest; } -char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr) { +uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const ngtcp2_in_addr *addr) { size_t i; - char *p = dest; + const uint8_t *in = (const uint8_t *)addr; - p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[0]); + dest = ngtcp2_encode_uint(dest, in[0]); for (i = 1; i < 4; ++i) { - *p++ = '.'; - p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[i]); + *dest++ = '.'; + dest = ngtcp2_encode_uint(dest, in[i]); } - *p = '\0'; - return dest; } @@ -105,9 +168,9 @@ char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr) { * length |len| to |dest| in hex string. Any leading zeros are * suppressed. It returns |dest| plus the number of bytes written. */ -static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) { +static uint8_t *write_hex_zsup(uint8_t *dest, const uint8_t *data, size_t len) { size_t i; - char *p = dest; + uint8_t *p = dest; uint8_t d; for (i = 0; i < len; ++i) { @@ -116,10 +179,10 @@ static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) { break; } - d &= 0xF; + d &= 0xFU; if (d) { - *p++ = LOWER_XDIGITS[d]; + *p++ = (uint8_t)LOWER_XDIGITS[d]; ++i; break; } @@ -132,23 +195,23 @@ static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) { for (; i < len; ++i) { d = data[i]; - *p++ = LOWER_XDIGITS[d >> 4]; - *p++ = LOWER_XDIGITS[d & 0xF]; + *p++ = (uint8_t)LOWER_XDIGITS[d >> 4]; + *p++ = (uint8_t)LOWER_XDIGITS[d & 0xFU]; } return p; } -char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr) { +uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const ngtcp2_in6_addr *addr) { uint16_t blks[8]; size_t i; size_t zlen, zoff; size_t max_zlen = 0, max_zoff = 8; - char *p = dest; + const uint8_t *in = (const uint8_t *)addr; for (i = 0; i < 16; i += sizeof(uint16_t)) { /* Copy in network byte order. */ - memcpy(&blks[i / sizeof(uint16_t)], addr + i, sizeof(uint16_t)); + memcpy(&blks[i / sizeof(uint16_t)], in + i, sizeof(uint16_t)); } for (i = 0; i < 8;) { @@ -175,29 +238,29 @@ char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr) { } if (max_zoff != 0) { - p = write_hex_zsup(p, (const uint8_t *)blks, sizeof(uint16_t)); + dest = write_hex_zsup(dest, (const uint8_t *)blks, sizeof(uint16_t)); for (i = 1; i < max_zoff; ++i) { - *p++ = ':'; - p = write_hex_zsup(p, (const uint8_t *)(blks + i), sizeof(uint16_t)); + *dest++ = ':'; + dest = + write_hex_zsup(dest, (const uint8_t *)(blks + i), sizeof(uint16_t)); } } if (max_zoff != 8) { - *p++ = ':'; + *dest++ = ':'; if (max_zoff + max_zlen == 8) { - *p++ = ':'; + *dest++ = ':'; } else { for (i = max_zoff + max_zlen; i < 8; ++i) { - *p++ = ':'; - p = write_hex_zsup(p, (const uint8_t *)(blks + i), sizeof(uint16_t)); + *dest++ = ':'; + dest = + write_hex_zsup(dest, (const uint8_t *)(blks + i), sizeof(uint16_t)); } } } - *p = '\0'; - return dest; } @@ -290,6 +353,8 @@ static size_t count_digit(uint64_t x) { return y + 1; } +size_t ngtcp2_encode_uintlen(uint64_t n) { return count_digit(n); } + uint8_t *ngtcp2_encode_uint(uint8_t *dest, uint64_t n) { static const uint8_t uint_digits[] = "00010203040506070809101112131415161718192021222324252627282930313233343536" diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h index 051053d75b7c04..abda53e46d528e 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h @@ -53,43 +53,47 @@ const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n); uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len); /* - * ngtcp2_encode_hex_cstr encodes |data| of length |len| in hex - * string. It writes additional NULL bytes at the end of the buffer. - * The buffer pointed by |dest| must have at least |len| * 2 + 1 bytes - * space. This function returns |dest|. + * ngtcp2_encode_uint_hexlen returns the number of bytes + * ngtcp2_encode_uint_hex produces when |n| is given. */ -char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len); +size_t ngtcp2_encode_uint_hexlen(uint64_t n); /* - * ngtcp2_encode_ipv4_cstr encodes binary form IPv4 address stored in + * ngtcp2_encode_uint_hex encodes |n| in hex string. It omits the + * leading zeros (e.g., 1fb). The buffer pointed by |dest| must have + * at least ngtcp2_encode_uint_hexlen(|n|) bytes. This function + * returns |dest| + the number of bytes written. + */ +uint8_t *ngtcp2_encode_uint_hex(uint8_t *dest, uint64_t n); + +/* + * ngtcp2_encode_ipv4 encodes binary form IPv4 address stored in * |addr| to human readable text form in the buffer pointed by |dest|. - * The capacity of buffer must have enough length to store a text form - * plus a terminating NULL byte. The resulting text form ends with - * NULL byte. The function returns |dest|. + * The capacity of buffer must have enough length to store a text + * form. The function returns |dest| + the number of bytes written. */ -char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr); +uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const ngtcp2_in_addr *addr); /* - * ngtcp2_encode_ipv6_cstr encodes binary form IPv6 address stored in + * ngtcp2_encode_ipv6 encodes binary form IPv6 address stored in * |addr| to human readable text form in the buffer pointed by |dest|. - * The capacity of buffer must have enough length to store a text form - * plus a terminating NULL byte. The resulting text form ends with - * NULL byte. The function produces the canonical form of IPv6 text + * The capacity of buffer must have enough length to store a text + * form. The function produces the canonical form of IPv6 text * representation described in * https://tools.ietf.org/html/rfc5952#section-4. The function - * returns |dest|. + * returns |dest| + the number of bytes written. */ -char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr); +uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const ngtcp2_in6_addr *addr); /* * ngtcp2_encode_printable_ascii encodes |data| of length |len| in * |dest| in the following manner: printable ascii characters are - * copied as is. The other characters are converted to ".". It - * writes additional NULL bytes at the end of the buffer. |dest| must - * have at least |len| + 1 bytes. This function returns |dest|. + * copied as is. The other characters are converted to ".". |dest| + * must have at least |len|. This function returns |dest| + the + * number of bytes written. */ -char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data, - size_t len); +uint8_t *ngtcp2_encode_printable_ascii(uint8_t *dest, const uint8_t *data, + size_t len); /* * ngtcp2_cmemeq returns nonzero if the first |n| bytes of the buffers @@ -98,6 +102,12 @@ char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data, */ int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n); +/* + * ngtcp2_encode_uintlen returns the number of bytes + * ngtcp2_encode_uint produces when |n| is given. + */ +size_t ngtcp2_encode_uintlen(uint64_t n); + /* * ngtcp2_encode_uint encodes |n| as a decimal integer to the buffer * pointed by |dest|. This function assumes that the buffer contains diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c index 5d378176e16289..f28c4f57b15967 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c @@ -586,6 +586,9 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version, if (decode_varint_param(¶ms->max_idle_timeout, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } + if (params->max_idle_timeout > UINT64_MAX / NGTCP2_MILLISECONDS) { + params->max_idle_timeout = UINT64_MAX; + } params->max_idle_timeout *= NGTCP2_MILLISECONDS; break; case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE: @@ -733,7 +736,7 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version, if ((size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - if (valuelen < sizeof(uint32_t) || (valuelen & 0x3)) { + if (valuelen < sizeof(uint32_t) || (valuelen & 0x3U)) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } p = ngtcp2_get_uint32be(¶ms->version_info.chosen_version, p); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h index d98d034b3c28be..0ea85edb0a4dc6 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h @@ -35,28 +35,28 @@ parameter ID. */ typedef uint64_t ngtcp2_transport_param_id; -#define NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID 0x00 -#define NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT 0x01 -#define NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN 0x02 -#define NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE 0x03 -#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA 0x04 -#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 0x05 -#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 0x06 -#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI 0x07 -#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI 0x08 -#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI 0x09 -#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0A -#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0B -#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0C -#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0D -#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0E -#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0F -#define NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID 0x10 +#define NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID 0x00U +#define NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT 0x01U +#define NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN 0x02U +#define NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE 0x03U +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA 0x04U +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 0x05U +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 0x06U +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI 0x07U +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI 0x08U +#define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI 0x09U +#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0AU +#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0BU +#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0CU +#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0DU +#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0EU +#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0FU +#define NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID 0x10U /* https://datatracker.ietf.org/doc/html/rfc9221 */ -#define NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE 0x20 -#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2AB2 +#define NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE 0x20U +#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2AB2U /* https://datatracker.ietf.org/doc/html/rfc9368 */ -#define NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION 0x11 +#define NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION 0x11U /* NGTCP2_MAX_STREAMS is the maximum number of streams. */ #define NGTCP2_MAX_STREAMS (1LL << 60)