From 674d31d57f351a292904a4b1b3ef3aa4ef7a21e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 23 Dec 2023 14:39:35 +0100 Subject: [PATCH 1/2] tools: fix update-ngtcp2 script --- tools/dep_updaters/update-ngtcp2.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/dep_updaters/update-ngtcp2.sh b/tools/dep_updaters/update-ngtcp2.sh index a77be7efa8558f..8e29dc0c60dd43 100755 --- a/tools/dep_updaters/update-ngtcp2.sh +++ b/tools/dep_updaters/update-ngtcp2.sh @@ -63,9 +63,11 @@ autoreconf -i ./configure --prefix="$PWD/build" --enable-lib-only -cp -R lib/* "$DEPS_DIR/ngtcp2/ngtcp2/lib/" +rm -rf "$DEPS_DIR/ngtcp2/ngtcp2/lib/" +cp -R lib "$DEPS_DIR/ngtcp2/ngtcp2/lib/" -cp -R crypto/* "$DEPS_DIR/ngtcp2/ngtcp2/crypto/" +rm -rf "$DEPS_DIR/ngtcp2/ngtcp2/crypto/" +cp -R crypto "$DEPS_DIR/ngtcp2/ngtcp2/crypto/" # Update the version number on maintaining-dependencies.md # and print the new version as the last line of the script as we need From aa87692607510e7f3d202639a1faa1e05f7801c5 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Sun, 19 Nov 2023 00:26:01 +0000 Subject: [PATCH 2/2] deps: update ngtcp2 to 1.1.0 --- deps/ngtcp2/ngtcp2.gyp | 9 +- .../ngtcp2/crypto/boringssl/boringssl.c | 116 +- .../crypto/includes/ngtcp2/ngtcp2_crypto.h | 304 +- .../includes/ngtcp2/ngtcp2_crypto_boringssl.h | 16 +- .../includes/ngtcp2/ngtcp2_crypto_picotls.h | 20 +- ...ypto_openssl.h => ngtcp2_crypto_quictls.h} | 59 +- .../includes/ngtcp2/ngtcp2_crypto_wolfssl.h | 16 +- deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c | 112 +- .../{openssl/openssl.c => quictls/quictls.c} | 341 +- deps/ngtcp2/ngtcp2/crypto/shared.c | 190 +- deps/ngtcp2/ngtcp2/crypto/shared.h | 89 +- deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c | 82 +- .../ngtcp2/lib/includes/ngtcp2/ngtcp2.h | 2374 +++++++------ .../ngtcp2/lib/includes/ngtcp2/version.h | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c | 20 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h | 5 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c | 8 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h | 6 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c | 1658 ++++++--- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h | 172 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c | 1486 -------- deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h | 149 - deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c | 524 ++- deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h | 75 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c | 3157 +++++++++-------- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h | 194 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h | 132 + deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c | 95 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h | 82 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c | 66 + deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h | 71 + deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c | 536 ++- deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h | 48 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c | 5 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c | 220 ++ deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h | 171 + deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c | 38 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c | 271 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h | 25 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h | 5 + deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c | 2 + deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h | 2 + deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h | 33 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h | 29 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c | 565 ++- deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h | 198 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h | 62 + deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c | 14 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c | 4 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h | 4 - deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c | 122 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c | 27 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h | 6 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c | 6 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h | 8 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c | 13 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h | 5 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c | 346 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h | 154 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c | 5 + deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h | 7 + deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c | 44 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h | 53 +- deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h | 68 + deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c | 71 + deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h | 52 + deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c | 45 +- 68 files changed, 7658 insertions(+), 7242 deletions(-) rename deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/{ngtcp2_crypto_openssl.h => ngtcp2_crypto_quictls.h} (63%) rename deps/ngtcp2/ngtcp2/crypto/{openssl/openssl.c => quictls/quictls.c} (73%) delete mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c delete mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c create mode 100644 deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h diff --git a/deps/ngtcp2/ngtcp2.gyp b/deps/ngtcp2/ngtcp2.gyp index e53b7f61ea387b..d3af013715dd40 100644 --- a/deps/ngtcp2/ngtcp2.gyp +++ b/deps/ngtcp2/ngtcp2.gyp @@ -8,14 +8,15 @@ 'ngtcp2/lib/ngtcp2_addr.c', 'ngtcp2/lib/ngtcp2_balloc.c', 'ngtcp2/lib/ngtcp2_bbr.c', - 'ngtcp2/lib/ngtcp2_bbr2.c', 'ngtcp2/lib/ngtcp2_buf.c', 'ngtcp2/lib/ngtcp2_cc.c', 'ngtcp2/lib/ngtcp2_cid.c', 'ngtcp2/lib/ngtcp2_conn.c', 'ngtcp2/lib/ngtcp2_conv.c', + 'ngtcp2/lib/ngtcp2_conversion.c', 'ngtcp2/lib/ngtcp2_crypto.c', 'ngtcp2/lib/ngtcp2_err.c', + 'ngtcp2/lib/ngtcp2_frame_chain.c', 'ngtcp2/lib/ngtcp2_gaptr.c', 'ngtcp2/lib/ngtcp2_idtr.c', 'ngtcp2/lib/ngtcp2_ksl.c', @@ -43,8 +44,8 @@ 'ngtcp2/lib/ngtcp2_window_filter.c', 'ngtcp2/crypto/shared.c' ], - 'ngtcp2_sources_openssl': [ - 'ngtcp2/crypto/openssl/openssl.c' + 'ngtcp2_sources_quictls': [ + 'ngtcp2/crypto/quictls/quictls.c' ], 'ngtcp2_sources_boringssl': [ 'ngtcp2/crypto/boringssl/boringssl.c' @@ -132,7 +133,7 @@ }, 'sources': [ '<@(ngtcp2_sources)', - '<@(ngtcp2_sources_openssl)', + '<@(ngtcp2_sources_quictls)', ] }, { diff --git a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c index 015032d41ca0ce..50b89110e36ff7 100644 --- a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c @@ -92,8 +92,8 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { return ngtcp2_crypto_aead_init(aead, (void *)EVP_aead_aes_128_gcm()); } -static const EVP_AEAD *crypto_ssl_get_aead(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_AEAD *crypto_cipher_id_get_aead(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: return EVP_aead_aes_128_gcm(); case TLS1_CK_AES_256_GCM_SHA384: @@ -105,8 +105,8 @@ static const EVP_AEAD *crypto_ssl_get_aead(SSL *ssl) { } } -static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t crypto_cipher_id_get_aead_max_encryption(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: case TLS1_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; @@ -117,8 +117,9 @@ static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { } } -static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t +crypto_cipher_id_get_aead_max_decryption_failure(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: case TLS1_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; @@ -129,8 +130,9 @@ static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { } } -static const ngtcp2_crypto_boringssl_cipher *crypto_ssl_get_hp(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const ngtcp2_crypto_boringssl_cipher * +crypto_cipher_id_get_hp(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: return &crypto_cipher_aes_128; case TLS1_CK_AES_256_GCM_SHA384: @@ -142,8 +144,8 @@ static const ngtcp2_crypto_boringssl_cipher *crypto_ssl_get_hp(SSL *ssl) { } } -static const EVP_MD *crypto_ssl_get_md(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_MD *crypto_cipher_id_get_md(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_CK_AES_128_GCM_SHA256: case TLS1_CK_CHACHA20_POLY1305_SHA256: return EVP_sha256(); @@ -154,15 +156,47 @@ static const EVP_MD *crypto_ssl_get_md(SSL *ssl) { } } +static int supported_cipher_id(uint32_t cipher_id) { + switch (cipher_id) { + case TLS1_CK_AES_128_GCM_SHA256: + case TLS1_CK_AES_256_GCM_SHA384: + case TLS1_CK_CHACHA20_POLY1305_SHA256: + return 1; + default: + return 0; + } +} + +static ngtcp2_crypto_ctx *crypto_ctx_cipher_id(ngtcp2_crypto_ctx *ctx, + uint32_t cipher_id) { + ngtcp2_crypto_aead_init(&ctx->aead, + (void *)crypto_cipher_id_get_aead(cipher_id)); + ctx->md.native_handle = (void *)crypto_cipher_id_get_md(cipher_id); + ctx->hp.native_handle = (void *)crypto_cipher_id_get_hp(cipher_id); + ctx->max_encryption = crypto_cipher_id_get_aead_max_encryption(cipher_id); + ctx->max_decryption_failure = + crypto_cipher_id_get_aead_max_decryption_failure(cipher_id); + + return ctx; +} + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { SSL *ssl = tls_native_handle; - ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_ssl_get_aead(ssl)); - ctx->md.native_handle = (void *)crypto_ssl_get_md(ssl); - ctx->hp.native_handle = (void *)crypto_ssl_get_hp(ssl); - ctx->max_encryption = crypto_ssl_get_aead_max_encryption(ssl); - ctx->max_decryption_failure = crypto_ssl_get_aead_max_decryption_failure(ssl); - return ctx; + const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + uint32_t cipher_id; + + if (cipher == NULL) { + return NULL; + } + + cipher_id = SSL_CIPHER_get_id(cipher); + + if (!supported_cipher_id(cipher_id)) { + return NULL; + } + + return crypto_ctx_cipher_id(ctx, cipher_id); } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx, @@ -394,15 +428,17 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, } } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +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); int rv; int err; if (SSL_provide_quic_data( - ssl, ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level(crypto_level), + ssl, + ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level( + encryption_level), data, datalen) != 1) { return -1; } @@ -423,7 +459,10 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, SSL_reset_early_data_reject(ssl); - ngtcp2_conn_early_data_rejected(conn); + rv = ngtcp2_conn_tls_early_data_rejected(conn); + if (rv != 0) { + return -1; + } goto retry; default: @@ -435,7 +474,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, return 0; } - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = SSL_process_quic_post_handshake(ssl); @@ -464,7 +503,7 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) { SSL_get_peer_quic_transport_params(ssl, &tp, &tplen); - rv = ngtcp2_conn_decode_remote_transport_params(conn, tp, tplen); + rv = ngtcp2_conn_decode_and_set_remote_transport_params(conn, tp, tplen); if (rv != 0) { ngtcp2_conn_set_tls_error(conn, rv); return -1; @@ -482,33 +521,34 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_boringssl_from_ssl_encryption_level( +ngtcp2_encryption_level ngtcp2_crypto_boringssl_from_ssl_encryption_level( enum ssl_encryption_level_t ssl_level) { switch (ssl_level) { case ssl_encryption_initial: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case ssl_encryption_early_data: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case ssl_encryption_handshake: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case ssl_encryption_application: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); } } -enum ssl_encryption_level_t ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +enum ssl_encryption_level_t +ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return ssl_encryption_initial; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return ssl_encryption_handshake; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return ssl_encryption_application; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return ssl_encryption_early_data; default: assert(0); @@ -541,7 +581,7 @@ static int set_read_secret(SSL *ssl, enum ssl_encryption_level_t bssl_level, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(bssl_level); (void)cipher; @@ -558,7 +598,7 @@ static int set_write_secret(SSL *ssl, enum ssl_encryption_level_t bssl_level, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(bssl_level); (void)cipher; @@ -574,7 +614,7 @@ static int add_handshake_data(SSL *ssl, enum ssl_encryption_level_t bssl_level, const uint8_t *data, size_t datalen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(bssl_level); int rv; diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h index 4736b51c3cb48d..06427d7a7cac70 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h @@ -38,39 +38,16 @@ extern "C" { # include #endif /* WIN32 */ -/** - * @macro - * - * :macro:`NGTCP2_CRYPTO_INITIAL_SECRETLEN` is the length of secret - * for Initial packets. - */ -#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32 - -/** - * @macro - * - * :macro:`NGTCP2_CRYPTO_INITIAL_KEYLEN` is the length of key for - * Initial packets. - */ -#define NGTCP2_CRYPTO_INITIAL_KEYLEN 16 - -/** - * @macro - * - * :macro:`NGTCP2_CRYPTO_INITIAL_IVLEN` is the length of IV for - * Initial packets. - */ -#define NGTCP2_CRYPTO_INITIAL_IVLEN 12 - /** * @function * * `ngtcp2_crypto_ctx_tls` initializes |ctx| by extracting negotiated * ciphers and message digests from native TLS session * |tls_native_handle|. This is used for encrypting/decrypting - * Handshake and Short header packets. + * Handshake and 1-RTT packets. If it is unable to obtain necessary + * data from |tls_native_handle|, this function returns NULL. * - * If libngtcp2_crypto_openssl is linked, |tls_native_handle| must be + * If libngtcp2_crypto_quictls is linked, |tls_native_handle| must be * a pointer to SSL object. */ NGTCP2_EXTERN ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, @@ -81,10 +58,11 @@ NGTCP2_EXTERN ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, * * `ngtcp2_crypto_ctx_tls_early` initializes |ctx| by extracting early * ciphers and message digests from native TLS session - * |tls_native_handle|. This is used for encrypting/decrypting 0RTT - * packets. + * |tls_native_handle|. This is used for encrypting/decrypting 0-RTT + * packets. If it is unable to obtain necessary data from + * |tls_native_handle|, this function returns NULL. * - * If libngtcp2_crypto_openssl is linked, |tls_native_handle| must be + * If libngtcp2_crypto_quictls is linked, |tls_native_handle| must be * a pointer to SSL object. */ NGTCP2_EXTERN ngtcp2_crypto_ctx * @@ -96,7 +74,7 @@ ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx, void *tls_native_handle); * `ngtcp2_crypto_md_init` initializes |md| with the provided * |md_native_handle| which is an underlying message digest object. * - * If libngtcp2_crypto_openssl is linked, |md_native_handle| must be a + * If libngtcp2_crypto_quictls is linked, |md_native_handle| must be a * pointer to EVP_MD. * * If libngtcp2_crypto_gnutls is linked, |md_native_handle| must be @@ -134,10 +112,12 @@ ngtcp2_crypto_aead_noncelen(const ngtcp2_crypto_aead *aead); /** * @function * - * `ngtcp2_crypto_hkdf_extract` performs HKDF extract operation. The - * result is the length of |md| and is stored to the buffer pointed by - * |dest|. The caller is responsible to specify the buffer that can - * store the output. + * `ngtcp2_crypto_hkdf_extract` performs HKDF extract operation. + * + * The length of output is `ngtcp2_crypto_md_hashlen(md) + * `. The output is stored in the buffer + * pointed by |dest|. The caller is responsible to specify the buffer + * that has enough capacity to store the output. * * This function returns 0 if it succeeds, or -1. */ @@ -150,7 +130,7 @@ ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, * @function * * `ngtcp2_crypto_hkdf_expand` performs HKDF expand operation. The - * result is |destlen| bytes long and is stored to the buffer pointed + * result is |destlen| bytes long, and is stored in the buffer pointed * by |dest|. * * This function returns 0 if it succeeds, or -1. @@ -166,7 +146,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, * @function * * `ngtcp2_crypto_hkdf` performs HKDF operation. The result is - * |destlen| bytes long and is stored to the buffer pointed by |dest|. + * |destlen| bytes long, and is stored in the buffer pointed by + * |dest|. * * This function returns 0 if it succeeds, or -1. */ @@ -176,41 +157,6 @@ NGTCP2_EXTERN int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, const uint8_t *salt, size_t saltlen, const uint8_t *info, size_t infolen); -/** - * @function - * - * `ngtcp2_crypto_hkdf_expand_label` performs HKDF expand label. The - * result is |destlen| bytes long and is stored to the buffer pointed - * by |dest|. - * - * This function returns 0 if it succeeds, or -1. - */ -NGTCP2_EXTERN int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen, - const ngtcp2_crypto_md *md, - const uint8_t *secret, - size_t secretlen, - const uint8_t *label, - size_t labellen); - -/** - * @enum - * - * :type:`ngtcp2_crypto_side` indicates which side the application - * implements; client or server. - */ -typedef enum ngtcp2_crypto_side { - /** - * :enum:`NGTCP2_CRYPTO_SIDE_CLIENT` indicates that the application - * is client. - */ - NGTCP2_CRYPTO_SIDE_CLIENT, - /** - * :enum:`NGTCP2_CRYPTO_SIDE_SERVER` indicates that the application - * is server. - */ - NGTCP2_CRYPTO_SIDE_SERVER -} ngtcp2_crypto_side; - /** * @function * @@ -225,11 +171,10 @@ ngtcp2_crypto_packet_protection_ivlen(const ngtcp2_crypto_aead *aead); * * `ngtcp2_crypto_encrypt` encrypts |plaintext| of length * |plaintextlen| and writes the ciphertext into the buffer pointed by - * |dest|. The length of ciphertext is plaintextlen + + * |dest|. The length of ciphertext is |plaintextlen| + * :member:`aead->max_overhead ` * bytes long. |dest| must have enough capacity to store the - * ciphertext. It is allowed to specify the same value to |dest| and - * |plaintext|. + * ciphertext. |dest| and |plaintext| may point to the same buffer. * * This function returns 0 if it succeeds, or -1. */ @@ -263,11 +208,10 @@ ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, * * `ngtcp2_crypto_decrypt` decrypts |ciphertext| of length * |ciphertextlen| and writes the plaintext into the buffer pointed by - * |dest|. The length of plaintext is ciphertextlen - + * |dest|. The length of plaintext is |ciphertextlen| - * :member:`aead->max_overhead ` * bytes long. |dest| must have enough capacity to store the - * plaintext. It is allowed to specify the same value to |dest| and - * |ciphertext|. + * plaintext. |dest| and |ciphertext| may point to the same buffer. * * This function returns 0 if it succeeds, or -1. */ @@ -299,7 +243,7 @@ ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead, /** * @function * - * `ngtcp2_crypto_hp_mask` generates mask which is used in packet + * `ngtcp2_crypto_hp_mask` generates a mask which is used in packet * header encryption. The mask is written to the buffer pointed by * |dest|. The sample is passed as |sample| which is * :macro:`NGTCP2_HP_SAMPLELEN` bytes long. The length of mask must @@ -333,15 +277,14 @@ ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp, /** * @function * - * `ngtcp2_crypto_derive_and_install_rx_key` derives the rx keys from - * |secret| and installs new keys to |conn|. + * `ngtcp2_crypto_derive_and_install_rx_key` derives the decryption + * keying materials from |secret|, and installs them to |conn|. * - * If |key| is not NULL, the derived packet protection key for - * decryption is written to the buffer pointed by |key|. If |iv| is - * not NULL, the derived packet protection IV for decryption is - * written to the buffer pointed by |iv|. If |hp| is not NULL, the - * derived header protection key for decryption is written to the - * buffer pointed by |hp|. + * If |key| is not NULL, the derived packet protection key is written + * to the buffer pointed by |key|. If |iv| is not NULL, the derived + * packet protection IV is written to the buffer pointed by |iv|. If + * |hp| is not NULL, the derived header protection key is written to + * the buffer pointed by |hp|. * * |secretlen| specifies the length of |secret|. * @@ -351,44 +294,44 @@ ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * `ngtcp2_crypto_packet_protection_ivlen(ctx->aead) * ` where ctx is obtained by * `ngtcp2_crypto_ctx_tls` (or `ngtcp2_crypto_ctx_tls_early` if - * |level| == :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`). + * |level| == + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`). * * In the first call of this function, it calls * `ngtcp2_conn_set_crypto_ctx` (or `ngtcp2_conn_set_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to set - * negotiated AEAD and message digest algorithm. After the successful - * call of this function, application can use + * :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_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to get - * :type:`ngtcp2_crypto_ctx`. + * :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_crypto_level.NGTCP2_CRYPTO_LEVEL_APPLICATION`, this + * :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 + * from an object obtained by `ngtcp2_conn_get_tls_native_handle`, and * sets it to |conn| by calling - * `ngtcp2_conn_decode_remote_transport_params`. + * `ngtcp2_conn_decode_and_set_remote_transport_params`. * * This function returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_rx_key( ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp, - ngtcp2_crypto_level level, const uint8_t *secret, size_t secretlen); + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen); /** * @function * - * `ngtcp2_crypto_derive_and_install_tx_key` derives the tx keys from - * |secret| and installs new keys to |conn|. + * `ngtcp2_crypto_derive_and_install_tx_key` derives the encryption + * keying materials from |secret|, and installs new keys to |conn|. * - * If |key| is not NULL, the derived packet protection key for - * encryption is written to the buffer pointed by |key|. If |iv| is - * not NULL, the derived packet protection IV for encryption is - * written to the buffer pointed by |iv|. If |hp| is not NULL, the - * derived header protection key for encryption is written to the - * buffer pointed by |hp|. + * If |key| is not NULL, the derived packet protection key is written + * to the buffer pointed by |key|. If |iv| is not NULL, the derived + * packet protection IV is written to the buffer pointed by |iv|. If + * |hp| is not NULL, the derived header protection key is written to + * the buffer pointed by |hp|. * * |secretlen| specifies the length of |secret|. * @@ -398,58 +341,59 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_rx_key( * `ngtcp2_crypto_packet_protection_ivlen(ctx->aead) * ` where ctx is obtained by * `ngtcp2_crypto_ctx_tls` (or `ngtcp2_crypto_ctx_tls_early` if - * |level| == :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`). + * |level| == + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`). * * In the first call of this function, it calls * `ngtcp2_conn_set_crypto_ctx` (or `ngtcp2_conn_set_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to set - * negotiated AEAD and message digest algorithm. After the successful - * call of this function, application can use + * :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_early_crypto_ctx` * if |level| == - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`) to get - * :type:`ngtcp2_crypto_ctx`. + * :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_crypto_level.NGTCP2_CRYPTO_LEVEL_APPLICATION`, this + * :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 + * from an object obtained by `ngtcp2_conn_get_tls_native_handle`, and * sets it to |conn| by calling - * `ngtcp2_conn_decode_remote_transport_params`. + * `ngtcp2_conn_decode_and_set_remote_transport_params`. * * This function returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_tx_key( ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp, - ngtcp2_crypto_level level, const uint8_t *secret, size_t secretlen); + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen); /** * @function * * `ngtcp2_crypto_update_key` updates traffic keying materials. * - * The new traffic secret for decryption is written to the buffer - * pointed by |rx_secret|. The length of secret is |secretlen| bytes, - * and |rx_secret| must point to the buffer which has enough capacity. + * The new decryption traffic secret is written to the buffer pointed + * by |rx_secret|. The length of secret is |secretlen| bytes, and + * |rx_secret| must point to the buffer which has enough capacity. * - * The new traffic secret for encryption is written to the buffer - * pointed by |tx_secret|. The length of secret is |secretlen| bytes, - * and |tx_secret| must point to the buffer which has enough capacity. + * The new encryption traffic secret is written to the buffer pointed + * by |tx_secret|. The length of secret is |secretlen| bytes, and + * |tx_secret| must point to the buffer which has enough capacity. * - * The derived packet protection key for decryption is written to the - * buffer pointed by |rx_key|. The derived packet protection IV for - * decryption is written to the buffer pointed by |rx_iv|. - * |rx_aead_ctx| must be constructed with |rx_key|. + * The derived decryption packet protection key is written to the + * buffer pointed by |rx_key|. The derived decryption packet + * protection IV is written to the buffer pointed by |rx_iv|. + * |rx_aead_ctx| is initialized with the derived key and IV. * - * The derived packet protection key for encryption is written to the - * buffer pointed by |tx_key|. The derived packet protection IV for - * encryption is written to the buffer pointed by |tx_iv|. - * |tx_aead_ctx| must be constructed with |rx_key|. + * The derived encryption packet protection key is written to the + * buffer pointed by |tx_key|. The derived encryption packet + * protection IV is written to the buffer pointed by |tx_iv|. + * |tx_aead_ctx| is initialized with the derived key and IV. * - * |current_rx_secret| and |current_tx_secret| are the current traffic - * secrets for decryption and encryption. |secretlen| specifies the - * length of |rx_secret| and |tx_secret|. + * |current_rx_secret| and |current_tx_secret| are the current + * decryption and encryption traffic secrets respectively. They share + * the same length with |rx_secret| and |tx_secret|. * * The length of packet protection key and header protection key is * `ngtcp2_crypto_aead_keylen(ctx->aead) `, @@ -488,7 +432,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb( * @function * * `ngtcp2_crypto_client_initial_cb` installs initial secrets and - * encryption keys and sets QUIC transport parameters. + * encryption keys, and sets QUIC transport parameters. * * This function can be directly passed to * :member:`ngtcp2_callbacks.client_initial` field. It is only used @@ -507,8 +451,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, * response to incoming Retry packet. * * This function can be directly passed to - * :member:`ngtcp2_callbacks.recv_retry` field. It is only used - * by client. + * :member:`ngtcp2_callbacks.recv_retry` field. It is only used by + * client. * * This function returns 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE`. @@ -525,8 +469,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_recv_retry_cb(ngtcp2_conn *conn, * transport parameters. * * This function can be directly passed to - * :member:`ngtcp2_callbacks.recv_client_initial` field. It is - * only used by server. + * :member:`ngtcp2_callbacks.recv_client_initial` field. It is only + * used by server. * * This function returns 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE`. @@ -539,21 +483,21 @@ NGTCP2_EXTERN int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn, * @function * * `ngtcp2_crypto_read_write_crypto_data` reads CRYPTO data |data| of - * length |datalen| in encryption level |crypto_level| and may feed - * outgoing CRYPTO data to |conn|. This function can drive handshake. - * This function can be also used after handshake completes. It is - * allowed to call this function with |datalen| == 0. In this case, - * no additional read operation is done. + * length |datalen| in an encryption level |encryption_level|, and may + * feed outgoing CRYPTO data to |conn|. This function can drive + * handshake. This function can be also used after handshake + * completes. It is allowed to call this function with |datalen| == + * 0. In this case, no additional read operation is done. * * This function returns 0 if it succeeds, or a negative error code. * The generic error code is -1 if a specific error code is not * suitable. The error codes less than -10000 are specific to - * underlying TLS implementation. For OpenSSL, the error codes are - * defined in *ngtcp2_crypto_openssl.h*. + * underlying TLS implementation. For quictls, the error codes are + * defined in *ngtcp2_crypto_quictls.h*. */ NGTCP2_EXTERN int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, const uint8_t *data, size_t datalen); /** @@ -570,17 +514,17 @@ ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, * codes. */ NGTCP2_EXTERN int ngtcp2_crypto_recv_crypto_data_cb( - ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, uint64_t offset, - const uint8_t *data, size_t datalen, void *user_data); + ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, + uint64_t offset, const uint8_t *data, size_t datalen, void *user_data); /** * @function * * `ngtcp2_crypto_generate_stateless_reset_token` generates a * stateless reset token using HKDF extraction using the given |cid| - * and static key |secret| as input. The token will be written to - * the buffer pointed by |token| and it must have a capacity of at - * least :macro:`NGTCP2_STATELESS_RESET_TOKENLEN` bytes. + * and |secret| as input. The token will be written to the buffer + * pointed by |token|, and it must have a capacity of at least + * :macro:`NGTCP2_STATELESS_RESET_TOKENLEN` bytes. * * This function returns 0 if it succeeds, or -1. */ @@ -644,12 +588,12 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token( * :macro:`NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN` bytes long. The * successfully generated token starts with * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY`. |secret| of length - * |secretlen| is an initial keying material to generate keys to - * encrypt the token. |version| is QUIC version. |remote_addr| of - * length |remote_addrlen| is an address of client. |retry_scid| is a - * Source Connection ID chosen by server and set in Retry packet. - * |odcid| is a Destination Connection ID in Initial packet sent by - * client. |ts| is the timestamp when the token is generated. + * |secretlen| is a keying material to generate keys to encrypt the + * token. |version| is QUIC version. |remote_addr| of length + * |remote_addrlen| is an address of client. |retry_scid| is a Source + * Connection ID chosen by server, and set in Retry packet. |odcid| + * is a Destination Connection ID in Initial packet sent by client. + * |ts| is the timestamp when the token is generated. * * This function returns the length of generated token if it succeeds, * or -1. @@ -664,16 +608,16 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_retry_token( * * `ngtcp2_crypto_verify_retry_token` verifies Retry token stored in * the buffer pointed by |token| of length |tokenlen|. |secret| of - * length |secretlen| is an initial keying material to generate keys - * to decrypt the token. |version| is QUIC version of the Initial - * packet that contains this token. |remote_addr| of length - * |remote_addrlen| is an address of client. |dcid| is a Destination - * Connection ID in Initial packet sent by client. |timeout| is the - * period during which the token is valid. |ts| is the current - * timestamp. When validation succeeds, the extracted Destination - * Connection ID (which is the Destination Connection ID in Initial - * packet sent by client that triggered Retry packet) is stored to the - * buffer pointed by |odcid|. + * length |secretlen| is a keying material to generate keys to decrypt + * the token. |version| is QUIC version of the Initial packet that + * contains this token. |remote_addr| of length |remote_addrlen| is + * an address of client. |dcid| is a Destination Connection ID in + * Initial packet sent by client. |timeout| is the period during + * which the token is valid. |ts| is the current timestamp. When + * validation succeeds, the extracted Destination Connection ID (which + * is the Destination Connection ID in Initial packet sent by client + * that triggered Retry packet) is stored in the buffer pointed by + * |odcid|. * * This function returns 0 if it succeeds, or -1. */ @@ -692,10 +636,9 @@ NGTCP2_EXTERN int ngtcp2_crypto_verify_retry_token( * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` bytes long. The * successfully generated token starts with * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR`. |secret| of length - * |secretlen| is an initial keying material to generate keys to - * encrypt the token. |remote_addr| of length |remote_addrlen| is an - * address of client. |ts| is the timestamp when the token is - * generated. + * |secretlen| is a keying material to generate keys to encrypt the + * token. |remote_addr| of length |remote_addrlen| is an address of + * client. |ts| is the timestamp when the token is generated. * * This function returns the length of generated token if it succeeds, * or -1. @@ -710,8 +653,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_regular_token( * * `ngtcp2_crypto_verify_regular_token` verifies a regular token * stored in the buffer pointed by |token| of length |tokenlen|. - * |secret| of length |secretlen| is an initial keying material to - * generate keys to decrypt the token. |remote_addr| of length + * |secret| of length |secretlen| is a keying material to generate + * keys to decrypt the token. |remote_addr| of length * |remote_addrlen| is an address of client. |timeout| is the period * during which the token is valid. |ts| is the current timestamp. * @@ -750,9 +693,12 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_write_connection_close( * @function * * `ngtcp2_crypto_write_retry` writes Retry packet to the buffer - * pointed by |dest| of length |destlen|. |odcid| specifies Original - * Destination Connection ID. |token| specifies Retry Token, and - * |tokenlen| specifies its length. + * pointed by |dest| of length |destlen|. |dcid| is the Connection ID + * which appeared in a packet as a Source Connection ID sent by + * client. |scid| is a server chosen Source Connection ID. |odcid| + * specifies Original Destination Connection ID which appeared in a + * packet as a Destination Connection ID sent by client. |token| + * specifies Retry Token, and |tokenlen| specifies its length. * * This function wraps around `ngtcp2_pkt_write_retry` for easier use. * @@ -783,7 +729,7 @@ ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx, * * `ngtcp2_crypto_aead_ctx_decrypt_init` initializes |aead_ctx| with * new AEAD cipher context object for decryption which is constructed - * to use |key| as encryption key. |aead| specifies AEAD cipher to + * to use |key| as decryption key. |aead| specifies AEAD cipher to * use. |noncelen| is the length of nonce. * * This function returns 0 if it succeeds, or -1. @@ -806,7 +752,8 @@ ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx); /** * @function * - * `ngtcp2_crypto_delete_crypto_aead_ctx_cb` deletes the given |aead_ctx|. + * `ngtcp2_crypto_delete_crypto_aead_ctx_cb` deletes the given + * |aead_ctx|. * * This function can be directly passed to * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` field. @@ -845,7 +792,8 @@ NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, * * `ngtcp2_crypto_version_negotiation_cb` installs Initial keys for * |version| which is negotiated or being negotiated. |client_dcid| - * is the destination connection ID in first Initial packet of client. + * is the destination connection ID in first Initial packet from + * client. * * This function can be directly passed to * :member:`ngtcp2_callbacks.version_negotiation` field. @@ -872,7 +820,7 @@ typedef ngtcp2_conn *(*ngtcp2_crypto_get_conn)( * * :type:`ngtcp2_crypto_conn_ref` is a structure to get a pointer to * :type:`ngtcp2_conn`. It is meant to be set to TLS native handle as - * an application specific data (e.g. SSL_set_app_data in OpenSSL). + * an application specific data (e.g. SSL_set_app_data in quictls). */ typedef struct ngtcp2_crypto_conn_ref { /** diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h index 6497c09e79840d..43a3c36f03a382 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h @@ -37,23 +37,23 @@ extern "C" { * @function * * `ngtcp2_crypto_boringssl_from_ssl_encryption_level` translates - * |ssl_level| to :type:`ngtcp2_crypto_level`. This function is only - * available for BoringSSL backend. + * |ssl_level| to :type:`ngtcp2_encryption_level`. This function is + * only available for BoringSSL backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level +NGTCP2_EXTERN ngtcp2_encryption_level ngtcp2_crypto_boringssl_from_ssl_encryption_level( enum ssl_encryption_level_t ssl_level); /** * @function * - * `ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level` translates - * |crypto_level| to ssl_encryption_level_t. This function is only - * available for BoringSSL backend. + * `ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level` translates + * |encryption_level| to ssl_encryption_level_t. This function is + * only available for BoringSSL backend. */ NGTCP2_EXTERN enum ssl_encryption_level_t -ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h index d4b551c382fd69..61020bb3a8f376 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_picotls.h @@ -36,8 +36,8 @@ extern "C" { /** * @struct * - * :type:`ngtcp2_crypto_picotls_ctx` contains per-connection state - * of Picotls objects and must be an object to bet set to + * :type:`ngtcp2_crypto_picotls_ctx` contains per-connection state of + * Picotls objects and must be an object to bet set to * `ngtcp2_conn_set_tls_native_handle`. */ typedef struct ngtcp2_crypto_picotls_ctx { @@ -65,21 +65,21 @@ ngtcp2_crypto_picotls_ctx_init(ngtcp2_crypto_picotls_ctx *cptls); * @function * * `ngtcp2_crypto_picotls_from_epoch` translates |epoch| to - * :type:`ngtcp2_crypto_level`. This function is only available for - * Picotls backend. + * :type:`ngtcp2_encryption_level`. This function is only available + * for Picotls backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level +NGTCP2_EXTERN ngtcp2_encryption_level ngtcp2_crypto_picotls_from_epoch(size_t epoch); /** * @function * - * `ngtcp2_crypto_picotls_from_ngtcp2_crypto_level` translates - * |crypto_level| to epoch. This function is only available for + * `ngtcp2_crypto_picotls_from_ngtcp2_encryption_level` translates + * |encryption_level| to epoch. This function is only available for * Picotls backend. */ -NGTCP2_EXTERN size_t ngtcp2_crypto_picotls_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +NGTCP2_EXTERN size_t ngtcp2_crypto_picotls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function @@ -206,7 +206,7 @@ ngtcp2_crypto_picotls_configure_client_session(ngtcp2_crypto_picotls_ctx *cptls, * * `ngtcp2_crypto_picotls_deconfigure_session` frees the resources * allocated for |cptls| during QUIC connection. It frees the - * following data using :manpage:`free(3)`. + * following data using :manpage:`free(3)`: * * - handshake_properties.max_early_data_size * - handshake_properties.additional_extensions[0].data.base diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_quictls.h similarity index 63% rename from deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h rename to deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_quictls.h index 844081bfa8b055..b25c13b81c8b18 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_quictls.h @@ -22,8 +22,8 @@ * 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_CRYPTO_OPENSSL_H -#define NGTCP2_CRYPTO_OPENSSL_H +#ifndef NGTCP2_CRYPTO_QUICTLS_H +#define NGTCP2_CRYPTO_QUICTLS_H #include @@ -36,57 +36,57 @@ extern "C" { /** * @macrosection * - * OpenSSL specific error codes + * quictls specific error codes */ /** * @macro * - * :macro:`NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP` is the + * :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP` is the * error code which indicates that TLS handshake routine is * interrupted by X509 certificate lookup. See * :macro:`SSL_ERROR_WANT_X509_LOOKUP` error description from * `SSL_do_handshake`. */ -#define NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP -10001 +#define NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP -10001 /** * @macro * - * :macro:`NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB` is the + * :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB` is the * error code which indicates that TLS handshake routine is * interrupted by client hello callback. See * :macro:`SSL_ERROR_WANT_CLIENT_HELLO_CB` error description from * `SSL_do_handshake`. */ -#define NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB -10002 +#define NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB -10002 /** * @function * - * `ngtcp2_crypto_openssl_from_ossl_encryption_level` translates - * |ossl_level| to :type:`ngtcp2_crypto_level`. This function is only - * available for OpenSSL backend. + * `ngtcp2_crypto_quictls_from_ossl_encryption_level` translates + * |ossl_level| to :type:`ngtcp2_encryption_level`. This function is + * only available for quictls backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level -ngtcp2_crypto_openssl_from_ossl_encryption_level( +NGTCP2_EXTERN ngtcp2_encryption_level +ngtcp2_crypto_quictls_from_ossl_encryption_level( OSSL_ENCRYPTION_LEVEL ossl_level); /** * @function * - * `ngtcp2_crypto_openssl_from_ngtcp2_crypto_level` translates - * |crypto_level| to OSSL_ENCRYPTION_LEVEL. This function is only - * available for OpenSSL backend. + * `ngtcp2_crypto_quictls_from_ngtcp2_encryption_level` translates + * |encryption_level| to OSSL_ENCRYPTION_LEVEL. This function is only + * available for quictls backend. */ NGTCP2_EXTERN OSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_openssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +ngtcp2_crypto_quictls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function * - * `ngtcp2_crypto_openssl_configure_server_context` configures + * `ngtcp2_crypto_quictls_configure_server_context` configures * |ssl_ctx| for server side QUIC connection. It performs the * following modifications: * @@ -102,12 +102,12 @@ ngtcp2_crypto_openssl_from_ngtcp2_crypto_level( * It returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int -ngtcp2_crypto_openssl_configure_server_context(SSL_CTX *ssl_ctx); +ngtcp2_crypto_quictls_configure_server_context(SSL_CTX *ssl_ctx); /** * @function * - * `ngtcp2_crypto_openssl_configure_client_context` configures + * `ngtcp2_crypto_quictls_configure_client_context` configures * |ssl_ctx| for client side QUIC connection. It performs the * following modifications: * @@ -123,10 +123,25 @@ ngtcp2_crypto_openssl_configure_server_context(SSL_CTX *ssl_ctx); * It returns 0 if it succeeds, or -1. */ NGTCP2_EXTERN int -ngtcp2_crypto_openssl_configure_client_context(SSL_CTX *ssl_ctx); +ngtcp2_crypto_quictls_configure_client_context(SSL_CTX *ssl_ctx); + +/** + * @function + * + * `ngtcp2_crypto_quictls_init` initializes libngtcp2_crypto_quictls + * library. This initialization is optional. For quictls >= 3.0, it + * is highly recommended to call this function before any use of + * libngtcp2_crypto library API to workaround the performance + * regression. Note that calling this function does not solve all + * performance issues introduced in 3.x. For quictls 1.1.1, this + * function does nothing, and always succeeds. + * + * This function returns 0 if it succeeds, or -1. + */ +NGTCP2_EXTERN int ngtcp2_crypto_quictls_init(void); #ifdef __cplusplus } #endif -#endif /* NGTCP2_CRYPTO_OPENSSL_H */ +#endif /* NGTCP2_CRYPTO_QUICTLS_H */ diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h index 3b10802c25b5e8..e1d621adce94d8 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_wolfssl.h @@ -39,23 +39,23 @@ extern "C" { * @function * * `ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level` translates - * |wolfssl_level| to :type:`ngtcp2_crypto_level`. This function is only - * available for wolfSSL backend. + * |wolfssl_level| to :type:`ngtcp2_encryption_level`. This function + * is only available for wolfSSL backend. */ -NGTCP2_EXTERN ngtcp2_crypto_level +NGTCP2_EXTERN ngtcp2_encryption_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( WOLFSSL_ENCRYPTION_LEVEL wolfssl_level); /** * @function * - * `ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level` translates - * |crypto_level| to WOLFSSL_ENCRYPTION_LEVEL. This function is only - * available for wolfSSL backend. + * `ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level` translates + * |encryption_level| to WOLFSSL_ENCRYPTION_LEVEL. This function is + * only available for wolfSSL backend. */ NGTCP2_EXTERN WOLFSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level); +ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level); /** * @function diff --git a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c index 32d17adc6c3a35..35bfb7b2f8fa19 100644 --- a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c +++ b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c @@ -68,45 +68,40 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { return ngtcp2_crypto_aead_init(aead, (void *)&ptls_openssl_aes128gcm); } -static const ptls_aead_algorithm_t *crypto_ptls_get_aead(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - - return cs->aead; -} - -static uint64_t crypto_ptls_get_aead_max_encryption(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - +static uint64_t +crypto_cipher_suite_get_aead_max_encryption(ptls_cipher_suite_t *cs) { if (cs->aead == &ptls_openssl_aes128gcm || cs->aead == &ptls_openssl_aes256gcm) { return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; } +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 if (cs->aead == &ptls_openssl_chacha20poly1305) { return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305; } +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ return 0; } -static uint64_t crypto_ptls_get_aead_max_decryption_failure(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - +static uint64_t +crypto_cipher_suite_get_aead_max_decryption_failure(ptls_cipher_suite_t *cs) { if (cs->aead == &ptls_openssl_aes128gcm || cs->aead == &ptls_openssl_aes256gcm) { return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; } +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 if (cs->aead == &ptls_openssl_chacha20poly1305) { return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305; } +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ return 0; } -static const ptls_cipher_algorithm_t *crypto_ptls_get_hp(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - +static const ptls_cipher_algorithm_t * +crypto_cipher_suite_get_hp(ptls_cipher_suite_t *cs) { if (cs->aead == &ptls_openssl_aes128gcm) { return &ptls_openssl_aes128ctr; } @@ -115,29 +110,43 @@ static const ptls_cipher_algorithm_t *crypto_ptls_get_hp(ptls_t *ptls) { return &ptls_openssl_aes256ctr; } +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 if (cs->aead == &ptls_openssl_chacha20poly1305) { return &ptls_openssl_chacha20; } +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ return NULL; } -static const ptls_hash_algorithm_t *crypto_ptls_get_md(ptls_t *ptls) { - ptls_cipher_suite_t *cs = ptls_get_cipher(ptls); - - return cs->hash; +static int supported_cipher_suite(ptls_cipher_suite_t *cs) { + return cs->aead == &ptls_openssl_aes128gcm || + cs->aead == &ptls_openssl_aes256gcm +#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 + || cs->aead == &ptls_openssl_chacha20poly1305 +#endif /* PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 */ + ; } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { ngtcp2_crypto_picotls_ctx *cptls = tls_native_handle; - ngtcp2_crypto_aead_init(&ctx->aead, - (void *)crypto_ptls_get_aead(cptls->ptls)); - ctx->md.native_handle = (void *)crypto_ptls_get_md(cptls->ptls); - ctx->hp.native_handle = (void *)crypto_ptls_get_hp(cptls->ptls); - ctx->max_encryption = crypto_ptls_get_aead_max_encryption(cptls->ptls); + ptls_cipher_suite_t *cs = ptls_get_cipher(cptls->ptls); + + if (cs == NULL) { + return NULL; + } + + if (!supported_cipher_suite(cs)) { + return NULL; + } + + ngtcp2_crypto_aead_init(&ctx->aead, (void *)cs->aead); + ctx->md.native_handle = (void *)cs->hash; + ctx->hp.native_handle = (void *)crypto_cipher_suite_get_hp(cs); + ctx->max_encryption = crypto_cipher_suite_get_aead_max_encryption(cs); ctx->max_decryption_failure = - crypto_ptls_get_aead_max_decryption_failure(cptls->ptls); + crypto_cipher_suite_get_aead_max_decryption_failure(cs); return ctx; } @@ -350,13 +359,14 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, return 0; } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +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); ptls_buffer_t sendbuf; size_t epoch_offsets[5] = {0}; - size_t epoch = ngtcp2_crypto_picotls_from_ngtcp2_crypto_level(crypto_level); + size_t epoch = + ngtcp2_crypto_picotls_from_ngtcp2_encryption_level(encryption_level); size_t epoch_datalen; size_t i; int rv; @@ -379,7 +389,11 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, if (!ngtcp2_conn_is_server(conn) && cptls->handshake_properties.client.early_data_acceptance == PTLS_EARLY_DATA_REJECTED) { - ngtcp2_conn_early_data_rejected(conn); + rv = ngtcp2_conn_tls_early_data_rejected(conn); + if (rv != 0) { + rv = -1; + goto fin; + } } for (i = 0; i < 4; ++i) { @@ -399,7 +413,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, } if (rv == 0) { - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = 0; @@ -432,32 +446,32 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_picotls_from_epoch(size_t epoch) { +ngtcp2_encryption_level ngtcp2_crypto_picotls_from_epoch(size_t epoch) { switch (epoch) { case 0: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case 1: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case 2: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case 3: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); } } -size_t ngtcp2_crypto_picotls_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +size_t ngtcp2_crypto_picotls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return 0; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return 1; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return 2; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return 3; default: assert(0); @@ -543,8 +557,8 @@ int ngtcp2_crypto_picotls_collected_extensions( conn_ref = *ptls_get_data_ptr(ptls); conn = conn_ref->get_conn(conn_ref); - rv = ngtcp2_conn_decode_remote_transport_params(conn, extensions->data.base, - extensions->data.len); + rv = ngtcp2_conn_decode_and_set_remote_transport_params( + conn, extensions->data.base, extensions->data.len); if (rv != 0) { ngtcp2_conn_set_tls_error(conn, rv); return -1; @@ -561,7 +575,7 @@ static int update_traffic_key_server_cb(ptls_update_traffic_key_t *self, const void *secret) { ngtcp2_crypto_conn_ref *conn_ref = *ptls_get_data_ptr(ptls); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = ngtcp2_crypto_picotls_from_epoch(epoch); + ngtcp2_encryption_level level = ngtcp2_crypto_picotls_from_epoch(epoch); ptls_cipher_suite_t *cipher = ptls_get_cipher(ptls); size_t secretlen = cipher->hash->digest_size; ngtcp2_crypto_picotls_ctx *cptls; @@ -574,7 +588,7 @@ static int update_traffic_key_server_cb(ptls_update_traffic_key_t *self, return -1; } - if (level == NGTCP2_CRYPTO_LEVEL_HANDSHAKE) { + if (level == NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE) { /* libngtcp2 allows an application to change QUIC transport * parameters before installing Handshake tx key. We need to * wait for the key to get the correct local transport @@ -606,7 +620,7 @@ static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *ptls, int is_enc, size_t epoch, const void *secret) { ngtcp2_crypto_conn_ref *conn_ref = *ptls_get_data_ptr(ptls); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = ngtcp2_crypto_picotls_from_epoch(epoch); + ngtcp2_encryption_level level = ngtcp2_crypto_picotls_from_epoch(epoch); ptls_cipher_suite_t *cipher = ptls_get_cipher(ptls); size_t secretlen = cipher->hash->digest_size; @@ -660,7 +674,7 @@ int ngtcp2_crypto_picotls_configure_client_session( ngtcp2_crypto_picotls_ctx *cptls, ngtcp2_conn *conn) { ptls_handshake_properties_t *hsprops = &cptls->handshake_properties; - hsprops->client.max_early_data_size = calloc(1, sizeof(uint32_t)); + hsprops->client.max_early_data_size = calloc(1, sizeof(size_t)); if (hsprops->client.max_early_data_size == NULL) { return -1; } diff --git a/deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c similarity index 73% rename from deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c rename to deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c index 466d9e11ca6415..330ca687b44666 100644 --- a/deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -42,6 +42,168 @@ #include "shared.h" +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static int crypto_initialized; +static EVP_CIPHER *crypto_aes_128_gcm; +static EVP_CIPHER *crypto_aes_256_gcm; +static EVP_CIPHER *crypto_chacha20_poly1305; +static EVP_CIPHER *crypto_aes_128_ccm; +static EVP_CIPHER *crypto_aes_128_ctr; +static EVP_CIPHER *crypto_aes_256_ctr; +static EVP_CIPHER *crypto_chacha20; +static EVP_MD *crypto_sha256; +static EVP_MD *crypto_sha384; +static EVP_KDF *crypto_hkdf; + +int ngtcp2_crypto_quictls_init(void) { + crypto_aes_128_gcm = EVP_CIPHER_fetch(NULL, "AES-128-GCM", NULL); + if (crypto_aes_128_gcm == NULL) { + return -1; + } + + crypto_aes_256_gcm = EVP_CIPHER_fetch(NULL, "AES-256-GCM", NULL); + if (crypto_aes_256_gcm == NULL) { + return -1; + } + + crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL); + if (crypto_chacha20_poly1305 == NULL) { + return -1; + } + + crypto_aes_128_ccm = EVP_CIPHER_fetch(NULL, "AES-128-CCM", NULL); + if (crypto_aes_128_ccm == NULL) { + return -1; + } + + crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL); + if (crypto_aes_128_ctr == NULL) { + return -1; + } + + crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL); + if (crypto_aes_256_ctr == NULL) { + return -1; + } + + crypto_chacha20 = EVP_CIPHER_fetch(NULL, "ChaCha20", NULL); + if (crypto_chacha20 == NULL) { + return -1; + } + + crypto_sha256 = EVP_MD_fetch(NULL, "sha256", NULL); + if (crypto_sha256 == NULL) { + return -1; + } + + crypto_sha384 = EVP_MD_fetch(NULL, "sha384", NULL); + if (crypto_sha384 == NULL) { + return -1; + } + + crypto_hkdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + if (crypto_hkdf == NULL) { + return -1; + } + + crypto_initialized = 1; + + return 0; +} + +static const EVP_CIPHER *crypto_aead_aes_128_gcm(void) { + if (crypto_aes_128_gcm) { + return crypto_aes_128_gcm; + } + + return EVP_aes_128_gcm(); +} + +static const EVP_CIPHER *crypto_aead_aes_256_gcm(void) { + if (crypto_aes_256_gcm) { + return crypto_aes_256_gcm; + } + + return EVP_aes_256_gcm(); +} + +static const EVP_CIPHER *crypto_aead_chacha20_poly1305(void) { + if (crypto_chacha20_poly1305) { + return crypto_chacha20_poly1305; + } + + return EVP_chacha20_poly1305(); +} + +static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) { + if (crypto_aes_128_ccm) { + return crypto_aes_128_ccm; + } + + return EVP_aes_128_ccm(); +} + +static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) { + if (crypto_aes_128_ctr) { + return crypto_aes_128_ctr; + } + + return EVP_aes_128_ctr(); +} + +static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) { + if (crypto_aes_256_ctr) { + return crypto_aes_256_ctr; + } + + return EVP_aes_256_ctr(); +} + +static const EVP_CIPHER *crypto_cipher_chacha20(void) { + if (crypto_chacha20) { + return crypto_chacha20; + } + + return EVP_chacha20(); +} + +static const EVP_MD *crypto_md_sha256(void) { + if (crypto_sha256) { + return crypto_sha256; + } + + return EVP_sha256(); +} + +static const EVP_MD *crypto_md_sha384(void) { + if (crypto_sha384) { + return crypto_sha384; + } + + return EVP_sha384(); +} + +static EVP_KDF *crypto_kdf_hkdf(void) { + if (crypto_hkdf) { + return crypto_hkdf; + } + + return EVP_KDF_fetch(NULL, "hkdf", NULL); +} +#else /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */ +# define crypto_aead_aes_128_gcm EVP_aes_128_gcm +# define crypto_aead_aes_256_gcm EVP_aes_256_gcm +# define crypto_aead_chacha20_poly1305 EVP_chacha20_poly1305 +# define crypto_aead_aes_128_ccm EVP_aes_128_ccm +# define crypto_cipher_aes_128_ctr EVP_aes_128_ctr +# define crypto_cipher_aes_256_ctr EVP_aes_256_ctr +# define crypto_cipher_chacha20 EVP_chacha20 +# define crypto_md_sha256 EVP_sha256 +# define crypto_md_sha384 EVP_sha384 + +int ngtcp2_crypto_quictls_init(void) { return 0; } +#endif /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */ + static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) { switch (EVP_CIPHER_nid(aead)) { case NID_aes_128_gcm: @@ -58,18 +220,18 @@ static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) { } ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead) { - return ngtcp2_crypto_aead_init(aead, (void *)EVP_aes_128_gcm()); + return ngtcp2_crypto_aead_init(aead, (void *)crypto_aead_aes_128_gcm()); } ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) { - md->native_handle = (void *)EVP_sha256(); + md->native_handle = (void *)crypto_md_sha256(); return md; } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) { - ngtcp2_crypto_aead_init(&ctx->aead, (void *)EVP_aes_128_gcm()); - ctx->md.native_handle = (void *)EVP_sha256(); - ctx->hp.native_handle = (void *)EVP_aes_128_ctr(); + ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm()); + ctx->md.native_handle = (void *)crypto_md_sha256(); + ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr(); ctx->max_encryption = 0; ctx->max_decryption_failure = 0; return ctx; @@ -83,26 +245,26 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_init(ngtcp2_crypto_aead *aead, } ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { - return ngtcp2_crypto_aead_init(aead, (void *)EVP_aes_128_gcm()); + return ngtcp2_crypto_aead_init(aead, (void *)crypto_aead_aes_128_gcm()); } -static const EVP_CIPHER *crypto_ssl_get_aead(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_CIPHER *crypto_cipher_id_get_aead(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_gcm(); + return crypto_aead_aes_128_gcm(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_gcm(); + return crypto_aead_aes_256_gcm(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20_poly1305(); + return crypto_aead_chacha20_poly1305(); case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_aes_128_ccm(); + return crypto_aead_aes_128_ccm(); default: return NULL; } } -static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t crypto_cipher_id_get_aead_max_encryption(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; @@ -115,8 +277,9 @@ static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) { } } -static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static uint64_t +crypto_cipher_id_get_aead_max_decryption_failure(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_256_GCM_SHA384: return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; @@ -129,42 +292,75 @@ static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { } } -static const EVP_CIPHER *crypto_ssl_get_hp(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_aes_128_ctr(); + return crypto_cipher_aes_128_ctr(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_ctr(); + return crypto_cipher_aes_256_ctr(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20(); + return crypto_cipher_chacha20(); default: return NULL; } } -static const EVP_MD *crypto_ssl_get_md(SSL *ssl) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { +static const EVP_MD *crypto_cipher_id_get_md(uint32_t cipher_id) { + switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_CHACHA20_POLY1305_SHA256: case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_sha256(); + return crypto_md_sha256(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_sha384(); + return crypto_md_sha384(); default: return NULL; } } +static int supported_cipher_id(uint32_t cipher_id) { + switch (cipher_id) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_AES_256_GCM_SHA384: + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + case TLS1_3_CK_AES_128_CCM_SHA256: + return 1; + default: + return 0; + } +} + +static ngtcp2_crypto_ctx *crypto_ctx_cipher_id(ngtcp2_crypto_ctx *ctx, + uint32_t cipher_id) { + ngtcp2_crypto_aead_init(&ctx->aead, + (void *)crypto_cipher_id_get_aead(cipher_id)); + ctx->md.native_handle = (void *)crypto_cipher_id_get_md(cipher_id); + ctx->hp.native_handle = (void *)crypto_cipher_id_get_hp(cipher_id); + ctx->max_encryption = crypto_cipher_id_get_aead_max_encryption(cipher_id); + ctx->max_decryption_failure = + crypto_cipher_id_get_aead_max_decryption_failure(cipher_id); + + return ctx; +} + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { SSL *ssl = tls_native_handle; - ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_ssl_get_aead(ssl)); - ctx->md.native_handle = (void *)crypto_ssl_get_md(ssl); - ctx->hp.native_handle = (void *)crypto_ssl_get_hp(ssl); - ctx->max_encryption = crypto_ssl_get_aead_max_encryption(ssl); - ctx->max_decryption_failure = crypto_ssl_get_aead_max_decryption_failure(ssl); - return ctx; + const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + uint32_t cipher_id; + + if (cipher == NULL) { + return NULL; + } + + cipher_id = (uint32_t)SSL_CIPHER_get_id(cipher); + + if (!supported_cipher_id(cipher_id)) { + return NULL; + } + + return crypto_ctx_cipher_id(ctx, cipher_id); } ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx, @@ -327,7 +523,7 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, const uint8_t *salt, size_t saltlen) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L const EVP_MD *prf = md->native_handle; - EVP_KDF *kdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + EVP_KDF *kdf = crypto_kdf_hkdf(); EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf); int mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; OSSL_PARAM params[] = { @@ -342,7 +538,9 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, }; int rv = 0; - EVP_KDF_free(kdf); + if (!crypto_initialized) { + EVP_KDF_free(kdf); + } if (EVP_KDF_derive(kctx, dest, (size_t)EVP_MD_size(prf), params) <= 0) { rv = -1; @@ -382,7 +580,7 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, size_t infolen) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L const EVP_MD *prf = md->native_handle; - EVP_KDF *kdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + EVP_KDF *kdf = crypto_kdf_hkdf(); EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf); int mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; OSSL_PARAM params[] = { @@ -397,7 +595,9 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, }; int rv = 0; - EVP_KDF_free(kdf); + if (!crypto_initialized) { + EVP_KDF_free(kdf); + } if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) { rv = -1; @@ -436,7 +636,7 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, const uint8_t *info, size_t infolen) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L const EVP_MD *prf = md->native_handle; - EVP_KDF *kdf = EVP_KDF_fetch(NULL, "hkdf", NULL); + EVP_KDF *kdf = crypto_kdf_hkdf(); EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf); OSSL_PARAM params[] = { OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, @@ -451,7 +651,9 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, }; int rv = 0; - EVP_KDF_free(kdf); + if (!crypto_initialized) { + EVP_KDF_free(kdf); + } if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) { rv = -1; @@ -591,15 +793,16 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, return 0; } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +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); int rv; int err; if (SSL_provide_quic_data( - ssl, ngtcp2_crypto_openssl_from_ngtcp2_crypto_level(crypto_level), + ssl, + ngtcp2_crypto_quictls_from_ngtcp2_encryption_level(encryption_level), data, datalen) != 1) { return -1; } @@ -613,9 +816,9 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, case SSL_ERROR_WANT_WRITE: return 0; case SSL_ERROR_WANT_CLIENT_HELLO_CB: - return NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB; + return NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB; case SSL_ERROR_WANT_X509_LOOKUP: - return NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP; + return NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP; case SSL_ERROR_SSL: return -1; default: @@ -623,7 +826,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, } } - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = SSL_process_quic_post_handshake(ssl); @@ -652,7 +855,7 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) { SSL_get_peer_quic_transport_params(ssl, &tp, &tplen); - rv = ngtcp2_conn_decode_remote_transport_params(conn, tp, tplen); + rv = ngtcp2_conn_decode_and_set_remote_transport_params(conn, tp, tplen); if (rv != 0) { ngtcp2_conn_set_tls_error(conn, rv); return -1; @@ -670,17 +873,17 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_openssl_from_ossl_encryption_level( +ngtcp2_encryption_level ngtcp2_crypto_quictls_from_ossl_encryption_level( OSSL_ENCRYPTION_LEVEL ossl_level) { switch (ossl_level) { case ssl_encryption_initial: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case ssl_encryption_early_data: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case ssl_encryption_handshake: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case ssl_encryption_application: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); /* if NDEBUG is set */ @@ -688,16 +891,16 @@ ngtcp2_crypto_level ngtcp2_crypto_openssl_from_ossl_encryption_level( } OSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_openssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +ngtcp2_crypto_quictls_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return ssl_encryption_initial; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return ssl_encryption_handshake; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return ssl_encryption_application; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return ssl_encryption_early_data; default: assert(0); @@ -730,8 +933,8 @@ static int set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *tx_secret, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = - ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); + ngtcp2_encryption_level level = + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); if (rx_secret && ngtcp2_crypto_derive_and_install_rx_key(conn, NULL, NULL, NULL, level, @@ -752,8 +955,8 @@ static int add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *data, size_t datalen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = - ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); + ngtcp2_encryption_level level = + ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); int rv; rv = ngtcp2_conn_submit_crypto_data(conn, level, data, datalen); @@ -786,22 +989,26 @@ static SSL_QUIC_METHOD quic_method = { add_handshake_data, flush_flight, send_alert, +#ifdef LIBRESSL_VERSION_NUMBER + NULL, + NULL, +#endif /* LIBRESSL_VERSION_NUMBER */ }; -static void crypto_openssl_configure_context(SSL_CTX *ssl_ctx) { +static void crypto_quictls_configure_context(SSL_CTX *ssl_ctx) { SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_quic_method(ssl_ctx, &quic_method); } -int ngtcp2_crypto_openssl_configure_server_context(SSL_CTX *ssl_ctx) { - crypto_openssl_configure_context(ssl_ctx); +int ngtcp2_crypto_quictls_configure_server_context(SSL_CTX *ssl_ctx) { + crypto_quictls_configure_context(ssl_ctx); return 0; } -int ngtcp2_crypto_openssl_configure_client_context(SSL_CTX *ssl_ctx) { - crypto_openssl_configure_context(ssl_ctx); +int ngtcp2_crypto_quictls_configure_client_context(SSL_CTX *ssl_ctx) { + crypto_quictls_configure_context(ssl_ctx); return 0; } diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.c b/deps/ngtcp2/ngtcp2/crypto/shared.c index 78252b852b4fab..162094a375cb8b 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.c +++ b/deps/ngtcp2/ngtcp2/crypto/shared.c @@ -64,11 +64,9 @@ int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen, (size_t)(p - info)); } -#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32 - -int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret, - uint8_t *tx_secret, +int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *initial_secret, + uint32_t version, const ngtcp2_cid *client_dcid, ngtcp2_crypto_side side) { static const uint8_t CLABEL[] = "client in"; @@ -88,16 +86,14 @@ int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret, switch (version) { case NGTCP2_PROTO_VER_V1: + default: salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V1; saltlen = sizeof(NGTCP2_INITIAL_SALT_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V2_DRAFT; - saltlen = sizeof(NGTCP2_INITIAL_SALT_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V2; + saltlen = sizeof(NGTCP2_INITIAL_SALT_V2) - 1; break; - default: - salt = (const uint8_t *)NGTCP2_INITIAL_SALT_DRAFT; - saltlen = sizeof(NGTCP2_INITIAL_SALT_DRAFT) - 1; } if (ngtcp2_crypto_hkdf_extract(initial_secret, &ctx.md, client_dcid->data, @@ -139,9 +135,9 @@ int ngtcp2_crypto_derive_packet_protection_key( static const uint8_t KEY_LABEL_V1[] = "quic key"; static const uint8_t IV_LABEL_V1[] = "quic iv"; static const uint8_t HP_KEY_LABEL_V1[] = "quic hp"; - static const uint8_t KEY_LABEL_V2_DRAFT[] = "quicv2 key"; - static const uint8_t IV_LABEL_V2_DRAFT[] = "quicv2 iv"; - static const uint8_t HP_KEY_LABEL_V2_DRAFT[] = "quicv2 hp"; + static const uint8_t KEY_LABEL_V2[] = "quicv2 key"; + static const uint8_t IV_LABEL_V2[] = "quicv2 iv"; + static const uint8_t HP_KEY_LABEL_V2[] = "quicv2 hp"; size_t keylen = ngtcp2_crypto_aead_keylen(aead); size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); const uint8_t *key_label; @@ -152,13 +148,13 @@ int ngtcp2_crypto_derive_packet_protection_key( size_t hp_key_labellen; switch (version) { - case NGTCP2_PROTO_VER_V2_DRAFT: - key_label = KEY_LABEL_V2_DRAFT; - key_labellen = sizeof(KEY_LABEL_V2_DRAFT) - 1; - iv_label = IV_LABEL_V2_DRAFT; - iv_labellen = sizeof(IV_LABEL_V2_DRAFT) - 1; - hp_key_label = HP_KEY_LABEL_V2_DRAFT; - hp_key_labellen = sizeof(HP_KEY_LABEL_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + key_label = KEY_LABEL_V2; + key_labellen = sizeof(KEY_LABEL_V2) - 1; + iv_label = IV_LABEL_V2; + iv_labellen = sizeof(IV_LABEL_V2) - 1; + hp_key_label = HP_KEY_LABEL_V2; + hp_key_labellen = sizeof(HP_KEY_LABEL_V2) - 1; break; default: key_label = KEY_LABEL_V1; @@ -188,14 +184,27 @@ int ngtcp2_crypto_derive_packet_protection_key( return 0; } -int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, +int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, uint32_t version, const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen) { static const uint8_t LABEL[] = "quic ku"; + static const uint8_t LABEL_V2[] = "quicv2 ku"; + const uint8_t *label; + size_t labellen; + + switch (version) { + case NGTCP2_PROTO_VER_V2: + label = LABEL_V2; + labellen = sizeof(LABEL_V2) - 1; + break; + default: + label = LABEL; + labellen = sizeof(LABEL) - 1; + } if (ngtcp2_crypto_hkdf_expand_label(dest, secretlen, md, secret, secretlen, - LABEL, sizeof(LABEL) - 1) != 0) { + label, labellen) != 0) { return -1; } @@ -204,7 +213,7 @@ int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp_key, - ngtcp2_crypto_level level, + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen) { const ngtcp2_crypto_ctx *ctx; @@ -220,7 +229,7 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, ngtcp2_crypto_ctx cctx; uint32_t version; - if (level == NGTCP2_CRYPTO_LEVEL_EARLY && !ngtcp2_conn_is_server(conn)) { + if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && !ngtcp2_conn_is_server(conn)) { return 0; } @@ -235,13 +244,16 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - ngtcp2_crypto_ctx_tls_early(&cctx, tls); - ngtcp2_conn_set_early_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_early_crypto_ctx(conn); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + if (ngtcp2_crypto_ctx_tls_early(&cctx, tls) == NULL) { + return -1; + } + + ngtcp2_conn_set_0rtt_crypto_ctx(conn, &cctx); + ctx = ngtcp2_conn_get_0rtt_crypto_ctx(conn); version = ngtcp2_conn_get_client_chosen_version(conn); break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: if (ngtcp2_conn_is_server(conn) && !ngtcp2_conn_get_negotiated_version(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); @@ -250,15 +262,21 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } } /* fall through */ - default: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: ctx = ngtcp2_conn_get_crypto_ctx(conn); version = ngtcp2_conn_get_negotiated_version(conn); if (!ctx->aead.native_handle) { - ngtcp2_crypto_ctx_tls(&cctx, tls); + if (ngtcp2_crypto_ctx_tls(&cctx, tls) == NULL) { + return -1; + } + ngtcp2_conn_set_crypto_ctx(conn, &cctx); ctx = ngtcp2_conn_get_crypto_ctx(conn); } + break; + default: + return -1; } aead = &ctx->aead; @@ -280,20 +298,20 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + rv = ngtcp2_conn_install_0rtt_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { goto fail; } break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: rv = ngtcp2_conn_install_rx_handshake_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { goto fail; } break; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: if (!ngtcp2_conn_is_server(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); if (rv != 0) { @@ -345,7 +363,7 @@ static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) { int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp_key, - ngtcp2_crypto_level level, + ngtcp2_encryption_level level, const uint8_t *secret, size_t secretlen) { const ngtcp2_crypto_ctx *ctx; @@ -361,7 +379,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, ngtcp2_crypto_ctx cctx; uint32_t version; - if (level == NGTCP2_CRYPTO_LEVEL_EARLY && ngtcp2_conn_is_server(conn)) { + if (level == NGTCP2_ENCRYPTION_LEVEL_0RTT && ngtcp2_conn_is_server(conn)) { return 0; } @@ -376,13 +394,16 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - ngtcp2_crypto_ctx_tls_early(&cctx, tls); - ngtcp2_conn_set_early_crypto_ctx(conn, &cctx); - ctx = ngtcp2_conn_get_early_crypto_ctx(conn); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + if (ngtcp2_crypto_ctx_tls_early(&cctx, tls) == NULL) { + return -1; + } + + ngtcp2_conn_set_0rtt_crypto_ctx(conn, &cctx); + ctx = ngtcp2_conn_get_0rtt_crypto_ctx(conn); version = ngtcp2_conn_get_client_chosen_version(conn); break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: if (ngtcp2_conn_is_server(conn) && !ngtcp2_conn_get_negotiated_version(conn)) { rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); @@ -391,15 +412,21 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } } /* fall through */ - default: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: ctx = ngtcp2_conn_get_crypto_ctx(conn); version = ngtcp2_conn_get_negotiated_version(conn); if (!ctx->aead.native_handle) { - ngtcp2_crypto_ctx_tls(&cctx, tls); + if (ngtcp2_crypto_ctx_tls(&cctx, tls) == NULL) { + return -1; + } + ngtcp2_conn_set_crypto_ctx(conn, &cctx); ctx = ngtcp2_conn_get_crypto_ctx(conn); } + break; + default: + return -1; } aead = &ctx->aead; @@ -421,13 +448,13 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } switch (level) { - case NGTCP2_CRYPTO_LEVEL_EARLY: - rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); + case NGTCP2_ENCRYPTION_LEVEL_0RTT: + rv = ngtcp2_conn_install_0rtt_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { goto fail; } break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: rv = ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { @@ -440,7 +467,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key, } break; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: rv = ngtcp2_conn_install_tx_key(conn, secret, secretlen, &aead_ctx, iv, ivlen, &hp_ctx); if (rv != 0) { @@ -521,7 +548,7 @@ int ngtcp2_crypto_derive_and_install_initial_key( ngtcp2_conn_set_initial_crypto_ctx(conn, &ctx); if (ngtcp2_crypto_derive_initial_secrets( - version, rx_secret, tx_secret, initial_secret, client_dcid, + rx_secret, tx_secret, initial_secret, version, client_dcid, server ? NGTCP2_CRYPTO_SIDE_SERVER : NGTCP2_CRYPTO_SIDE_CLIENT) != 0) { return -1; @@ -564,16 +591,14 @@ int ngtcp2_crypto_derive_and_install_initial_key( switch (version) { case NGTCP2_PROTO_VER_V1: + default: retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V1; retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V2_DRAFT; - retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V2; + retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_DRAFT; - retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } if (ngtcp2_crypto_aead_ctx_encrypt_init(&retry_aead_ctx, &retry_aead, @@ -657,7 +682,7 @@ int ngtcp2_crypto_derive_and_install_vneg_initial_key( } if (ngtcp2_crypto_derive_initial_secrets( - version, rx_secret, tx_secret, initial_secret, client_dcid, + rx_secret, tx_secret, initial_secret, version, client_dcid, server ? NGTCP2_CRYPTO_SIDE_SERVER : NGTCP2_CRYPTO_SIDE_CLIENT) != 0) { return -1; @@ -725,8 +750,8 @@ int ngtcp2_crypto_update_key( size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); uint32_t version = ngtcp2_conn_get_negotiated_version(conn); - if (ngtcp2_crypto_update_traffic_secret(rx_secret, md, current_rx_secret, - secretlen) != 0) { + if (ngtcp2_crypto_update_traffic_secret(rx_secret, version, md, + current_rx_secret, secretlen) != 0) { return -1; } @@ -735,8 +760,8 @@ int ngtcp2_crypto_update_key( return -1; } - if (ngtcp2_crypto_update_traffic_secret(tx_secret, md, current_tx_secret, - secretlen) != 0) { + if (ngtcp2_crypto_update_traffic_secret(tx_secret, version, md, + current_tx_secret, secretlen) != 0) { return -1; } @@ -883,6 +908,7 @@ static size_t crypto_generate_retry_token_aad(uint8_t *dest, uint32_t version, version = ngtcp2_htonl(version); memcpy(p, &version, sizeof(version)); + p += sizeof(version); memcpy(p, sa, (size_t)salen); p += salen; memcpy(p, retry_scid->data, retry_scid->datalen); @@ -907,13 +933,15 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token( ngtcp2_crypto_md md; ngtcp2_crypto_aead_ctx aead_ctx; size_t plaintextlen; - uint8_t aad[sizeof(version) + sizeof(ngtcp2_sockaddr_storage) + - NGTCP2_MAX_CIDLEN]; + uint8_t + aad[sizeof(version) + sizeof(ngtcp2_sockaddr_union) + NGTCP2_MAX_CIDLEN]; size_t aadlen; uint8_t *p = plaintext; ngtcp2_tstamp ts_be = ngtcp2_htonl64(ts); int rv; + assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union)); + memset(plaintext, 0, sizeof(plaintext)); *p++ = (uint8_t)odcid->datalen; @@ -984,8 +1012,8 @@ int ngtcp2_crypto_verify_retry_token( ngtcp2_crypto_aead_ctx aead_ctx; ngtcp2_crypto_aead aead; ngtcp2_crypto_md md; - uint8_t aad[sizeof(version) + sizeof(ngtcp2_sockaddr_storage) + - NGTCP2_MAX_CIDLEN]; + uint8_t + aad[sizeof(version) + sizeof(ngtcp2_sockaddr_union) + NGTCP2_MAX_CIDLEN]; size_t aadlen; const uint8_t *rand_data; const uint8_t *ciphertext; @@ -994,6 +1022,8 @@ int ngtcp2_crypto_verify_retry_token( int rv; ngtcp2_tstamp gen_ts; + assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union)); + if (tokenlen != NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN || token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY) { return -1; @@ -1034,7 +1064,9 @@ int ngtcp2_crypto_verify_retry_token( cil = plaintext[0]; - assert(cil == 0 || (cil >= NGTCP2_MIN_CIDLEN && cil <= NGTCP2_MAX_CIDLEN)); + if (cil != 0 && (cil < NGTCP2_MIN_CIDLEN || cil > NGTCP2_MAX_CIDLEN)) { + return -1; + } memcpy(&gen_ts, plaintext + /* cid len = */ 1 + NGTCP2_MAX_CIDLEN, sizeof(gen_ts)); @@ -1055,11 +1087,11 @@ static size_t crypto_generate_regular_token_aad(uint8_t *dest, size_t addrlen; switch (sa->sa_family) { - case AF_INET: + case NGTCP2_AF_INET: addr = (const uint8_t *)&((const ngtcp2_sockaddr_in *)(void *)sa)->sin_addr; addrlen = sizeof(((const ngtcp2_sockaddr_in *)(void *)sa)->sin_addr); break; - case AF_INET6: + case NGTCP2_AF_INET6: addr = (const uint8_t *)&((const ngtcp2_sockaddr_in6 *)(void *)sa)->sin6_addr; addrlen = sizeof(((const ngtcp2_sockaddr_in6 *)(void *)sa)->sin6_addr); @@ -1234,8 +1266,8 @@ ngtcp2_ssize ngtcp2_crypto_write_connection_close( ngtcp2_crypto_ctx_initial(&ctx); - if (ngtcp2_crypto_derive_initial_secrets(version, rx_secret, tx_secret, - initial_secret, scid, + if (ngtcp2_crypto_derive_initial_secrets(rx_secret, tx_secret, initial_secret, + version, scid, NGTCP2_CRYPTO_SIDE_SERVER) != 0) { return -1; } @@ -1287,16 +1319,14 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, switch (version) { case NGTCP2_PROTO_VER_V1: + default: key = (const uint8_t *)NGTCP2_RETRY_KEY_V1; noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - key = (const uint8_t *)NGTCP2_RETRY_KEY_V2_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + key = (const uint8_t *)NGTCP2_RETRY_KEY_V2; + noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - key = (const uint8_t *)NGTCP2_RETRY_KEY_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &aead, key, noncelen) != @@ -1331,8 +1361,8 @@ int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, void *user_data) { return NGTCP2_ERR_CALLBACK_FAILURE; } - if (ngtcp2_crypto_read_write_crypto_data(conn, NGTCP2_CRYPTO_LEVEL_INITIAL, - NULL, 0) != 0) { + if (ngtcp2_crypto_read_write_crypto_data( + conn, NGTCP2_ENCRYPTION_LEVEL_INITIAL, NULL, 0) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1398,15 +1428,15 @@ void ngtcp2_crypto_delete_crypto_cipher_ctx_cb( } int ngtcp2_crypto_recv_crypto_data_cb(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data) { int rv; (void)offset; (void)user_data; - if (ngtcp2_crypto_read_write_crypto_data(conn, crypto_level, data, datalen) != - 0) { + if (ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data, + datalen) != 0) { rv = ngtcp2_conn_get_tls_error(conn); if (rv) { return rv; diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.h b/deps/ngtcp2/ngtcp2/crypto/shared.h index 02b948901ae40e..d69fd21212d7d2 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.h +++ b/deps/ngtcp2/ngtcp2/crypto/shared.h @@ -31,16 +31,6 @@ #include -/** - * @macro - * - * :macro:`NGTCP2_INITIAL_SALT_DRAFT` is a salt value which is used to - * derive initial secret. It is used for QUIC draft versions. - */ -#define NGTCP2_INITIAL_SALT_DRAFT \ - "\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97\x86\xf1\x9c\x61\x11\xe0\x43\x90" \ - "\xa8\x99" - /** * @macro * @@ -54,12 +44,12 @@ /** * @macro * - * :macro:`NGTCP2_INITIAL_SALT_V2_DRAFT` is a salt value which is used to - * derive initial secret. It is used for QUIC v2 draft. + * :macro:`NGTCP2_INITIAL_SALT_V2` is a salt value which is used to + * derive initial secret. It is used for QUIC v2. */ -#define NGTCP2_INITIAL_SALT_V2_DRAFT \ - "\xa7\x07\xc2\x03\xa5\x9b\x47\x18\x4a\x1d\x62\xca\x57\x04\x06\xea\x7a\xe3" \ - "\xe5\xd3" +#define NGTCP2_INITIAL_SALT_V2 \ + "\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb\xf9\xbd" \ + "\x2e\xd9" /* Maximum key usage (encryption) limits */ #define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM (1ULL << 23) @@ -72,6 +62,30 @@ #define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305 (1ULL << 36) #define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM (2965820ULL) +/** + * @macro + * + * :macro:`NGTCP2_CRYPTO_INITIAL_SECRETLEN` is the length of secret + * for Initial packets. + */ +#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32 + +/** + * @macro + * + * :macro:`NGTCP2_CRYPTO_INITIAL_KEYLEN` is the length of key for + * Initial packets. + */ +#define NGTCP2_CRYPTO_INITIAL_KEYLEN 16 + +/** + * @macro + * + * :macro:`NGTCP2_CRYPTO_INITIAL_IVLEN` is the length of IV for + * Initial packets. + */ +#define NGTCP2_CRYPTO_INITIAL_IVLEN 12 + /** * @function * @@ -86,7 +100,7 @@ ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx); * `ngtcp2_crypto_aead_init` initializes |aead| with the provided * |aead_native_handle| which is an underlying AEAD object. * - * If libngtcp2_crypto_openssl is linked, |aead_native_handle| must be + * If libngtcp2_crypto_quictls is linked, |aead_native_handle| must be * a pointer to EVP_CIPHER. * * If libngtcp2_crypto_gnutls is linked, |aead_native_handle| must be @@ -106,6 +120,25 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_init(ngtcp2_crypto_aead *aead, */ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead); +/** + * @enum + * + * :type:`ngtcp2_crypto_side` indicates which side the application + * implements; client or server. + */ +typedef enum ngtcp2_crypto_side { + /** + * :enum:`NGTCP2_CRYPTO_SIDE_CLIENT` indicates that the application + * is client. + */ + NGTCP2_CRYPTO_SIDE_CLIENT, + /** + * :enum:`NGTCP2_CRYPTO_SIDE_SERVER` indicates that the application + * is server. + */ + NGTCP2_CRYPTO_SIDE_SERVER +} ngtcp2_crypto_side; + /** * @function * @@ -122,9 +155,9 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead); * * This function returns 0 if it succeeds, or -1. */ -int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret, - uint8_t *tx_secret, +int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *initial_secret, + uint32_t version, const ngtcp2_cid *client_dcid, ngtcp2_crypto_side side); @@ -168,7 +201,7 @@ int ngtcp2_crypto_derive_packet_protection_key(uint8_t *key, uint8_t *iv, * * This function returns 0 if it succeeds, or -1. */ -int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, +int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, uint32_t version, const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen); @@ -181,7 +214,7 @@ int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, * pointed by |buf| of length |len|, to the native handle |tls|. * * |tls| points to a implementation dependent TLS session object. If - * libngtcp2_crypto_openssl is linked, |tls| must be a pointer to SSL + * libngtcp2_crypto_quictls is linked, |tls| must be a pointer to SSL * object. * * This function returns 0 if it succeeds, or -1. @@ -197,7 +230,7 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, * `ngtcp2_conn_set_remote_transport_params`. * * |tls| points to a implementation dependent TLS session object. If - * libngtcp2_crypto_openssl is linked, |tls| must be a pointer to SSL + * libngtcp2_crypto_quictls is linked, |tls| must be a pointer to SSL * object. * * This function returns 0 if it succeeds, or -1. @@ -347,4 +380,18 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_aes_128_gcm(ngtcp2_crypto_aead *aead); */ int ngtcp2_crypto_random(uint8_t *data, size_t datalen); +/** + * @function + * + * `ngtcp2_crypto_hkdf_expand_label` performs HKDF expand label. The + * result is |destlen| bytes long, and is stored to the buffer pointed + * by |dest|. + * + * This function returns 0 if it succeeds, or -1. + */ +int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen, + const ngtcp2_crypto_md *md, + const uint8_t *secret, size_t secretlen, + const uint8_t *label, size_t labellen); + #endif /* NGTCP2_SHARED_H */ diff --git a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c index 9a58b9be2b76e9..2b7b5321863915 100644 --- a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c @@ -73,9 +73,8 @@ ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) { return ngtcp2_crypto_aead_init(aead, (void *)wolfSSL_EVP_aes_128_gcm()); } -static uint64_t crypto_wolfssl_get_aead_max_encryption(WOLFSSL *ssl) { - const WOLFSSL_EVP_CIPHER *aead = wolfSSL_quic_get_aead(ssl); - +static uint64_t +crypto_aead_get_aead_max_encryption(const WOLFSSL_EVP_CIPHER *aead) { if (wolfSSL_quic_aead_is_gcm(aead)) { return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; } @@ -88,9 +87,8 @@ static uint64_t crypto_wolfssl_get_aead_max_encryption(WOLFSSL *ssl) { return 0; } -static uint64_t crypto_wolfssl_get_aead_max_decryption_failure(WOLFSSL *ssl) { - const WOLFSSL_EVP_CIPHER *aead = wolfSSL_quic_get_aead(ssl); - +static uint64_t +crypto_aead_get_aead_max_decryption_failure(const WOLFSSL_EVP_CIPHER *aead) { if (wolfSSL_quic_aead_is_gcm(aead)) { return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; } @@ -103,16 +101,30 @@ static uint64_t crypto_wolfssl_get_aead_max_decryption_failure(WOLFSSL *ssl) { return 0; } +static int supported_aead(const WOLFSSL_EVP_CIPHER *aead) { + return wolfSSL_quic_aead_is_gcm(aead) || + wolfSSL_quic_aead_is_chacha20(aead) || wolfSSL_quic_aead_is_ccm(aead); +} + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { WOLFSSL *ssl = tls_native_handle; + const WOLFSSL_EVP_CIPHER *aead = wolfSSL_quic_get_aead(ssl); - ngtcp2_crypto_aead_init(&ctx->aead, (void *)wolfSSL_quic_get_aead(ssl)); + if (aead == NULL) { + return NULL; + } + + if (!supported_aead(aead)) { + return NULL; + } + + ngtcp2_crypto_aead_init(&ctx->aead, (void *)aead); ctx->md.native_handle = (void *)wolfSSL_quic_get_md(ssl); ctx->hp.native_handle = (void *)wolfSSL_quic_get_hp(ssl); - ctx->max_encryption = crypto_wolfssl_get_aead_max_encryption(ssl); + ctx->max_encryption = crypto_aead_get_aead_max_encryption(aead); ctx->max_decryption_failure = - crypto_wolfssl_get_aead_max_decryption_failure(ssl); + crypto_aead_get_aead_max_decryption_failure(aead); return ctx; } @@ -211,6 +223,7 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md, const uint8_t *salt, size_t saltlen) { if (wolfSSL_quic_hkdf_extract(dest, md->native_handle, secret, secretlen, salt, saltlen) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: wolfSSL_quic_hkdf_extract FAILED\n"); return -1; } return 0; @@ -222,6 +235,7 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen, size_t infolen) { if (wolfSSL_quic_hkdf_expand(dest, destlen, md->native_handle, secret, secretlen, info, infolen) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: wolfSSL_quic_hkdf_expand FAILED\n"); return -1; } return 0; @@ -233,6 +247,7 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen, const uint8_t *info, size_t infolen) { if (wolfSSL_quic_hkdf(dest, destlen, md->native_handle, secret, secretlen, salt, saltlen, info, infolen) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: wolfSSL_quic_hkdf FAILED\n"); return -1; } return 0; @@ -286,18 +301,19 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, sizeof(PLAINTEXT) - 1) != WOLFSSL_SUCCESS || wolfSSL_EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len) != WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: hp_mask FAILED\n"); return -1; } return 0; } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - const uint8_t *data, size_t datalen) { +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_ENCRYPTION_LEVEL level = - ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level(crypto_level); + ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level(encryption_level); int rv; int err; @@ -313,9 +329,9 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, if (!ngtcp2_conn_get_handshake_completed(conn)) { rv = wolfSSL_quic_do_handshake(ssl); - DEBUG_MSG("WOLFSSL: do_handshake, rv=%d\n", rv); if (rv <= 0) { err = wolfSSL_get_error(ssl, rv); + DEBUG_MSG("WOLFSSL: do_handshake, rv=%d, err=%d\n", rv, err); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: @@ -328,7 +344,7 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, } DEBUG_MSG("WOLFSSL: handshake done\n"); - ngtcp2_conn_handshake_completed(conn); + ngtcp2_conn_tls_handshake_completed(conn); } rv = wolfSSL_process_quic_post_handshake(ssl); @@ -359,7 +375,7 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) { wolfSSL_get_peer_quic_transport_params(ssl, &tp, &tplen); DEBUG_MSG("WOLFSSL: get peer transport params, len=%lu\n", tplen); - rv = ngtcp2_conn_decode_remote_transport_params(conn, tp, tplen); + rv = ngtcp2_conn_decode_and_set_remote_transport_params(conn, tp, tplen); if (rv != 0) { DEBUG_MSG("WOLFSSL: decode peer transport params failed, rv=%d\n", rv); ngtcp2_conn_set_tls_error(conn, rv); @@ -380,17 +396,17 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, return 0; } -ngtcp2_crypto_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( +ngtcp2_encryption_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( WOLFSSL_ENCRYPTION_LEVEL wolfssl_level) { switch (wolfssl_level) { case wolfssl_encryption_initial: - return NGTCP2_CRYPTO_LEVEL_INITIAL; + return NGTCP2_ENCRYPTION_LEVEL_INITIAL; case wolfssl_encryption_early_data: - return NGTCP2_CRYPTO_LEVEL_EARLY; + return NGTCP2_ENCRYPTION_LEVEL_0RTT; case wolfssl_encryption_handshake: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + return NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; case wolfssl_encryption_application: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; + return NGTCP2_ENCRYPTION_LEVEL_1RTT; default: assert(0); abort(); /* if NDEBUG is set */ @@ -398,16 +414,16 @@ ngtcp2_crypto_level ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level( } WOLFSSL_ENCRYPTION_LEVEL -ngtcp2_crypto_wolfssl_from_ngtcp2_crypto_level( - ngtcp2_crypto_level crypto_level) { - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: +ngtcp2_crypto_wolfssl_from_ngtcp2_encryption_level( + ngtcp2_encryption_level encryption_level) { + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: return wolfssl_encryption_initial; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: return wolfssl_encryption_handshake; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: return wolfssl_encryption_application; - case NGTCP2_CRYPTO_LEVEL_EARLY: + case NGTCP2_ENCRYPTION_LEVEL_0RTT: return wolfssl_encryption_early_data; default: assert(0); @@ -441,7 +457,7 @@ static int set_encryption_secrets(WOLFSSL *ssl, const uint8_t *tx_secret, size_t secretlen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level(wolfssl_level); DEBUG_MSG("WOLFSSL: set encryption secrets, level=%d, rxlen=%lu, txlen=%lu\n", @@ -467,7 +483,7 @@ static int add_handshake_data(WOLFSSL *ssl, const uint8_t *data, size_t datalen) { ngtcp2_crypto_conn_ref *conn_ref = SSL_get_app_data(ssl); ngtcp2_conn *conn = conn_ref->get_conn(conn_ref); - ngtcp2_crypto_level level = + ngtcp2_encryption_level level = ngtcp2_crypto_wolfssl_from_wolfssl_encryption_level(wolfssl_level); int rv; @@ -514,11 +530,17 @@ static void crypto_wolfssl_configure_context(WOLFSSL_CTX *ssl_ctx) { int ngtcp2_crypto_wolfssl_configure_server_context(WOLFSSL_CTX *ssl_ctx) { crypto_wolfssl_configure_context(ssl_ctx); +#if PRINTF_DEBUG + wolfSSL_Debugging_ON(); +#endif return 0; } int ngtcp2_crypto_wolfssl_configure_client_context(WOLFSSL_CTX *ssl_ctx) { crypto_wolfssl_configure_context(ssl_ctx); wolfSSL_CTX_UseSessionTicket(ssl_ctx); +#if PRINTF_DEBUG + wolfSSL_Debugging_ON(); +#endif return 0; } diff --git a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h index ed71cb3ea0cb37..f16d15cb39bb52 100644 --- a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h +++ b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h @@ -54,26 +54,13 @@ # ifdef WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN -# endif +# endif /* WIN32_LEAN_AND_MEAN */ # include -# else +# else /* !WIN32 */ # include # include -# endif -#endif - -#ifdef AF_INET -# define NGTCP2_AF_INET AF_INET -#else -# define NGTCP2_AF_INET 2 -#endif - -#ifdef AF_INET6 -# define NGTCP2_AF_INET6 AF_INET6 -#else -# define NGTCP2_AF_INET6 23 -# define NGTCP2_USE_GENERIC_IPV6_SOCKADDR -#endif +# endif /* !WIN32 */ +#endif /* NGTCP2_USE_GENERIC_SOCKADDR */ #include @@ -181,7 +168,7 @@ typedef void *(*ngtcp2_realloc)(void *ptr, size_t size, void *user_data); * * void conn_new() { * ngtcp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb, - * my_realloc_cb}; + * my_realloc_cb}; * * ... * } @@ -223,7 +210,8 @@ typedef struct ngtcp2_mem { /** * @macro * - * :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1 second. + * :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1 + * second. */ #define NGTCP2_SECONDS ((ngtcp2_duration)1000000000ULL) @@ -267,34 +255,16 @@ typedef struct ngtcp2_mem { /** * @macro * - * :macro:`NGTCP2_PROTO_VER_V2_DRAFT` is the provisional version - * number for QUIC version 2 draft. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html - */ -#define NGTCP2_PROTO_VER_V2_DRAFT ((uint32_t)0x709a50c4u) - -/** - * @macro - * - * :macro:`NGTCP2_PROTO_VER_DRAFT_MAX` is the maximum QUIC draft - * version that this library supports. - */ -#define NGTCP2_PROTO_VER_DRAFT_MAX 0xff000020u - -/** - * @macro - * - * :macro:`NGTCP2_PROTO_VER_DRAFT_MIN` is the minimum QUIC draft - * version that this library supports. + * :macro:`NGTCP2_PROTO_VER_V2` is the QUIC version 2. See + * :rfc:`9369`. */ -#define NGTCP2_PROTO_VER_DRAFT_MIN 0xff00001du +#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6b3343cfu) /** * @macro * * :macro:`NGTCP2_PROTO_VER_MAX` is the highest QUIC version that this - * library supports. + * library supports. Deprecated since v1.1.0. */ #define NGTCP2_PROTO_VER_MAX NGTCP2_PROTO_VER_V1 @@ -302,9 +272,9 @@ typedef struct ngtcp2_mem { * @macro * * :macro:`NGTCP2_PROTO_VER_MIN` is the lowest QUIC version that this - * library supports. + * library supports. Deprecated since v1.1.0. */ -#define NGTCP2_PROTO_VER_MIN NGTCP2_PROTO_VER_DRAFT_MIN +#define NGTCP2_PROTO_VER_MIN NGTCP2_PROTO_VER_V1 /** * @macro @@ -324,7 +294,7 @@ typedef struct ngtcp2_mem { * @macro * * :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE` is the default maximum UDP - * datagram payload size that this endpoint transmits. + * datagram payload size that the local endpoint transmits. */ #define NGTCP2_MAX_UDP_PAYLOAD_SIZE 1200 @@ -362,7 +332,7 @@ typedef struct ngtcp2_mem { * @macro * * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN` is the minimum length - * of random bytes (Unpredictable Bits) in Stateless Reset packet + * of random bytes (Unpredictable Bits) in Stateless Reset packet. */ #define NGTCP2_MIN_STATELESS_RESET_RANDLEN 5 @@ -374,24 +344,6 @@ typedef struct ngtcp2_mem { */ #define NGTCP2_PATH_CHALLENGE_DATALEN 8 -/** - * @macro - * - * :macro:`NGTCP2_RETRY_KEY_DRAFT` is an encryption key to create - * integrity tag of Retry packet. It is used for QUIC draft versions. - */ -#define NGTCP2_RETRY_KEY_DRAFT \ - "\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1" - -/** - * @macro - * - * :macro:`NGTCP2_RETRY_NONCE_DRAFT` is nonce used when generating - * integrity tag of Retry packet. It is used for QUIC draft versions. - */ -#define NGTCP2_RETRY_NONCE_DRAFT \ - "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c" - /** * @macro * @@ -404,32 +356,29 @@ typedef struct ngtcp2_mem { /** * @macro * - * :macro:`NGTCP2_RETRY_NONCE_V1` is nonce used when generating integrity - * tag of Retry packet. It is used for QUIC v1. + * :macro:`NGTCP2_RETRY_NONCE_V1` is nonce used when generating + * integrity tag of Retry packet. It is used for QUIC v1. */ #define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb" /** * @macro * - * :macro:`NGTCP2_RETRY_KEY_V2_DRAFT` is an encryption key to create - * integrity tag of Retry packet. It is used for QUIC v2 draft. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html + * :macro:`NGTCP2_RETRY_KEY_V2` is an encryption key to create + * integrity tag of Retry packet. It is used for QUIC v2. See + * :rfc:`9369`. */ -#define NGTCP2_RETRY_KEY_V2_DRAFT \ - "\xba\x85\x8d\xc7\xb4\x3d\xe5\xdb\xf8\x76\x17\xff\x4a\xb2\x53\xdb" +#define NGTCP2_RETRY_KEY_V2 \ + "\x8f\xb4\xb0\x1b\x56\xac\x48\xe2\x60\xfb\xcb\xce\xad\x7c\xcc\x92" /** * @macro * - * :macro:`NGTCP2_RETRY_NONCE_V2_DRAFT` is nonce used when generating - * integrity tag of Retry packet. It is used for QUIC v2 draft. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html + * :macro:`NGTCP2_RETRY_NONCE_V2` is nonce used when generating + * integrity tag of Retry packet. It is used for QUIC v2. See + * :rfc:`9369`. */ -#define NGTCP2_RETRY_NONCE_V2_DRAFT \ - "\x14\x1b\x99\xc2\x39\xb0\x3e\x78\x5d\x6a\x2e\x9f" +#define NGTCP2_RETRY_NONCE_V2 "\xd8\x69\x69\xbc\x2d\x7c\x6d\x99\x90\xef\xb0\x4a" /** * @macro @@ -476,14 +425,6 @@ typedef struct ngtcp2_mem { */ #define NGTCP2_MIN_INITIAL_DCIDLEN 8 -/** - * @macro - * - * :macro:`NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT` is the default handshake - * timeout. - */ -#define NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT (10 * NGTCP2_SECONDS) - /** * @macrosection * @@ -525,8 +466,8 @@ typedef struct ngtcp2_mem { */ #define NGTCP2_ECN_MASK 0x3 -#define NGTCP2_PKT_INFO_VERSION_V1 1 -#define NGTCP2_PKT_INFO_VERSION NGTCP2_PKT_INFO_VERSION_V1 +#define NGTCP2_PKT_INFO_V1 1 +#define NGTCP2_PKT_INFO_VERSION NGTCP2_PKT_INFO_V1 /** * @struct @@ -535,12 +476,12 @@ typedef struct ngtcp2_mem { */ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { /** - * :member:`ecn` is ECN marking and when passing - * `ngtcp2_conn_read_pkt()`, and it should be either + * :member:`ecn` is ECN marking, and when it is passed to + * `ngtcp2_conn_read_pkt()`, it should be either * :macro:`NGTCP2_ECN_NOT_ECT`, :macro:`NGTCP2_ECN_ECT_1`, * :macro:`NGTCP2_ECN_ECT_0`, or :macro:`NGTCP2_ECN_CE`. */ - uint32_t ecn; + uint8_t ecn; } ngtcp2_pkt_info; /** @@ -562,190 +503,190 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * :macro:`NGTCP2_ERR_NOBUF` indicates that a provided buffer does not * have enough space to store data. */ -#define NGTCP2_ERR_NOBUF -203 +#define NGTCP2_ERR_NOBUF -202 /** * @macro * * :macro:`NGTCP2_ERR_PROTO` indicates a general protocol error. */ -#define NGTCP2_ERR_PROTO -205 +#define NGTCP2_ERR_PROTO -203 /** * @macro * * :macro:`NGTCP2_ERR_INVALID_STATE` indicates that a requested * operation is not allowed at the current connection state. */ -#define NGTCP2_ERR_INVALID_STATE -206 +#define NGTCP2_ERR_INVALID_STATE -204 /** * @macro * * :macro:`NGTCP2_ERR_ACK_FRAME` indicates that an invalid ACK frame * is received. */ -#define NGTCP2_ERR_ACK_FRAME -207 +#define NGTCP2_ERR_ACK_FRAME -205 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED` indicates that there is no * spare stream ID available. */ -#define NGTCP2_ERR_STREAM_ID_BLOCKED -208 +#define NGTCP2_ERR_STREAM_ID_BLOCKED -206 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_IN_USE` indicates that a stream ID is * already in use. */ -#define NGTCP2_ERR_STREAM_IN_USE -209 +#define NGTCP2_ERR_STREAM_IN_USE -207 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED` indicates that stream data * cannot be sent because of flow control. */ -#define NGTCP2_ERR_STREAM_DATA_BLOCKED -210 +#define NGTCP2_ERR_STREAM_DATA_BLOCKED -208 /** * @macro * * :macro:`NGTCP2_ERR_FLOW_CONTROL` indicates flow control error. */ -#define NGTCP2_ERR_FLOW_CONTROL -211 +#define NGTCP2_ERR_FLOW_CONTROL -209 /** * @macro * * :macro:`NGTCP2_ERR_CONNECTION_ID_LIMIT` indicates that the number * of received Connection ID exceeds acceptable limit. */ -#define NGTCP2_ERR_CONNECTION_ID_LIMIT -212 +#define NGTCP2_ERR_CONNECTION_ID_LIMIT -210 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_LIMIT` indicates that a remote endpoint * opens more streams that is permitted. */ -#define NGTCP2_ERR_STREAM_LIMIT -213 +#define NGTCP2_ERR_STREAM_LIMIT -211 /** * @macro * * :macro:`NGTCP2_ERR_FINAL_SIZE` indicates that inconsistent final * size of a stream. */ -#define NGTCP2_ERR_FINAL_SIZE -214 +#define NGTCP2_ERR_FINAL_SIZE -212 /** * @macro * * :macro:`NGTCP2_ERR_CRYPTO` indicates crypto (TLS) related error. */ -#define NGTCP2_ERR_CRYPTO -215 +#define NGTCP2_ERR_CRYPTO -213 /** * @macro * * :macro:`NGTCP2_ERR_PKT_NUM_EXHAUSTED` indicates that packet number * is exhausted. */ -#define NGTCP2_ERR_PKT_NUM_EXHAUSTED -216 +#define NGTCP2_ERR_PKT_NUM_EXHAUSTED -214 /** * @macro * * :macro:`NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM` indicates that a * required transport parameter is missing. */ -#define NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM -217 +#define NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM -215 /** * @macro * * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` indicates that a * transport parameter is malformed. */ -#define NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM -218 +#define NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM -216 /** * @macro * * :macro:`NGTCP2_ERR_FRAME_ENCODING` indicates there is an error in * frame encoding. */ -#define NGTCP2_ERR_FRAME_ENCODING -219 +#define NGTCP2_ERR_FRAME_ENCODING -217 /** * @macro * * :macro:`NGTCP2_ERR_DECRYPT` indicates a decryption failure. */ -#define NGTCP2_ERR_DECRYPT -220 +#define NGTCP2_ERR_DECRYPT -218 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_SHUT_WR` indicates no more data can be * sent to a stream. */ -#define NGTCP2_ERR_STREAM_SHUT_WR -221 +#define NGTCP2_ERR_STREAM_SHUT_WR -219 /** * @macro * - * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` indicates that a stream was not - * found. + * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` indicates that a stream was + * not found. */ -#define NGTCP2_ERR_STREAM_NOT_FOUND -222 +#define NGTCP2_ERR_STREAM_NOT_FOUND -220 /** * @macro * * :macro:`NGTCP2_ERR_STREAM_STATE` indicates that a requested * operation is not allowed at the current stream state. */ -#define NGTCP2_ERR_STREAM_STATE -226 +#define NGTCP2_ERR_STREAM_STATE -221 /** * @macro * * :macro:`NGTCP2_ERR_RECV_VERSION_NEGOTIATION` indicates that Version * Negotiation packet was received. */ -#define NGTCP2_ERR_RECV_VERSION_NEGOTIATION -229 +#define NGTCP2_ERR_RECV_VERSION_NEGOTIATION -222 /** * @macro * * :macro:`NGTCP2_ERR_CLOSING` indicates that connection is in closing * state. */ -#define NGTCP2_ERR_CLOSING -230 +#define NGTCP2_ERR_CLOSING -223 /** * @macro * * :macro:`NGTCP2_ERR_DRAINING` indicates that connection is in * draining state. */ -#define NGTCP2_ERR_DRAINING -231 +#define NGTCP2_ERR_DRAINING -224 /** * @macro * * :macro:`NGTCP2_ERR_TRANSPORT_PARAM` indicates a general transport * parameter error. */ -#define NGTCP2_ERR_TRANSPORT_PARAM -234 +#define NGTCP2_ERR_TRANSPORT_PARAM -225 /** * @macro * * :macro:`NGTCP2_ERR_DISCARD_PKT` indicates a packet was discarded. */ -#define NGTCP2_ERR_DISCARD_PKT -235 +#define NGTCP2_ERR_DISCARD_PKT -226 /** * @macro * * :macro:`NGTCP2_ERR_CONN_ID_BLOCKED` indicates that there is no * spare Connection ID available. */ -#define NGTCP2_ERR_CONN_ID_BLOCKED -237 +#define NGTCP2_ERR_CONN_ID_BLOCKED -227 /** * @macro * * :macro:`NGTCP2_ERR_INTERNAL` indicates an internal error. */ -#define NGTCP2_ERR_INTERNAL -238 +#define NGTCP2_ERR_INTERNAL -228 /** * @macro * * :macro:`NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED` indicates that a crypto * buffer exceeded. */ -#define NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED -239 +#define NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED -229 /** * @macro * @@ -753,21 +694,21 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` is used and a function call * succeeded. */ -#define NGTCP2_ERR_WRITE_MORE -240 +#define NGTCP2_ERR_WRITE_MORE -230 /** * @macro * * :macro:`NGTCP2_ERR_RETRY` indicates that server should send Retry * packet. */ -#define NGTCP2_ERR_RETRY -241 +#define NGTCP2_ERR_RETRY -231 /** * @macro * * :macro:`NGTCP2_ERR_DROP_CONN` indicates that an endpoint should * drop connection immediately. */ -#define NGTCP2_ERR_DROP_CONN -242 +#define NGTCP2_ERR_DROP_CONN -232 /** * @macro * @@ -775,7 +716,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * limit is reached and key update is not available. An endpoint * should drop connection immediately. */ -#define NGTCP2_ERR_AEAD_LIMIT_REACHED -243 +#define NGTCP2_ERR_AEAD_LIMIT_REACHED -233 /** * @macro * @@ -783,41 +724,41 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * could not probe that a path is capable of sending UDP datagram * payload of size at least 1200 bytes. */ -#define NGTCP2_ERR_NO_VIABLE_PATH -244 +#define NGTCP2_ERR_NO_VIABLE_PATH -234 /** * @macro * * :macro:`NGTCP2_ERR_VERSION_NEGOTIATION` indicates that server * should send Version Negotiation packet. */ -#define NGTCP2_ERR_VERSION_NEGOTIATION -245 +#define NGTCP2_ERR_VERSION_NEGOTIATION -235 /** * @macro * * :macro:`NGTCP2_ERR_HANDSHAKE_TIMEOUT` indicates that QUIC * connection is not established before the specified deadline. */ -#define NGTCP2_ERR_HANDSHAKE_TIMEOUT -246 +#define NGTCP2_ERR_HANDSHAKE_TIMEOUT -236 /** * @macro * * :macro:`NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE` indicates the * version negotiation failed. */ -#define NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE -247 +#define NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE -237 /** * @macro * * :macro:`NGTCP2_ERR_IDLE_CLOSE` indicates the connection should be * closed silently because of idle timeout. */ -#define NGTCP2_ERR_IDLE_CLOSE -248 +#define NGTCP2_ERR_IDLE_CLOSE -238 /** * @macro * * :macro:`NGTCP2_ERR_FATAL` indicates that error codes less than this * value is fatal error. When this error is returned, an endpoint - * should drop connection immediately. + * should close connection immediately. */ #define NGTCP2_ERR_FATAL -500 /** @@ -892,7 +833,7 @@ typedef enum ngtcp2_pkt_type { */ NGTCP2_PKT_INITIAL = 0x10, /** - * :enum:`NGTCP2_PKT_0RTT` indicates 0RTT packet. + * :enum:`NGTCP2_PKT_0RTT` indicates 0-RTT packet. */ NGTCP2_PKT_0RTT = 0x11, /** @@ -1061,12 +1002,10 @@ typedef enum ngtcp2_pkt_type { /** * @macro * - * :macro:`NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT` is QUIC transport - * error code ``VERSION_NEGOTIATION_ERROR``. - * - * https://quicwg.org/quic-v2/draft-ietf-quic-v2.html + * :macro:`NGTCP2_VERSION_NEGOTIATION_ERROR` is QUIC transport error + * code ``VERSION_NEGOTIATION_ERROR``. See :rfc:`9368`. */ -#define NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT 0x53f8u +#define NGTCP2_VERSION_NEGOTIATION_ERROR 0x11 /** * @enum @@ -1096,6 +1035,8 @@ typedef enum ngtcp2_path_validation_result { * @typedef * * :type:`ngtcp2_tstamp` is a timestamp with nanosecond resolution. + * ``UINT64_MAX`` is an invalid value, and it is often used to + * indicate that no value is set. */ typedef uint64_t ngtcp2_tstamp; @@ -1103,7 +1044,8 @@ typedef uint64_t ngtcp2_tstamp; * @typedef * * :type:`ngtcp2_duration` is a period of time in nanosecond - * resolution. + * resolution. ``UINT64_MAX`` is an invalid value, and it is often + * used to indicate that no value is set. */ typedef uint64_t ngtcp2_duration; @@ -1178,10 +1120,15 @@ typedef struct ngtcp2_pkt_hd { */ int64_t pkt_num; /** - * :member:`token` contains token for Initial - * packet. + * :member:`token` contains token. Only Initial packet may contain + * token. NULL if no token is present. */ - ngtcp2_vec token; + const uint8_t *token; + /** + * :member:`tokenlen` is the length of :member:`token`. 0 if no + * token is present. + */ + size_t tokenlen; /** * :member:`pkt_numlen` is the number of bytes spent to encode * :member:`pkt_num`. @@ -1197,8 +1144,10 @@ typedef struct ngtcp2_pkt_hd { */ uint32_t version; /** - * :member:`type` is a type of QUIC packet. See - * :type:`ngtcp2_pkt_type`. + * :member:`type` is a type of QUIC packet. This field does not + * have a QUIC packet type defined for a specific QUIC version. + * Instead, it contains version independent packet type defined by + * this library. See :type:`ngtcp2_pkt_type`. */ uint8_t type; /** @@ -1229,25 +1178,6 @@ typedef struct ngtcp2_pkt_stateless_reset { size_t randlen; } ngtcp2_pkt_stateless_reset; -/** - * @enum - * - * :type:`ngtcp2_transport_params_type` defines TLS message type which - * carries transport parameters. - */ -typedef enum ngtcp2_transport_params_type { - /** - * :enum:`NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO` is Client Hello - * TLS message. - */ - NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, - /** - * :enum:`NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS` is - * Encrypted Extensions TLS message. - */ - NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS -} ngtcp2_transport_params_type; - /** * @macrosection * @@ -1296,14 +1226,96 @@ typedef enum ngtcp2_transport_params_type { */ #define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39u +#ifdef NGTCP2_USE_GENERIC_SOCKADDR +# ifndef NGTCP2_AF_INET +# error NGTCP2_AF_INET must be defined +# endif /* !NGTCP2_AF_INET */ + +# ifndef NGTCP2_AF_INET6 +# error NGTCP2_AF_INET6 must be defined +# endif /* !NGTCP2_AF_INET6 */ + +typedef unsigned short int ngtcp2_sa_family; +typedef uint16_t ngtcp2_in_port; + +typedef struct ngtcp2_sockaddr { + ngtcp2_sa_family sa_family; + uint8_t sa_data[14]; +} ngtcp2_sockaddr; + +typedef struct ngtcp2_in_addr { + uint32_t s_addr; +} ngtcp2_in_addr; + +typedef struct ngtcp2_sockaddr_in { + ngtcp2_sa_family sin_family; + ngtcp2_in_port sin_port; + ngtcp2_in_addr sin_addr; + uint8_t sin_zero[8]; +} ngtcp2_sockaddr_in; + +typedef struct ngtcp2_in6_addr { + uint8_t in6_addr[16]; +} ngtcp2_in6_addr; + +typedef struct ngtcp2_sockaddr_in6 { + ngtcp2_sa_family sin6_family; + ngtcp2_in_port sin6_port; + uint32_t sin6_flowinfo; + ngtcp2_in6_addr sin6_addr; + uint32_t sin6_scope_id; +} ngtcp2_sockaddr_in6; + +typedef uint32_t ngtcp2_socklen; +#else /* !NGTCP2_USE_GENERIC_SOCKADDR */ +# define NGTCP2_AF_INET AF_INET +# define NGTCP2_AF_INET6 AF_INET6 + /** - * @macro + * @typedef + * + * :type:`ngtcp2_sockaddr` is typedefed to struct sockaddr. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * the generic struct sockaddr defined in ngtcp2.h. + */ +typedef struct sockaddr ngtcp2_sockaddr; +/** + * @typedef + * + * :type:`ngtcp2_sockaddr_in` is typedefed to struct sockaddr_in. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * the generic struct sockaddr_in defined in ngtcp2.h. + */ +typedef struct sockaddr_in ngtcp2_sockaddr_in; +/** + * @typedef + * + * :type:`ngtcp2_sockaddr_in6` is typedefed to struct sockaddr_in6. + * If :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed + * to the generic struct sockaddr_in6 defined in ngtcp2.h. + */ +typedef struct sockaddr_in6 ngtcp2_sockaddr_in6; +/** + * @typedef + * + * :type:`ngtcp2_socklen` is typedefed to socklen_t. If + * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to + * uint32_t. + */ +typedef socklen_t ngtcp2_socklen; +#endif /* !NGTCP2_USE_GENERIC_SOCKADDR */ + +/** + * @struct * - * :macro:`NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_DRAFT` is TLS - * extension type of quic_transport_parameters used during draft - * development. + * :type:`ngtcp2_sockaddr_union` conveniently includes all supported + * address types. */ -#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_DRAFT 0xffa5u +typedef union ngtcp2_sockaddr_union { + ngtcp2_sockaddr sa; + ngtcp2_sockaddr_in in; + ngtcp2_sockaddr_in6 in6; +} ngtcp2_sockaddr_union; /** * @struct @@ -1317,29 +1329,21 @@ typedef struct ngtcp2_preferred_addr { */ ngtcp2_cid cid; /** - * :member:`ipv4_port` is a port of IPv4 address. + * :member:`ipv4` contains IPv4 address and port. */ - uint16_t ipv4_port; + ngtcp2_sockaddr_in ipv4; /** - * :member:`ipv6_port` is a port of IPv6 address. + * :member:`ipv6` contains IPv6 address and port. */ - uint16_t ipv6_port; + ngtcp2_sockaddr_in6 ipv6; /** - * :member:`ipv4_addr` contains IPv4 address in network byte order. - */ - uint8_t ipv4_addr[4]; - /** - * :member:`ipv6_addr` contains IPv6 address in network byte order. - */ - uint8_t ipv6_addr[16]; - /** - * :member:`ipv4_present` indicates that :member:`ipv4_addr` and - * :member:`ipv4_port` contain IPv4 address and port respectively. + * :member:`ipv4_present` indicates that :member:`ipv4` contains + * IPv4 address and port. */ uint8_t ipv4_present; /** - * :member:`ipv6_present` indicates that :member:`ipv6_addr` and - * :member:`ipv6_port` contain IPv6 address and port respectively. + * :member:`ipv6_present` indicates that :member:`ipv6` contains + * IPv6 address and port. */ uint8_t ipv6_present; /** @@ -1352,7 +1356,7 @@ typedef struct ngtcp2_preferred_addr { * @struct * * :type:`ngtcp2_version_info` represents version_information - * structure. + * structure. See :rfc:`9368`. */ typedef struct ngtcp2_version_info { /** @@ -1360,19 +1364,21 @@ typedef struct ngtcp2_version_info { */ uint32_t chosen_version; /** - * :member:`other_versions` points the wire image of other_versions - * field. The each version is therefore in network byte order. + * :member:`available_versions` points the wire image of + * available_versions field. The each version is therefore in + * network byte order. */ - uint8_t *other_versions; + const uint8_t *available_versions; /** - * :member:`other_versionslen` is the number of bytes pointed by - * :member:`other_versions`, not the number of versions included. + * :member:`available_versionslen` is the number of bytes pointed by + * :member:`available_versions`, not the number of versions + * included. */ - size_t other_versionslen; + size_t available_versionslen; } ngtcp2_version_info; -#define NGTCP2_TRANSPORT_PARAMS_VERSION_V1 1 -#define NGTCP2_TRANSPORT_PARAMS_VERSION NGTCP2_TRANSPORT_PARAMS_VERSION_V1 +#define NGTCP2_TRANSPORT_PARAMS_V1 1 +#define NGTCP2_TRANSPORT_PARAMS_VERSION NGTCP2_TRANSPORT_PARAMS_V1 /** * @struct @@ -1382,55 +1388,58 @@ typedef struct ngtcp2_version_info { */ typedef struct ngtcp2_transport_params { /** - * :member:`preferred_address` contains preferred address if - * :member:`preferred_address_present` is nonzero. + * :member:`preferred_addr` contains preferred address if + * :member:`preferred_addr_present` is nonzero. */ - ngtcp2_preferred_addr preferred_address; + ngtcp2_preferred_addr preferred_addr; /** * :member:`original_dcid` is the Destination Connection ID field * from the first Initial packet from client. Server must specify - * this field. It is expected that application knows the original - * Destination Connection ID even if it sends Retry packet, for - * example, by including it in retry token. Otherwise, application - * should not specify this field. + * this field and set :member:`original_dcid_present` to nonzero. + * It is expected that application knows the original Destination + * Connection ID even if it sends Retry packet, for example, by + * including it in retry token. Otherwise, application should not + * specify this field. */ ngtcp2_cid original_dcid; /** * :member:`initial_scid` is the Source Connection ID field from the - * first Initial packet the endpoint sends. Application should not - * specify this field. + * first Initial packet the local endpoint sends. Application + * should not specify this field. If :member:`initial_scid_present` + * is set to nonzero, it indicates this field is set. */ ngtcp2_cid initial_scid; /** * :member:`retry_scid` is the Source Connection ID field from Retry * packet. Only server uses this field. If server application - * received Initial packet with retry token from client and server - * verified its token, server application must set Destination - * Connection ID field from the Initial packet to this field and set - * :member:`retry_scid_present` to nonzero. Server application must - * verify that the Destination Connection ID from Initial packet was - * sent in Retry packet by, for example, including the Connection ID - * in a token, or including it in AAD when encrypting a token. + * received Initial packet with retry token from client, and server + * successfully verified its token, server application must set + * Destination Connection ID field from the Initial packet to this + * field, and set :member:`retry_scid_present` to nonzero. Server + * application must verify that the Destination Connection ID from + * Initial packet was sent in Retry packet by, for example, + * including the Connection ID in a token, or including it in AAD + * when encrypting a token. */ ngtcp2_cid retry_scid; /** * :member:`initial_max_stream_data_bidi_local` is the size of flow * control window of locally initiated stream. This is the number - * of bytes that the remote endpoint can send and the local endpoint - * must ensure that it has enough buffer to receive them. + * of bytes that the remote endpoint can send, and the local + * endpoint must ensure that it has enough buffer to receive them. */ uint64_t initial_max_stream_data_bidi_local; /** * :member:`initial_max_stream_data_bidi_remote` is the size of flow * control window of remotely initiated stream. This is the number - * of bytes that the remote endpoint can send and the local endpoint - * must ensure that it has enough buffer to receive them. + * of bytes that the remote endpoint can send, and the local + * endpoint must ensure that it has enough buffer to receive them. */ uint64_t initial_max_stream_data_bidi_remote; /** * :member:`initial_max_stream_data_uni` is the size of flow control * window of remotely initiated unidirectional stream. This is the - * number of bytes that the remote endpoint can send and the local + * number of bytes that the remote endpoint can send, and the local * endpoint must ensure that it has enough buffer to receive them. */ uint64_t initial_max_stream_data_uni; @@ -1451,12 +1460,13 @@ typedef struct ngtcp2_transport_params { uint64_t initial_max_streams_uni; /** * :member:`max_idle_timeout` is a duration during which sender - * allows quiescent. + * allows quiescent. 0 means no idle timeout. It must not be + * UINT64_MAX. */ ngtcp2_duration max_idle_timeout; /** - * :member:`max_udp_payload_size` is the maximum datagram size that - * the endpoint can receive. + * :member:`max_udp_payload_size` is the maximum UDP payload size + * that the local endpoint can receive. */ uint64_t max_udp_payload_size; /** @@ -1471,14 +1481,16 @@ typedef struct ngtcp2_transport_params { uint64_t ack_delay_exponent; /** * :member:`max_ack_delay` is the maximum acknowledgement delay by - * which the endpoint will delay sending acknowledgements. + * which the local endpoint will delay sending acknowledgements. It + * must be strictly less than (1 << 14) milliseconds. + * Sub-millisecond part is dropped when sending it in a QUIC + * transport parameter. */ ngtcp2_duration max_ack_delay; /** * :member:`max_datagram_frame_size` is the maximum size of DATAGRAM - * frame that this endpoint willingly receives. Specifying 0 - * disables DATAGRAM support. See - * https://datatracker.ietf.org/doc/html/rfc9221 + * frame that the local endpoint willingly receives. Specifying 0 + * disables DATAGRAM support. See :rfc:`9221`. */ uint64_t max_datagram_frame_size; /** @@ -1487,30 +1499,37 @@ typedef struct ngtcp2_transport_params { */ uint8_t stateless_reset_token_present; /** - * :member:`disable_active_migration` is nonzero if the endpoint - * does not support active connection migration. + * :member:`disable_active_migration` is nonzero if the local + * endpoint does not support active connection migration. */ uint8_t disable_active_migration; + /** + * :member:`original_dcid_present` is nonzero if + * :member:`original_dcid` field is set. + */ + uint8_t original_dcid_present; + /** + * :member:`initial_scid_present` is nonzero if + * :member:`initial_scid` field is set. + */ + uint8_t initial_scid_present; /** * :member:`retry_scid_present` is nonzero if :member:`retry_scid` * field is set. */ uint8_t retry_scid_present; /** - * :member:`preferred_address_present` is nonzero if + * :member:`preferred_addr_present` is nonzero if * :member:`preferred_address` is set. */ - uint8_t preferred_address_present; + uint8_t preferred_addr_present; /** * :member:`stateless_reset_token` contains stateless reset token. */ uint8_t stateless_reset_token[NGTCP2_STATELESS_RESET_TOKENLEN]; /** * :member:`grease_quic_bit` is nonzero if sender supports "Greasing - * the QUIC Bit" extension. See - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-bit-grease. - * Note that the local endpoint always enables greasing QUIC bit - * regardless of this field value. + * the QUIC Bit" extension. See :rfc:`9287`. */ uint8_t grease_quic_bit; /** @@ -1527,44 +1546,15 @@ typedef struct ngtcp2_transport_params { uint8_t version_info_present; } ngtcp2_transport_params; -/** - * @enum - * - * :type:`ngtcp2_pktns_id` defines packet number space identifier. - */ -typedef enum ngtcp2_pktns_id { - /** - * :enum:`NGTCP2_PKTNS_ID_INITIAL` is the Initial packet number - * space. - */ - NGTCP2_PKTNS_ID_INITIAL, - /** - * :enum:`NGTCP2_PKTNS_ID_HANDSHAKE` is the Handshake packet number - * space. - */ - NGTCP2_PKTNS_ID_HANDSHAKE, - /** - * :enum:`NGTCP2_PKTNS_ID_APPLICATION` is the Application data - * packet number space. - */ - NGTCP2_PKTNS_ID_APPLICATION, - /** - * :enum:`NGTCP2_PKTNS_ID_MAX` is defined to get the number of - * packet number spaces. - */ - NGTCP2_PKTNS_ID_MAX -} ngtcp2_pktns_id; - -#define NGTCP2_CONN_STAT_VERSION_V1 1 -#define NGTCP2_CONN_STAT_VERSION NGTCP2_CONN_STAT_VERSION_V1 +#define NGTCP2_CONN_INFO_V1 1 +#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V1 /** * @struct * - * :type:`ngtcp2_conn_stat` holds various connection statistics, and - * computed data for recovery and congestion controller. + * :type:`ngtcp2_conn_info` holds various connection statistics. */ -typedef struct ngtcp2_conn_stat { +typedef struct ngtcp2_conn_info { /** * :member:`latest_rtt` is the latest RTT sample which is not * adjusted by acknowledgement delay. @@ -1583,35 +1573,6 @@ typedef struct ngtcp2_conn_stat { * :member:`rttvar` is a mean deviation of observed RTT. */ ngtcp2_duration rttvar; - /** - * :member:`initial_rtt` is the initial RTT which is used when no - * RTT sample is available. - */ - ngtcp2_duration initial_rtt; - /** - * :member:`first_rtt_sample_ts` is the timestamp when the first RTT - * sample is obtained. - */ - ngtcp2_tstamp first_rtt_sample_ts; - /** - * :member:`pto_count` is the count of successive PTO timer - * expiration. - */ - size_t pto_count; - /** - * :member:`loss_detection_timer` is the deadline of the current - * loss detection timer. - */ - ngtcp2_tstamp loss_detection_timer; - /** - * :member:`last_tx_pkt_ts` corresponds to - * time_of_last_ack_eliciting_packet in :rfc:`9002`. - */ - ngtcp2_tstamp last_tx_pkt_ts[NGTCP2_PKTNS_ID_MAX]; - /** - * :member:`loss_time` corresponds to loss_time in :rfc:`9002`. - */ - ngtcp2_tstamp loss_time[NGTCP2_PKTNS_ID_MAX]; /** * :member:`cwnd` is the size of congestion window. */ @@ -1620,38 +1581,12 @@ typedef struct ngtcp2_conn_stat { * :member:`ssthresh` is slow start threshold. */ uint64_t ssthresh; - /** - * :member:`congestion_recovery_start_ts` is the timestamp when - * congestion recovery started. - */ - ngtcp2_tstamp congestion_recovery_start_ts; /** * :member:`bytes_in_flight` is the number in bytes of all sent * packets which have not been acknowledged. */ uint64_t bytes_in_flight; - /** - * :member:`max_udp_payload_size` is the maximum size of UDP - * datagram payload that this endpoint transmits. It is used by - * congestion controller to compute congestion window. - */ - size_t max_udp_payload_size; - /** - * :member:`delivery_rate_sec` is the current sending rate measured - * in byte per second. - */ - uint64_t delivery_rate_sec; - /** - * :member:`pacing_rate` is the current packet sending rate. If - * pacing is disabled, 0 is set. - */ - double pacing_rate; - /** - * :member:`send_quantum` is the maximum size of a data aggregate - * scheduled and transmitted together. - */ - size_t send_quantum; -} ngtcp2_conn_stat; +} ngtcp2_conn_info; /** * @enum @@ -1668,15 +1603,9 @@ typedef enum ngtcp2_cc_algo { */ NGTCP2_CC_ALGO_CUBIC = 0x01, /** - * :enum:`NGTCP2_CC_ALGO_BBR` represents BBR. If BBR is chosen, - * packet pacing is enabled. + * :enum:`NGTCP2_CC_ALGO_BBR` represents BBR v2. */ - NGTCP2_CC_ALGO_BBR = 0x02, - /** - * :enum:`NGTCP2_CC_ALGO_BBR2` represents BBR v2. If BBR v2 is - * chosen, packet pacing is enabled. - */ - NGTCP2_CC_ALGO_BBR2 = 0x03 + NGTCP2_CC_ALGO_BBR = 0x02 } ngtcp2_cc_algo; /** @@ -1737,27 +1666,30 @@ typedef void (*ngtcp2_qlog_write)(void *user_data, uint32_t flags, const void *data, size_t datalen); /** - * @struct + * @enum * - * :type:`ngtcp2_qlog_settings` is a set of settings for qlog. + * :type:`ngtcp2_token_type` defines the type of token. */ -typedef struct ngtcp2_qlog_settings { +typedef enum ngtcp2_token_type { /** - * :member:`odcid` is Original Destination Connection ID sent by - * client. It is used as group_id and ODCID fields. Client ignores - * this field and uses dcid parameter passed to - * `ngtcp2_conn_client_new()`. + * :enum:`NGTCP2_TOKEN_TYPE_UNKNOWN` indicates that the type of + * token is unknown. */ - ngtcp2_cid odcid; + NGTCP2_TOKEN_TYPE_UNKNOWN, /** - * :member:`write` is a callback function to write qlog. Setting - * ``NULL`` disables qlog. + * :enum:`NGTCP2_TOKEN_TYPE_RETRY` indicates that a token comes from + * Retry packet. */ - ngtcp2_qlog_write write; -} ngtcp2_qlog_settings; + NGTCP2_TOKEN_TYPE_RETRY, + /** + * :enum:`NGTCP2_TOKEN_TYPE_NEW_TOKEN` indicates that a token comes + * from NEW_TOKEN frame. + */ + NGTCP2_TOKEN_TYPE_NEW_TOKEN +} ngtcp2_token_type; -#define NGTCP2_SETTINGS_VERSION_V1 1 -#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_VERSION_V1 +#define NGTCP2_SETTINGS_V1 1 +#define NGTCP2_SETTINGS_VERSION NGTCP2_SETTINGS_V1 /** * @struct @@ -1766,9 +1698,10 @@ typedef struct ngtcp2_qlog_settings { */ typedef struct ngtcp2_settings { /** - * :member:`qlog` is qlog settings. + * :member:`qlog_write` is a callback function to write qlog. + * Setting ``NULL`` disables qlog. */ - ngtcp2_qlog_settings qlog; + ngtcp2_qlog_write qlog_write; /** * :member:`cc_algo` specifies congestion control algorithm. */ @@ -1789,24 +1722,37 @@ typedef struct ngtcp2_settings { */ ngtcp2_printf log_printf; /** - * :member:`max_udp_payload_size` is the maximum size of UDP - * datagram payload that this endpoint transmits. It is used by - * congestion controller to compute congestion window. + * :member:`max_tx_udp_payload_size` is the maximum size of UDP + * datagram payload that the local endpoint transmits. It is used + * by congestion controller to compute congestion window. */ - size_t max_udp_payload_size; + size_t max_tx_udp_payload_size; /** * :member:`token` is a token from Retry packet or NEW_TOKEN frame. * * Server sets this field if it received the token in Client Initial - * packet and successfully validated. + * packet and successfully validated. It should also set + * :member:`token_type` field. * * Client sets this field if it intends to send token in its Initial * packet. * * `ngtcp2_conn_server_new` and `ngtcp2_conn_client_new` make a copy * of token. + * + * Set NULL if there is no token. */ - ngtcp2_vec token; + const uint8_t *token; + /** + * :member:`tokenlen` is the length of :member:`token`. Set 0 if + * there is no token. + */ + size_t tokenlen; + /** + * :member:`token_type` is the type of token. Server application + * should set this field. + */ + ngtcp2_token_type token_type; /** * :member:`rand_ctx` is an optional random number generator to be * passed to :type:`ngtcp2_rand` callback. @@ -1834,20 +1780,20 @@ typedef struct ngtcp2_settings { */ uint64_t max_stream_window; /** - * :member:`ack_thresh` is the maximum number of unacknowledged - * packets before sending acknowledgement. It triggers the - * immediate acknowledgement. + * :member:`ack_thresh` is the minimum number of the received ACK + * eliciting packets that trigger the immediate acknowledgement from + * the local endpoint. */ size_t ack_thresh; /** - * :member:`no_udp_payload_size_shaping`, if set to nonzero, + * :member:`no_tx_udp_payload_size_shaping`, if set to nonzero, * instructs the library not to limit the UDP payload size to * :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE` (which can be extended by - * Path MTU Discovery) and instead use the mininum size among the - * given buffer size, :member:`max_udp_payload_size`, and the - * received max_udp_payload QUIC transport parameter. + * Path MTU Discovery), and instead use the minimum size among the + * given buffer size, :member:`max_tx_udp_payload_size`, and the + * received max_udp_payload_size QUIC transport parameter. */ - int no_udp_payload_size_shaping; + uint8_t no_tx_udp_payload_size_shaping; /** * :member:`handshake_timeout` is the period of time before giving * up QUIC connection establishment. If QUIC handshake is not @@ -1865,10 +1811,13 @@ typedef struct ngtcp2_settings { * of preference. * * On compatible version negotiation, server will negotiate one of - * those versions contained in this array if a client initially - * chooses a less preferred version. This version set corresponds - * to Offered Versions in QUIC Version Negotiation draft, and it should - * be sent in Version Negotiation packet. + * those versions contained in this array if there is some overlap + * between these versions and the versions offered by the client. + * If there is no overlap, but the client chosen version is + * supported by the library, the server chooses the client chosen + * version as the negotiated version. This version set corresponds + * to Offered Versions described in :rfc:`9368`, and it should be + * included in Version Negotiation packet. * * Client uses this field and :member:`original_version` to prevent * version downgrade attack if it reacted upon Version Negotiation @@ -1876,7 +1825,7 @@ typedef struct ngtcp2_settings { * |client_chosen_version| passed to `ngtcp2_conn_client_new` unless * |client_chosen_version| is a reserved version. */ - uint32_t *preferred_versions; + const uint32_t *preferred_versions; /** * :member:`preferred_versionslen` is the number of versions that * are contained in the array pointed by @@ -1884,13 +1833,14 @@ typedef struct ngtcp2_settings { */ size_t preferred_versionslen; /** - * :member:`other_versions` is the array of versions that are set in - * :member:`other_versions ` - * field of outgoing version_information QUIC transport parameter. + * :member:`available_versions` is the array of versions that are + * going to be set in :member:`available_versions + * ` field of outgoing + * version_information QUIC transport parameter. * - * For server, this corresponds to Fully-Deployed Versions in QUIC - * Version Negotiation draft. If this field is set not, it is set - * to :member:`preferred_versions` internally if + * For server, this corresponds to Fully-Deployed Versions described + * in :rfc:`9368`. If this field is not set, it is set to + * :member:`preferred_versions` internally if * :member:`preferred_versionslen` is not zero. If this field is * not set, and :member:`preferred_versionslen` is zero, this field * is set to :macro:`NGTCP2_PROTO_VER_V1` internally. @@ -1902,12 +1852,13 @@ typedef struct ngtcp2_settings { * `ngtcp2_conn_client_new` will be set in this field internally * unless |client_chosen_version| is a reserved version. */ - uint32_t *other_versions; + const uint32_t *available_versions; /** - * :member:`other_versionslen` is the number of versions that are - * contained in the array pointed by :member:`other_versions`. + * :member:`available_versionslen` is the number of versions that + * are contained in the array pointed by + * :member:`available_versions`. */ - size_t other_versionslen; + size_t available_versionslen; /** * :member:`original_version` is the original version that client * initially used to make a connection attempt. If it is set, and @@ -1920,92 +1871,14 @@ typedef struct ngtcp2_settings { * :member:`no_pmtud`, if set to nonzero, disables Path MTU * Discovery. */ - int no_pmtud; + uint8_t no_pmtud; + /** + * :member:`pkt_num` is the initial packet number for each packet + * number space. It must be in range [0, INT32_MAX], inclusive. + */ + uint32_t initial_pkt_num; } ngtcp2_settings; -#ifdef NGTCP2_USE_GENERIC_SOCKADDR -typedef struct ngtcp2_sockaddr { - uint16_t sa_family; - uint8_t sa_data[14]; -} ngtcp2_sockaddr; - -typedef struct ngtcp2_in_addr { - uint32_t s_addr; -} ngtcp2_in_addr; - -typedef struct ngtcp2_sockaddr_in { - uint16_t sin_family; - uint16_t sin_port; - ngtcp2_in_addr sin_addr; - uint8_t sin_zero[8]; -} ngtcp2_sockaddr_in; - -# define NGTCP2_SS_MAXSIZE 128 -# define NGTCP2_SS_ALIGNSIZE (sizeof(uint64_t)) -# define NGTCP2_SS_PAD1SIZE (NGTCP2_SS_ALIGNSIZE - sizeof(uint16_t)) -# define NGTCP2_SS_PAD2SIZE \ - (NGTCP2_SS_MAXSIZE - \ - (sizeof(uint16_t) + NGTCP2_SS_PAD1SIZE + NGTCP2_SS_ALIGNSIZE)) - -typedef struct ngtcp2_sockaddr_storage { - uint16_t ss_family; - uint8_t _ss_pad1[NGTCP2_SS_PAD1SIZE]; - uint64_t _ss_align; - uint8_t _ss_pad2[NGTCP2_SS_PAD2SIZE]; -} ngtcp2_sockaddr_storage; - -# undef NGTCP2_SS_PAD2SIZE -# undef NGTCP2_SS_PAD1SIZE -# undef NGTCP2_SS_ALIGNSIZE -# undef NGTCP2_SS_MAXSIZE - -typedef uint32_t ngtcp2_socklen; -#else -/** - * @typedef - * - * :type:`ngtcp2_sockaddr` is typedefed to struct sockaddr. If - * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to - * the generic struct sockaddr defined in ngtcp2.h. - */ -typedef struct sockaddr ngtcp2_sockaddr; -/** - * @typedef - * - * :type:`ngtcp2_sockaddr_storage` is typedefed to struct - * sockaddr_storage. If :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is - * defined, it is typedefed to the generic struct sockaddr_storage - * defined in ngtcp2.h. - */ -typedef struct sockaddr_storage ngtcp2_sockaddr_storage; -typedef struct sockaddr_in ngtcp2_sockaddr_in; -/** - * @typedef - * - * :type:`ngtcp2_socklen` is typedefed to socklen_t. If - * :macro:`NGTCP2_USE_GENERIC_SOCKADDR` is defined, it is typedefed to - * uint32_t. - */ -typedef socklen_t ngtcp2_socklen; -#endif - -#if defined(NGTCP2_USE_GENERIC_SOCKADDR) || \ - defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR) -typedef struct ngtcp2_in6_addr { - uint8_t in6_addr[16]; -} ngtcp2_in6_addr; - -typedef struct ngtcp2_sockaddr_in6 { - uint16_t sin6_family; - uint16_t sin6_port; - uint32_t sin6_flowinfo; - ngtcp2_in6_addr sin6_addr; - uint32_t sin6_scope_id; -} ngtcp2_sockaddr_in6; -#else -typedef struct sockaddr_in6 ngtcp2_sockaddr_in6; -#endif - /** * @struct * @@ -2018,7 +1891,8 @@ typedef struct ngtcp2_addr { */ ngtcp2_sockaddr *addr; /** - * :member:`addrlen` is the length of addr. + * :member:`addrlen` is the length of :member:`addr`. It must not + * be longer than sizeof(:type:`ngtcp2_sockaddr_union`). */ ngtcp2_socklen addrlen; } ngtcp2_addr; @@ -2045,7 +1919,7 @@ typedef struct ngtcp2_path { * Note that :type:`ngtcp2_path` is generally passed to * :type:`ngtcp2_conn` by an application, and :type:`ngtcp2_conn` * stores their copies. Unfortunately, there is no way for the - * application to know when :type:`ngtcp2_conn` finishes using a + * application to know when :type:`ngtcp2_conn` finished using a * specific :type:`ngtcp2_path` object in mid connection, which * means that the application cannot free the data pointed by this * field. Therefore, it is advised to use this field only when the @@ -2069,11 +1943,11 @@ typedef struct ngtcp2_path_storage { /** * :member:`local_addrbuf` is a buffer to store local address. */ - ngtcp2_sockaddr_storage local_addrbuf; + ngtcp2_sockaddr_union local_addrbuf; /** * :member:`remote_addrbuf` is a buffer to store remote address. */ - ngtcp2_sockaddr_storage remote_addrbuf; + ngtcp2_sockaddr_union remote_addrbuf; } ngtcp2_path_storage; /** @@ -2160,8 +2034,9 @@ typedef struct ngtcp2_crypto_cipher_ctx { * :type:`ngtcp2_crypto_ctx` is a convenient structure to bind all * crypto related objects in one place. Use * `ngtcp2_crypto_ctx_initial` to initialize this struct for Initial - * packet encryption. For Handshake and 1RTT packets, use - * `ngtcp2_crypto_ctx_tls`. + * packet encryption. For Handshake and 1-RTT packets, use + * `ngtcp2_crypto_ctx_tls`. For 0-RTT packets, use + * `ngtcp2_crypto_ctx_tls_early`. */ typedef struct ngtcp2_crypto_ctx { /** @@ -2191,60 +2066,56 @@ typedef struct ngtcp2_crypto_ctx { /** * @function * - * `ngtcp2_encode_transport_params` encodes |params| in |dest| of + * `ngtcp2_transport_params_encode` encodes |params| in |dest| of * length |destlen|. * * If |dest| is NULL, and |destlen| is zero, this function just * returns the number of bytes required to store the encoded transport * parameters. * - * This function returns the number of written, or one of the + * This function returns the number of bytes written, or one of the * following negative error codes: * * :macro:`NGTCP2_ERR_NOBUF` * Buffer is too small. - * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` - * |exttype| is invalid. */ -NGTCP2_EXTERN ngtcp2_ssize ngtcp2_encode_transport_params_versioned( - uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype, - int transport_params_version, const ngtcp2_transport_params *params); +NGTCP2_EXTERN ngtcp2_ssize ngtcp2_transport_params_encode_versioned( + uint8_t *dest, size_t destlen, int transport_params_version, + const ngtcp2_transport_params *params); /** * @function * - * `ngtcp2_decode_transport_params` decodes transport parameters in + * `ngtcp2_transport_params_decode` decodes transport parameters in * |data| of length |datalen|, and stores the result in the object * pointed by |params|. * - * If the optional parameters are missing, the default value is - * assigned. + * If an optional parameter is missing, the default value is assigned. * * The following fields may point to somewhere inside the buffer * pointed by |data| of length |datalen|: * - * - :member:`ngtcp2_transport_params.version_info.other_versions - * ` + * - :member:`ngtcp2_transport_params.version_info.available_versions + * ` * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM` - * The required parameter is missing. * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` * The input is malformed. */ -NGTCP2_EXTERN int ngtcp2_decode_transport_params_versioned( - int transport_params_version, ngtcp2_transport_params *params, - ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen); +NGTCP2_EXTERN int +ngtcp2_transport_params_decode_versioned(int transport_params_version, + ngtcp2_transport_params *params, + const uint8_t *data, size_t datalen); /** * @function * - * `ngtcp2_decode_transport_params_new` decodes transport parameters + * `ngtcp2_transport_params_decode_new` decodes transport parameters * in |data| of length |datalen|, and stores the result in the object * allocated dynamically. The pointer to the allocated object is - * assigned to |*pparams|. Unlike `ngtcp2_decode_transport_params`, + * assigned to |*pparams|. Unlike `ngtcp2_transport_params_decode`, * all direct and indirect fields are also allocated dynamically if * needed. * @@ -2261,22 +2132,21 @@ NGTCP2_EXTERN int ngtcp2_decode_transport_params_versioned( * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM` - * The required parameter is missing. * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` * The input is malformed. * :macro:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int ngtcp2_decode_transport_params_new( - ngtcp2_transport_params **pparams, ngtcp2_transport_params_type exttype, - const uint8_t *data, size_t datalen, const ngtcp2_mem *mem); +NGTCP2_EXTERN int +ngtcp2_transport_params_decode_new(ngtcp2_transport_params **pparams, + const uint8_t *data, size_t datalen, + const ngtcp2_mem *mem); /** * @function * * `ngtcp2_transport_params_del` frees the |params| which must be - * dynamically allocated by `ngtcp2_decode_transport_params_new`. + * dynamically allocated by `ngtcp2_transport_params_decode_new`. * * |mem| is a memory allocator that allocated |params|. If |mem| is * ``NULL``, the memory allocator returned by `ngtcp2_mem_default()` @@ -2331,15 +2201,16 @@ typedef struct ngtcp2_version_cid { * QUIC version. * * If the given packet is Long header packet, this function extracts - * the version from the packet and assigns it to + * the version from the packet, and assigns it to * :member:`dest->version `. It also * extracts the pointer to the Destination Connection ID and its - * length and assigns them to :member:`dest->dcid + * length, and assigns them to :member:`dest->dcid * ` and :member:`dest->dcidlen * ` respectively. Similarly, it extracts - * the pointer to the Source Connection ID and its length and assigns + * the pointer to the Source Connection ID and its length, and assigns * them to :member:`dest->scid ` and * :member:`dest->scidlen ` respectively. + * |short_dcidlen| is ignored. * * If the given packet is Short header packet, :member:`dest->version * ` will be 0, :member:`dest->scid @@ -2348,7 +2219,7 @@ typedef struct ngtcp2_version_cid { * Because the Short header packet does not have the length of * Destination Connection ID, the caller has to pass the length in * |short_dcidlen|. This function extracts the pointer to the - * Destination Connection ID and assigns it to :member:`dest->dcid + * Destination Connection ID, and assigns it to :member:`dest->dcid * `. |short_dcidlen| is assigned to * :member:`dest->dcidlen `. * @@ -2408,12 +2279,12 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, /** * @function * - * `ngtcp2_pkt_decode_hd_short` decodes QUIC short header packet - * header in |pkt| of length |pktlen|. |dcidlen| is the length of - * DCID in packet header. Short header packet does not encode the - * length of connection ID, thus we need the input from the outside. - * This function only parses the input just before packet number - * field. This function can handle Connection ID up to + * `ngtcp2_pkt_decode_hd_short` decodes QUIC short header in |pkt| of + * length |pktlen|. Short header packet does not encode the length of + * Connection ID, thus we need the input from the outside. |dcidlen| + * is the length of Destination Connection ID in packet header. This + * function only parses the input just before packet number field. + * This function can handle Connection ID up to * :macro:`NGTCP2_MAX_CIDLEN`. Consider to use * `ngtcp2_pkt_decode_version_cid` to get longer Connection ID. It * stores the result in the object pointed by |dest|, and returns the @@ -2461,13 +2332,13 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset( * * `ngtcp2_pkt_write_version_negotiation` writes Version Negotiation * packet in the buffer pointed by |dest| whose length is |destlen|. - * |unused_random| should be generated randomly. |dcid| is the - * destination connection ID which appears in a packet as a source - * connection ID sent by client which caused version negotiation. - * Similarly, |scid| is the source connection ID which appears in a - * packet as a destination connection ID sent by client. |sv| is a - * list of supported versions, and |nsv| specifies the number of - * supported versions included in |sv|. + * |unused_random| should be generated randomly. |dcid| is a + * Connection ID which appeared in a packet as a Source Connection ID + * sent by client which caused version negotiation. Similarly, |scid| + * is a Connection ID which appeared in a packet as a Destination + * Connection ID sent by client. |sv| is a list of supported + * versions, and |nsv| specifies the number of supported versions + * included in |sv|. * * This function returns the number of bytes written to the buffer, or * one of the following negative error codes: @@ -2494,7 +2365,7 @@ typedef struct ngtcp2_conn ngtcp2_conn; * asks TLS stack to produce first TLS cryptographic handshake data. * * This implementation of this callback must get the first handshake - * data from TLS stack and pass it to ngtcp2 library using + * data from TLS stack, and pass it to ngtcp2 library using * `ngtcp2_conn_submit_crypto_data` function. Make sure that before * calling `ngtcp2_conn_submit_crypto_data` function, client * application must create initial packet protection keys and IVs, and @@ -2514,9 +2385,9 @@ typedef int (*ngtcp2_client_initial)(ngtcp2_conn *conn, void *user_data); * Initial packet from client. An server application must implement * this callback, and generate initial keys and IVs for both * transmission and reception. Install them using - * `ngtcp2_conn_install_initial_key`. |dcid| is the destination - * connection ID which client generated randomly. It is used to - * derive initial packet protection keys. + * `ngtcp2_conn_install_initial_key`. |dcid| is the Destination + * Connection ID in Initial packet received from client. It is used + * to derive initial packet protection keys. * * The callback function must return 0 if it succeeds. If an error * occurs, return :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the @@ -2529,45 +2400,42 @@ typedef int (*ngtcp2_recv_client_initial)(ngtcp2_conn *conn, /** * @enum * - * :type:`ngtcp2_crypto_level` is encryption level. + * :type:`ngtcp2_encryption_level` is QUIC encryption level. */ -typedef enum ngtcp2_crypto_level { +typedef enum ngtcp2_encryption_level { /** - * :enum:`NGTCP2_CRYPTO_LEVEL_INITIAL` is Initial Keys encryption + * :enum:`NGTCP2_ENCRYPTION_LEVEL_INITIAL` is Initial encryption * level. */ - NGTCP2_CRYPTO_LEVEL_INITIAL, + NGTCP2_ENCRYPTION_LEVEL_INITIAL, /** - * :enum:`NGTCP2_CRYPTO_LEVEL_HANDSHAKE` is Handshake Keys - * encryption level. + * :enum:`NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE` is Handshake encryption + * level. */ - NGTCP2_CRYPTO_LEVEL_HANDSHAKE, + NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE, /** - * :enum:`NGTCP2_CRYPTO_LEVEL_APPLICATION` is Application Data - * (1-RTT) Keys encryption level. + * :enum:`NGTCP2_ENCRYPTION_LEVEL_1RTT` is 1-RTT encryption level. */ - NGTCP2_CRYPTO_LEVEL_APPLICATION, + NGTCP2_ENCRYPTION_LEVEL_1RTT, /** - * :enum:`NGTCP2_CRYPTO_LEVEL_EARLY` is Early Data (0-RTT) Keys - * encryption level. + * :enum:`NGTCP2_ENCRYPTION_LEVEL_0RTT` is 0-RTT encryption level. */ - NGTCP2_CRYPTO_LEVEL_EARLY -} ngtcp2_crypto_level; + NGTCP2_ENCRYPTION_LEVEL_0RTT +} ngtcp2_encryption_level; /** * @functypedef * * :type`ngtcp2_recv_crypto_data` is invoked when crypto data is - * received. The received data is pointed to by |data|, and its - * length is |datalen|. The |offset| specifies the offset where - * |data| is positioned. |user_data| is the arbitrary pointer passed - * to `ngtcp2_conn_client_new` or `ngtcp2_conn_server_new`. The - * ngtcp2 library ensures that the crypto data is passed to the - * application in the increasing order of |offset|. |datalen| is - * always strictly greater than 0. |crypto_level| indicates the - * encryption level where this data is received. Crypto data can - * never be received in - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_EARLY`. + * received. The received data is pointed by |data|, and its length + * is |datalen|. The |offset| specifies the offset where |data| is + * positioned. |user_data| is the arbitrary pointer passed to + * `ngtcp2_conn_client_new` or `ngtcp2_conn_server_new`. The ngtcp2 + * library ensures that the crypto data is passed to the application + * in the increasing order of |offset|. |datalen| is always strictly + * greater than 0. |encryption_level| indicates the encryption level + * where this data is received. Crypto data can never be received in + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`. * * The application should provide the given data to TLS stack. * @@ -2591,7 +2459,7 @@ typedef enum ngtcp2_crypto_level { * return immediately. */ typedef int (*ngtcp2_recv_crypto_data)(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data); @@ -2645,9 +2513,9 @@ typedef int (*ngtcp2_recv_version_negotiation)(ngtcp2_conn *conn, * This callback is client use only. * * Application must regenerate packet protection key, IV, and header - * protection key for Initial packets using the destination connection - * ID obtained by :member:`hd->scid ` and install - * them by calling `ngtcp2_conn_install_initial_key()`. + * protection key for Initial packets using the Destination Connection + * ID obtained by :member:`hd->scid `, and install + * them by calling `ngtcp2_conn_install_initial_key`. * * 0-RTT data accepted by the ngtcp2 library will be automatically * retransmitted as 0-RTT data by the library. @@ -2666,12 +2534,12 @@ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, * application to encrypt packet payload. The packet payload to * encrypt is passed as |plaintext| of length |plaintextlen|. The * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context - * object which is initialized with encryption key. The nonce is - * passed as |nonce| of length |noncelen|. The Additional + * object which is initialized with the specific encryption key. The + * nonce is passed as |nonce| of length |noncelen|. The Additional * Authenticated Data is passed as |aad| of length |aadlen|. * * The implementation of this callback must encrypt |plaintext| using - * the negotiated cipher suite and write the ciphertext into the + * the negotiated cipher suite, and write the ciphertext into the * buffer pointed by |dest|. |dest| has enough capacity to store the * ciphertext and any additional AEAD tag data. * @@ -2694,12 +2562,12 @@ typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * application to decrypt packet payload. The packet payload to * decrypt is passed as |ciphertext| of length |ciphertextlen|. The * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context - * object which is initialized with decryption key. The nonce is - * passed as |nonce| of length |noncelen|. The Additional + * object which is initialized with the specific decryption key. The + * nonce is passed as |nonce| of length |noncelen|. The Additional * Authenticated Data is passed as |aad| of length |aadlen|. * * The implementation of this callback must decrypt |ciphertext| using - * the negotiated cipher suite and write the ciphertext into the + * the negotiated cipher suite, and write the ciphertext into the * buffer pointed by |dest|. |dest| has enough capacity to store the * cleartext. * @@ -2722,12 +2590,12 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * :type:`ngtcp2_hp_mask` is invoked when the ngtcp2 library asks the * application to produce a mask to encrypt or decrypt packet header. * The encryption cipher is |hp|. |hp_ctx| is the cipher context - * object which is initialized with header protection key. The sample - * is passed as |sample| which is :macro:`NGTCP2_HP_SAMPLELEN` bytes - * long. + * object which is initialized with the specific header protection + * key. The sample is passed as |sample| which is + * :macro:`NGTCP2_HP_SAMPLELEN` bytes long. * * The implementation of this callback must produce a mask using the - * header protection cipher suite specified by QUIC specification and + * header protection cipher suite specified by QUIC specification, and * write the result into the buffer pointed by |dest|. The length of * the mask must be at least :macro:`NGTCP2_HP_MASKLEN`. The library * only uses the first :macro:`NGTCP2_HP_MASKLEN` bytes of the @@ -2746,7 +2614,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, /** * @macrosection * - * Stream data flags + * STREAM frame data flags */ /** @@ -2767,11 +2635,11 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, /** * @macro * - * :macro:`NGTCP2_STREAM_DATA_FLAG_EARLY` indicates that this chunk of - * data contains data received in 0RTT packet and the handshake has + * :macro:`NGTCP2_STREAM_DATA_FLAG_0RTT` indicates that this chunk of + * data contains data received in 0-RTT packet, and the handshake has * not completed yet, which means that the data might be replayed. */ -#define NGTCP2_STREAM_DATA_FLAG_EARLY 0x02u +#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02u /** * @functypedef @@ -2787,9 +2655,9 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * overlap. The data is passed as |data| of length |datalen|. * |datalen| may be 0 if and only if |fin| is nonzero. * - * If :macro:`NGTCP2_STREAM_DATA_FLAG_EARLY` is set in |flags|, it - * indicates that a part of or whole data was received in 0RTT packet - * and a handshake has not completed yet. + * If :macro:`NGTCP2_STREAM_DATA_FLAG_0RTT` is set in |flags|, it + * indicates that a part of or whole data was received in 0-RTT + * packet, and a handshake has not completed yet. * * The callback function must return 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the library return @@ -2804,9 +2672,9 @@ typedef int (*ngtcp2_recv_stream_data)(ngtcp2_conn *conn, uint32_t flags, * @functypedef * * :type:`ngtcp2_stream_open` is a callback function which is called - * when remote stream is opened by peer. This function is not called - * if stream is opened by implicitly (we might reconsider this - * behaviour). + * when remote stream is opened by a remote endpoint. This function + * is not called if stream is opened by implicitly (we might + * reconsider this behaviour later). * * The implementation of this callback should return 0 if it succeeds. * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library @@ -2883,16 +2751,19 @@ typedef int (*ngtcp2_stream_reset)(ngtcp2_conn *conn, int64_t stream_id, * @functypedef * * :type:`ngtcp2_acked_stream_data_offset` is a callback function - * which is called when stream data is acked, and application can free - * the data. The acked range of data is [offset, offset + datalen). - * For a given stream_id, this callback is called sequentially in - * increasing order of |offset| without any overlap. |datalen| is - * normally strictly greater than 0. One exception is that when a - * packet which includes STREAM frame which has fin flag set, and 0 - * length data, this callback is invoked with 0 passed as |datalen|. - * - * If a stream is closed prematurely and stream data is still + * which is called when stream data in range [|offset|, |offset| + + * |datalen|) is acknowledged, and application can free the portion of + * data. For a given |stream_id|, this callback is called + * sequentially in increasing order of |offset| without any overlap. + * |datalen| is normally strictly greater than 0. One exception is + * that when a STREAM frame has fin flag set and 0 length data, this + * callback is invoked with |datalen| == 0. + * + * If a stream is closed prematurely, and stream data is still * in-flight, this callback function is not called for those data. + * After :member:`ngtcp2_callbacks.stream_close` is called for a + * particular stream, |conn| does not touch data for the closed stream + * again, and application can free all unacknowledged stream data. * * The implementation of this callback should return 0 if it succeeds. * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library @@ -2938,7 +2809,7 @@ typedef int (*ngtcp2_extend_max_streams)(ngtcp2_conn *conn, * :type:`ngtcp2_extend_max_stream_data` is a callback function which * is invoked when max stream data is extended. |stream_id| * identifies the stream. |max_data| is a cumulative number of bytes - * the endpoint can send on this stream. + * an endpoint can send on this stream. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -2952,10 +2823,10 @@ typedef int (*ngtcp2_extend_max_stream_data)(ngtcp2_conn *conn, /** * @functypedef * - * :type:`ngtcp2_rand` is a callback function to get randomized byte - * string from application. Application must fill random |destlen| - * bytes to the buffer pointed by |dest|. The generated bytes are - * used only in non-cryptographic context. + * :type:`ngtcp2_rand` is a callback function to get random data of + * length |destlen|. Application must fill random |destlen| bytes to + * the buffer pointed by |dest|. The generated data is used only in + * non-cryptographic context. */ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx); @@ -2965,11 +2836,11 @@ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, * * :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 it - * in |cid|. It also has to generate stateless reset token into - * |token|. The length of stateless reset token is + * new unused connection ID with the exact |cidlen| bytes, and store + * it in |cid|. It also has to generate a stateless reset token, and + * store it in |token|. The length of stateless reset token is * :macro:`NGTCP2_STATELESS_RESET_TOKENLEN` and it is guaranteed that - * the buffer pointed by |cid| has the sufficient space to store the + * the buffer pointed by |token| has the sufficient space to store the * token. * * The callback function must return 0 if it succeeds. Returning @@ -2985,7 +2856,9 @@ typedef int (*ngtcp2_get_new_connection_id)(ngtcp2_conn *conn, ngtcp2_cid *cid, * * :type:`ngtcp2_remove_connection_id` is a callback function which * notifies the application that connection ID |cid| is no longer used - * by remote endpoint. + * by a remote endpoint. This Connection ID was previously offered by + * a local endpoint, and a remote endpoint could use it as Destination + * Connection ID when sending QUIC packet. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3005,15 +2878,15 @@ typedef int (*ngtcp2_remove_connection_id)(ngtcp2_conn *conn, * |current_tx_secret| of length |secretlen|. They are decryption and * encryption secrets respectively. * - * The application has to generate new secrets and keys for both - * encryption and decryption, and write decryption secret and IV to - * the buffer pointed by |rx_secret| and |rx_iv| respectively. It - * also has to create new AEAD cipher context object with new - * decryption key and initialize |rx_aead_ctx| with it. Similarly, - * write encryption secret and IV to the buffer pointed by |tx_secret| - * and |tx_iv|. Create new AEAD cipher context object with new - * encryption key and initialize |tx_aead_ctx| with it. All given - * buffers have the enough capacity to store secret, key and IV. + * The application must generate new secrets and keys for both + * encryption and decryption. It must write decryption secret and IV + * to the buffer pointed by |rx_secret| and |rx_iv| respectively. It + * also must create new AEAD cipher context object with new decryption + * key and initialize |rx_aead_ctx| with it. Similarly, write + * encryption secret and IV to the buffer pointed by |tx_secret| and + * |tx_iv|. Create new AEAD cipher context object with new encryption + * key and initialize |tx_aead_ctx| with it. All given buffers have + * the enough capacity to store secret, key and IV. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3048,14 +2921,25 @@ typedef int (*ngtcp2_update_key)( */ #define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01u +/** + * @macro + * + * :macro:`NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN` indicates that + * server should send NEW_TOKEN frame for the new remote address. + * This flag is only set for server. + */ +#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02u + /** * @functypedef * * :type:`ngtcp2_path_validation` is a callback function which tells - * the application the outcome of path validation. |flags| is zero or + * an application the outcome of path validation. |flags| is zero or * more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_* * `. |path| is the path that was - * validated. If |res| is + * validated. |old_path| is the path that is previously used before a + * local endpoint has migrated to |path| if |old_path| is not NULL. + * If |res| is * :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_SUCCESS`, * the path validation succeeded. If |res| is * :enum:`ngtcp2_path_validation_result.NGTCP2_PATH_VALIDATION_RESULT_FAILURE`, @@ -3067,6 +2951,7 @@ typedef int (*ngtcp2_update_key)( */ typedef int (*ngtcp2_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); @@ -3087,10 +2972,10 @@ typedef int (*ngtcp2_path_validation)(ngtcp2_conn *conn, uint32_t flags, * from `ngtcp2_conn_get_path()`. Both :member:`dest->local.addr * ` and :member:`dest->remote.addr * ` point to buffers which are at least - * ``sizeof(struct sockaddr_storage)`` bytes long, respectively. If + * sizeof(:type:`ngtcp2_sockaddr_union`) bytes long, respectively. If * an application denies the preferred addresses, just leave |dest| * unmodified (or set :member:`dest->remote.addrlen - * ` to 0) and return 0. + * ` to 0), and return 0. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3110,12 +2995,12 @@ typedef int (*ngtcp2_select_preferred_addr)(ngtcp2_conn *conn, typedef enum ngtcp2_connection_id_status_type { /** * :enum:`NGTCP2_CONNECTION_ID_STATUS_TYPE_ACTIVATE` indicates that - * a local endpoint starts using new destination Connection ID. + * a local endpoint starts using new Destination Connection ID. */ NGTCP2_CONNECTION_ID_STATUS_TYPE_ACTIVATE, /** * :enum:`NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE` indicates - * that a local endpoint stops using a given destination Connection + * that a local endpoint stops using a given Destination Connection * ID. */ NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE @@ -3125,9 +3010,9 @@ typedef enum ngtcp2_connection_id_status_type { * @functypedef * * :type:`ngtcp2_connection_id_status` is a callback function which is - * called when the status of Connection ID changes. + * called when the status of Destination Connection ID changes. * - * |token| is the associated stateless reset token and it is ``NULL`` + * |token| is the associated stateless reset token, and it is ``NULL`` * if no token is present. * * |type| is the one of the value defined in @@ -3138,25 +3023,25 @@ typedef enum ngtcp2_connection_id_status_type { * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. */ -typedef int (*ngtcp2_connection_id_status)(ngtcp2_conn *conn, int type, - uint64_t seq, const ngtcp2_cid *cid, - const uint8_t *token, - void *user_data); +typedef int (*ngtcp2_connection_id_status)( + ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq, + const ngtcp2_cid *cid, const uint8_t *token, void *user_data); /** * @functypedef * * :type:`ngtcp2_recv_new_token` is a callback function which is - * called when new token is received from server. + * called when new token is received from server. This callback is + * client use only. * - * |token| is the received token. + * |token| is the received token of length |tokenlen| bytes long. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. */ -typedef int (*ngtcp2_recv_new_token)(ngtcp2_conn *conn, const ngtcp2_vec *token, - void *user_data); +typedef int (*ngtcp2_recv_new_token)(ngtcp2_conn *conn, const uint8_t *token, + size_t tokenlen, void *user_data); /** * @functypedef @@ -3184,7 +3069,7 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( /** * @macrosection * - * Datagram flags + * DATAGRAM frame flags */ /** @@ -3197,11 +3082,11 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( /** * @macro * - * :macro:`NGTCP2_DATAGRAM_FLAG_EARLY` indicates that DATAGRAM frame - * is received in 0RTT packet and the handshake has not completed yet, + * :macro:`NGTCP2_DATAGRAM_FLAG_0RTT` indicates that DATAGRAM frame is + * received in 0-RTT packet, and the handshake has not completed yet, * which means that the data might be replayed. */ -#define NGTCP2_DATAGRAM_FLAG_EARLY 0x01u +#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01u /** * @functypedef @@ -3210,8 +3095,8 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( * received. |flags| is bitwise-OR of zero or more of * :macro:`NGTCP2_DATAGRAM_FLAG_* `. * - * If :macro:`NGTCP2_DATAGRAM_FLAG_EARLY` is set in |flags|, it - * indicates that DATAGRAM frame was received in 0RTT packet and a + * If :macro:`NGTCP2_DATAGRAM_FLAG_0RTT` is set in |flags|, it + * indicates that DATAGRAM frame was received in 0-RTT packet, and a * handshake has not completed yet. * * The callback function must return 0 if it succeeds, or @@ -3257,8 +3142,8 @@ typedef int (*ngtcp2_lost_datagram)(ngtcp2_conn *conn, uint64_t dgram_id, * * :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 - * :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes of random data and + * frame. Application must generate new unpredictable, exactly + * :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes of random data, and * store them into the buffer pointed by |data|. * * The callback function must return 0 if it succeeds. Returning @@ -3296,8 +3181,9 @@ typedef int (*ngtcp2_stream_stop_sending)(ngtcp2_conn *conn, int64_t stream_id, * server, it is called once when the version is negotiated. * * The implementation of this callback must install new Initial keys - * for |version|. Use `ngtcp2_conn_install_vneg_initial_key` to - * install keys. + * for |version| and Destination Connection ID |client_dcid| from + * client. Use `ngtcp2_conn_install_vneg_initial_key` to install + * keys. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -3317,11 +3203,25 @@ typedef int (*ngtcp2_version_negotiation)(ngtcp2_conn *conn, uint32_t version, * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. */ -typedef int (*ngtcp2_recv_key)(ngtcp2_conn *conn, ngtcp2_crypto_level level, +typedef int (*ngtcp2_recv_key)(ngtcp2_conn *conn, ngtcp2_encryption_level level, void *user_data); -#define NGTCP2_CALLBACKS_VERSION_V1 1 -#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_VERSION_V1 +/** + * @functypedef + * + * :type:`ngtcp2_tls_early_data_rejected` is invoked when early data + * was rejected by server during TLS handshake, or client decided not + * to attempt early data. + * + * The callback function must return 0 if it succeeds. Returning + * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return + * immediately. + */ +typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn, + void *user_data); + +#define NGTCP2_CALLBACKS_V1 1 +#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V1 /** * @struct @@ -3338,8 +3238,9 @@ typedef struct ngtcp2_callbacks { ngtcp2_client_initial client_initial; /** * :member:`recv_client_initial` is a callback function which is - * invoked when a server receives the first packet from client. - * This callback function must be specified for a server application. + * invoked when a server receives the first Initial packet from + * client. This callback function must be specified for a server + * application. */ ngtcp2_recv_client_initial recv_client_initial; /** @@ -3373,23 +3274,23 @@ typedef struct ngtcp2_callbacks { ngtcp2_decrypt decrypt; /** * :member:`hp_mask` is a callback function which is invoked to get - * a mask to encrypt or decrypt packet header. This callback + * a mask to encrypt or decrypt QUIC packet header. This callback * function must be specified. */ ngtcp2_hp_mask hp_mask; /** * :member:`recv_stream_data` is a callback function which is - * invoked when STREAM data, which includes application data, is + * invoked when stream data, which includes application data, is * received. This callback function is optional. */ ngtcp2_recv_stream_data recv_stream_data; /** * :member:`acked_stream_data_offset` is a callback function which - * is invoked when STREAM data, which includes application data, is + * is invoked when stream data, which includes application data, is * acknowledged by a remote endpoint. It tells an application the - * largest offset of acknowledged STREAM data without a gap so that - * application can free memory for the data. This callback function - * is optional. + * largest offset of acknowledged stream data without a gap so that + * application can free memory for the data up to that offset. This + * callback function is optional. */ ngtcp2_acked_stream_data_offset acked_stream_data_offset; /** @@ -3431,8 +3332,8 @@ typedef struct ngtcp2_callbacks { ngtcp2_extend_max_streams extend_max_local_streams_uni; /** * :member:`rand` is a callback function which is invoked when the - * library needs sequence of random data. This callback function - * must be specified. + * library needs random data. This callback function must be + * specified. */ ngtcp2_rand rand; /** @@ -3450,7 +3351,7 @@ typedef struct ngtcp2_callbacks { /** * :member:`update_key` is a callback function which is invoked when * the library tells an application that it must update keying - * materials and install new keys. This callback function must be + * materials, and install new keys. This callback function must be * specified. */ ngtcp2_update_key update_key; @@ -3463,8 +3364,8 @@ typedef struct ngtcp2_callbacks { /** * :member:`select_preferred_addr` is a callback function which is * invoked when the library asks a client to select preferred - * address presented by a server. This callback function is - * optional. + * address presented by a server. If not set, client ignores + * preferred addresses. This callback function is optional. */ ngtcp2_select_preferred_addr select_preferred_addr; /** @@ -3489,24 +3390,24 @@ typedef struct ngtcp2_callbacks { ngtcp2_extend_max_streams extend_max_remote_streams_uni; /** * :member:`extend_max_stream_data` is callback function which is - * invoked when the maximum offset of STREAM data that a local + * invoked when the maximum offset of stream data that a local * endpoint can send is increased. This callback function is * optional. */ ngtcp2_extend_max_stream_data extend_max_stream_data; /** * :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 + * when the new Destination Connection ID is activated, or the + * activated Destination Connection ID is now deactivated. This * callback function is optional. */ ngtcp2_connection_id_status dcid_status; /** * :member:`handshake_confirmed` is a callback function which is * invoked when both endpoints agree that handshake has finished. - * This field is ignored by server because handshake_completed - * indicates the handshake confirmation for server. This callback - * function is optional. + * This field is ignored by server because + * :member:`handshake_completed` also indicates the handshake + * confirmation for server. This callback function is optional. */ ngtcp2_handshake_confirmed handshake_confirmed; /** @@ -3535,20 +3436,20 @@ typedef struct ngtcp2_callbacks { ngtcp2_recv_datagram recv_datagram; /** * :member:`ack_datagram` is a callback function which is invoked - * when a packet containing DATAGRAM frame is acknowledged. This - * callback function is optional. + * when a QUIC packet containing DATAGRAM frame is acknowledged by a + * remote endpoint. This callback function is optional. */ ngtcp2_ack_datagram ack_datagram; /** * :member:`lost_datagram` is a callback function which is invoked - * when a packet containing DATAGRAM frame is declared lost. This - * callback function is optional. + * when a QUIC packet containing DATAGRAM frame is declared lost. + * This callback function is optional. */ ngtcp2_lost_datagram lost_datagram; /** * :member:`get_path_challenge_data` is a callback function which is - * invoked when the library needs new PATH_CHALLENGE data. This - * callback must be specified. + * invoked when the library needs new data sent along with + * PATH_CHALLENGE frame. This callback must be specified. */ ngtcp2_get_path_challenge_data get_path_challenge_data; /** @@ -3568,16 +3469,23 @@ typedef struct ngtcp2_callbacks { * :member:`recv_rx_key` is a callback function which is invoked * when a new key for decrypting packets is installed during QUIC * cryptographic handshake. It is not called for - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_INITIAL`. + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_INITIAL`. */ ngtcp2_recv_key recv_rx_key; /** * :member:`recv_tx_key` is a callback function which is invoked * when a new key for encrypting packets is installed during QUIC * cryptographic handshake. It is not called for - * :enum:`ngtcp2_crypto_level.NGTCP2_CRYPTO_LEVEL_INITIAL`. + * :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_INITIAL`. */ ngtcp2_recv_key recv_tx_key; + /** + * :member:`tls_early_data_rejected` is a callback function which is + * invoked when server rejected early data during TLS handshake, or + * client decided not to attempt early data. This callback function + * is only used by client. + */ + ngtcp2_tls_early_data_rejected tls_early_data_rejected; } ngtcp2_callbacks; /** @@ -3591,7 +3499,7 @@ typedef struct ngtcp2_callbacks { * * The primary use case of this function is for server to send * CONNECTION_CLOSE frame in Initial packet to close connection - * without committing the state when validating Retry token fails. + * without committing any state when validating Retry token fails. * * This function returns the number of bytes written if it succeeds, * or one of the following negative error codes: @@ -3613,11 +3521,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close( * @function * * `ngtcp2_pkt_write_retry` writes Retry packet in the buffer pointed - * by |dest| whose length is |destlen|. |dcid| is the destination - * connection ID which appeared in a packet as a source connection ID - * sent by client. |scid| is a server chosen source connection ID. - * |odcid| specifies Original Destination Connection ID which appeared - * in a packet as a destination connection ID sent by client. |token| + * by |dest| whose length is |destlen|. |dcid| is the Connection ID + * which appeared in a packet as a Source Connection ID sent by + * client. |scid| is a server chosen Source Connection ID. |odcid| + * specifies Original Destination Connection ID which appeared in a + * packet as a Destination Connection ID sent by client. |token| * specifies Retry Token, and |tokenlen| specifies its length. |aead| * must be AEAD_AES_128_GCM. |aead_ctx| must be initialized with * :macro:`NGTCP2_RETRY_KEY` as an encryption key. @@ -3644,17 +3552,14 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_retry( * * `ngtcp2_accept` is used by server implementation, and decides * whether packet |pkt| of length |pktlen| from client is acceptable - * for the very initial packet to a connection. + * for the very first packet to a connection. * - * If |dest| is not ``NULL`` and the function returns 0, or - * :macro:`NGTCP2_ERR_RETRY`, the decoded packet header is stored to - * the object pointed by |dest|. + * If |dest| is not ``NULL`` and the function returns 0, the decoded + * packet header is stored in the object pointed by |dest|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGTCP2_ERR_RETRY` - * Retry packet should be sent. * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` * The packet is not acceptable for the very first packet to a new * connection; or the function failed to parse the packet header. @@ -3666,17 +3571,21 @@ NGTCP2_EXTERN int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, * @function * * `ngtcp2_conn_client_new` creates new :type:`ngtcp2_conn`, and - * initializes it as client. |dcid| is randomized destination - * connection ID. |scid| is source connection ID. - * |client_chosen_version| is a QUIC version that a client chooses. - * |path| is the network path where this QUIC connection is being - * established and must not be ``NULL``. |callbacks|, |settings|, and - * |params| must not be ``NULL``, and the function make a copy of each - * of them. |params| is local QUIC transport parameters and sent to a - * remote endpoint during handshake. |user_data| is the arbitrary - * pointer which is passed to the user-defined callback functions. If - * |mem| is ``NULL``, the memory allocator returned by - * `ngtcp2_mem_default()` is used. + * initializes it as client. On success, it stores the pointer to the + * newly allocated object in |*pconn|. |dcid| is a randomized + * Destination Connection ID which must be longer than or equal to + * :macro:`NGTCP2_MIN_INITIAL_DCIDLEN`. |scid| is a Source Connection + * ID chosen by client. |client_chosen_version| is a QUIC version + * that a client chooses. |path| is the network path where this QUIC + * connection is being established, and must not be ``NULL``. + * |callbacks|, |settings|, and |params| must not be ``NULL``, and the + * function makes a copy of each of them. |params| is a local QUIC + * transport parameters, and sent to a remote endpoint during + * handshake. |user_data| is the arbitrary pointer which is passed to + * the user-defined callback functions. If |mem| is ``NULL``, the + * memory allocator returned by `ngtcp2_mem_default()` is used. + * + * Call `ngtcp2_conn_del` to free memory allocated for |*pconn|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3696,16 +3605,22 @@ NGTCP2_EXTERN int ngtcp2_conn_client_new_versioned( * @function * * `ngtcp2_conn_server_new` creates new :type:`ngtcp2_conn`, and - * initializes it as server. |dcid| is a destination connection ID. - * |scid| is a source connection ID. |path| is the network path where - * this QUIC connection is being established and must not be ``NULL``. - * |client_chosen_version| is a QUIC version that a client chooses. - * |callbacks|, |settings|, and |params| must not be ``NULL``, and the - * function make a copy of each of them. |params| is local QUIC - * transport parameters and sent to a remote endpoint during - * handshake. |user_data| is the arbitrary pointer which is passed to - * the user-defined callback functions. If |mem| is ``NULL``, the - * memory allocator returned by `ngtcp2_mem_default()` is used. + * initializes it as server. On success, it stores the pointer to the + * newly allocated object in |*pconn|. |dcid| is a Destination + * Connection ID, and is usually the Connection ID that appears in + * client Initial packet as Source Connection ID. |scid| is a Source + * Connection ID chosen by server. |path| is the network path where + * this QUIC connection is being established, and must not be + * ``NULL``. |client_chosen_version| is a QUIC version that a client + * chooses. |callbacks|, |settings|, and |params| must not be + * ``NULL``, and the function makes a copy of each of them. |params| + * is a local QUIC transport parameters, and sent to a remote endpoint + * during handshake. |user_data| is the arbitrary pointer which is + * passed to the user-defined callback functions. If |mem| is + * ``NULL``, the memory allocator returned by `ngtcp2_mem_default()` + * is used. + * + * Call `ngtcp2_conn_del` to free memory allocated for |*pconn|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3741,19 +3656,31 @@ NGTCP2_EXTERN void ngtcp2_conn_del(ngtcp2_conn *conn); * This function must not be called from inside the callback * functions. * - * This function returns 0 if it succeeds, or negative error codes. - * If :macro:`NGTCP2_ERR_RETRY` is returned, application must be a - * server and it must perform address validation by sending Retry - * packet and discard the connection state. If - * :macro:`NGTCP2_ERR_DROP_CONN` is returned, server application must - * drop the connection silently (without sending any CONNECTION_CLOSE - * frame) and discard connection state. If - * :macro:`NGTCP2_ERR_DRAINING` is returned, a connection has entered - * the draining state, and no further packet transmission is allowed. - * If :macro:`NGTCP2_ERR_CRYPTO` is returned, the error happened in - * TLS stack and `ngtcp2_conn_get_tls_alert` returns TLS alert if set. - * - * If any other negative errors are returned, call + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_RETRY` + * Server must perform address validation by sending Retry packet + * (see `ngtcp2_crypto_write_retry` and `ngtcp2_pkt_write_retry`), + * and discard the connection state. Client application does not + * get this error code. + * :macro:`NGTCP2_ERR_DROP_CONN` + * Server application must drop the connection silently (without + * sending any CONNECTION_CLOSE frame), and discard connection + * state. Client application does not get this error code. + * :macro:`NGTCP2_ERR_DRAINING` + * A connection has entered the draining state, and no further + * packet transmission is allowed. + * :macro:`NGTCP2_ERR_CLOSING` + * A connection has entered the closing state, and no further + * packet transmission is allowed. Calling + * `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` + * returns TLS alert if set. + * + * If any other negative error is returned, call * `ngtcp2_conn_write_connection_close` to get terminal packet, and * sending it makes QUIC connection enter the closing state. */ @@ -3767,8 +3694,8 @@ ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, * @function * * `ngtcp2_conn_write_pkt` is equivalent to calling - * `ngtcp2_conn_writev_stream` with -1 as stream_id, no stream data, and - * :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE` as flags. + * `ngtcp2_conn_writev_stream` with -1 as |stream_id|, no stream data, + * and :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE` as flags. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_pkt_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -3777,18 +3704,18 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_pkt_versioned( /** * @function * - * `ngtcp2_conn_handshake_completed` tells |conn| that the TLS stack - * declares TLS handshake completion. This does not mean QUIC + * `ngtcp2_conn_tls_handshake_completed` tells |conn| that the TLS + * stack declares TLS handshake completion. This does not mean QUIC * handshake has completed. The library needs extra conditions to be * met. */ -NGTCP2_EXTERN void ngtcp2_conn_handshake_completed(ngtcp2_conn *conn); +NGTCP2_EXTERN void ngtcp2_conn_tls_handshake_completed(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_handshake_completed` returns nonzero if QUIC handshake - * has completed. + * `ngtcp2_conn_get_handshake_completed` returns nonzero if QUIC + * handshake has completed. */ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); @@ -3797,11 +3724,11 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); * * `ngtcp2_conn_install_initial_key` installs packet protection keying * materials for Initial packets. |rx_aead_ctx| is AEAD cipher - * context object and must be initialized with a decryption key. + * context object, and must be initialized with a decryption key. * |rx_iv| is IV of length |rx_ivlen| for decryption. |rx_hp_ctx| is * a packet header protection cipher context object for decryption. * Similarly, |tx_aead_ctx|, |tx_iv| and |tx_hp_ctx| are for - * encrypting outgoing packets and are the same length with the + * encrypting outgoing packets, and are the same length with the * decryption counterpart . If they have already been set, they are * overwritten. * @@ -3810,14 +3737,16 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn); * * If this function succeeds, |conn| takes ownership of |rx_aead_ctx|, * |rx_hp_ctx|, |tx_aead_ctx|, and |tx_hp_ctx|. - * :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. - * - * After receiving Retry packet, the DCID most likely changes. In - * that case, client application must generate these keying materials - * again based on new DCID and install them again. + * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. + * + * After receiving Retry packet, a Destination Connection ID that + * client sends in Initial packet most likely changes. In that case, + * client application must generate these keying materials again based + * on new Destination Connection ID, and install them again with this + * function. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3837,11 +3766,11 @@ NGTCP2_EXTERN int ngtcp2_conn_install_initial_key( * `ngtcp2_conn_install_vneg_initial_key` installs packet protection * keying materials for Initial packets on compatible version * negotiation for |version|. |rx_aead_ctx| is AEAD cipher context - * object and must be initialized with a decryption key. |rx_iv| is + * object, and must be initialized with a decryption key. |rx_iv| is * IV of length |rx_ivlen| for decryption. |rx_hp_ctx| is a packet * header protection cipher context object for decryption. Similarly, * |tx_aead_ctx|, |tx_iv| and |tx_hp_ctx| are for encrypting outgoing - * packets and are the same length with the decryption counterpart . + * packets, and are the same length with the decryption counterpart. * If they have already been set, they are overwritten. * * |ivlen| must be the minimum length of AEAD nonce, or 8 bytes if @@ -3849,10 +3778,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_initial_key( * * If this function succeeds, |conn| takes ownership of |rx_aead_ctx|, * |rx_hp_ctx|, |tx_aead_ctx|, and |tx_hp_ctx|. - * :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3880,10 +3809,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_vneg_initial_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx|, - * and |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * and |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` + * and :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be + * called to delete these objects when they are no longer used. If + * this function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3908,10 +3837,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_rx_handshake_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3926,19 +3855,19 @@ NGTCP2_EXTERN int ngtcp2_conn_install_tx_handshake_key( /** * @function * - * `ngtcp2_conn_install_early_key` installs packet protection AEAD + * `ngtcp2_conn_install_0rtt_key` installs packet protection AEAD * cipher context object |aead_ctx|, IV |iv| of length |ivlen|, and * packet header protection cipher context object |hp_ctx| to encrypt - * (for client) or decrypt (for server) 0RTT packets. + * (for client) or decrypt (for server) 0-RTT packets. * * |ivlen| must be the minimum length of AEAD nonce, or 8 bytes if * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3946,7 +3875,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_tx_handshake_key( * :macro:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int ngtcp2_conn_install_early_key( +NGTCP2_EXTERN int ngtcp2_conn_install_0rtt_key( ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx); @@ -3954,7 +3883,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key( * @function * * `ngtcp2_conn_install_rx_key` installs packet protection keying - * materials for decrypting Short header packets. |secret| of length + * materials for decrypting 1-RTT packets. |secret| of length * |secretlen| is the decryption secret which is used to derive keying * materials passed to this function. |aead_ctx| is AEAD cipher * context object which must be initialized with a decryption key. @@ -3965,10 +3894,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -3985,7 +3914,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_rx_key( * @function * * `ngtcp2_conn_install_tx_key` installs packet protection keying - * materials for encrypting Short header packets. |secret| of length + * materials for encrypting 1-RTT packets. |secret| of length * |secretlen| is the encryption secret which is used to derive keying * materials passed to this function. |aead_ctx| is AEAD cipher * context object which must be initialized with an encryption key. @@ -3996,10 +3925,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_rx_key( * that is larger. * * If this function succeeds, |conn| takes ownership of |aead_ctx| and - * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and - * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete - * these objects when they are no longer used. If this function - * fails, the caller is responsible to delete them. + * |hp_ctx|. :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` and + * :member:`ngtcp2_callbacks.delete_crypto_cipher_ctx` will be called + * to delete these objects when they are no longer used. If this + * function fails, the caller is responsible to delete them. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4035,10 +3964,12 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, * is defined as NGTCP2_ERR_* macro, such as * :macro:`NGTCP2_ERR_DECRYPT`). In general, error code should be * propagated via return value, but sometimes ngtcp2 API is called - * inside callback function of TLS stack and it does not allow to + * inside callback function of TLS stack, and it does not allow to * return ngtcp2 error code directly. In this case, implementation * can set the error code (e.g., * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM`) using this function. + * + * See also `ngtcp2_conn_get_tls_error`. */ NGTCP2_EXTERN void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr); @@ -4055,7 +3986,9 @@ NGTCP2_EXTERN int ngtcp2_conn_get_tls_error(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_set_tls_alert` sets a TLS alert |alert| generated by a - * local endpoint to |conn|. + * TLS stack of a local endpoint to |conn|. + * + * See also `ngtcp2_conn_get_tls_alert`. */ NGTCP2_EXTERN void ngtcp2_conn_set_tls_alert(ngtcp2_conn *conn, uint8_t alert); @@ -4073,8 +4006,10 @@ NGTCP2_EXTERN uint8_t ngtcp2_conn_get_tls_alert(ngtcp2_conn *conn); * * `ngtcp2_conn_set_keep_alive_timeout` sets keep-alive timeout. If * nonzero value is given, after a connection is idle at least in a - * given amount of time, a keep-alive packet is sent. If 0 is set, - * keep-alive functionality is disabled and this is the default. + * given amount of time, a keep-alive packet is sent. If UINT64_MAX + * is set, keep-alive functionality is disabled, and this is the + * default. Specifying 0 in |timeout| is reserved for a future + * extension, and for now it is treated as if UINT64_MAX is given. */ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, ngtcp2_duration timeout); @@ -4082,18 +4017,19 @@ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_get_expiry` returns the next expiry time. + * `ngtcp2_conn_get_expiry` returns the next expiry time. It returns + * ``UINT64_MAX`` if there is no next expiry. * - * Call `ngtcp2_conn_handle_expiry()` and `ngtcp2_conn_write_pkt` (or - * `ngtcp2_conn_writev_stream`) if expiry time is passed. + * Call `ngtcp2_conn_handle_expiry` and then + * `ngtcp2_conn_writev_stream` (or `ngtcp2_conn_writev_datagram`) when + * the expiry time has passed. */ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_handle_expiry` handles expired timer. It does nothing - * if timer is not expired. + * `ngtcp2_conn_handle_expiry` handles expired timer. */ NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts); @@ -4108,9 +4044,9 @@ NGTCP2_EXTERN ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_decode_remote_transport_params` decodes QUIC transport - * parameters from the buffer pointed by |data| of length |datalen|, - * and sets the result to |conn|. + * `ngtcp2_conn_decode_and_set_remote_transport_params` decodes QUIC + * transport parameters from the buffer pointed by |data| of length + * |datalen|, and sets the result to |conn|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4126,9 +4062,8 @@ NGTCP2_EXTERN ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn); * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` * User callback failed */ -NGTCP2_EXTERN int -ngtcp2_conn_decode_remote_transport_params(ngtcp2_conn *conn, - const uint8_t *data, size_t datalen); +NGTCP2_EXTERN int ngtcp2_conn_decode_and_set_remote_transport_params( + ngtcp2_conn *conn, const uint8_t *data, size_t datalen); /** * @function @@ -4143,36 +4078,77 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_early_remote_transport_params` sets |params| as - * transport parameters previously received from a server. The - * parameters are used to send early data. QUIC requires that client - * application should remember transport parameters along with a - * session ticket. - * - * At least following fields should be set: - * - * - initial_max_stream_id_bidi - * - initial_max_stream_id_uni - * - initial_max_stream_data_bidi_local - * - initial_max_stream_data_bidi_remote - * - initial_max_stream_data_uni - * - initial_max_data - * - active_connection_id_limit - * - max_datagram_frame_size (if DATAGRAM extension was negotiated) - * - * The following fields are ignored: - * - * - ack_delay_exponent - * - max_ack_delay - * - initial_scid - * - original_dcid - * - preferred_address and preferred_address_present - * - retry_scid and retry_scid_present - * - stateless_reset_token and stateless_reset_token_present - */ -NGTCP2_EXTERN void ngtcp2_conn_set_early_remote_transport_params_versioned( - ngtcp2_conn *conn, int transport_params_version, - const ngtcp2_transport_params *params); + * `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 + * 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, it is 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. + */ +NGTCP2_EXTERN +ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params(ngtcp2_conn *conn, + uint8_t *dest, + size_t destlen); + +/** + * @function + * + * `ngtcp2_conn_decode_and_set_0rtt_transport_params` decodes QUIC + * transport parameters from |data| of length |datalen|, which is + * assumed to be the parameters received from the server in the + * previous connection, and sets it to |conn|. These parameters are + * used to send 0-RTT data. QUIC requires that client application + * should remember transport parameters along with a session ticket. + * + * At least following fields should be included: + * + * - :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 + * DATAGRAM extension was negotiated) + * + * This function must only be used by client. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_NOMEM` + * Out of memory. + * :macro:`NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM` + * The input is malformed. + */ +NGTCP2_EXTERN int ngtcp2_conn_decode_and_set_0rtt_transport_params( + ngtcp2_conn *conn, const uint8_t *data, size_t datalen); /** * @function @@ -4182,7 +4158,7 @@ NGTCP2_EXTERN void ngtcp2_conn_set_early_remote_transport_params_versioned( * Although the local transport parameters are passed to * `ngtcp2_conn_server_new`, server might want to update them after * ALPN is chosen. In that case, server can update the transport - * parameter with this function. Server must call this function + * parameters with this function. Server must call this function * before calling `ngtcp2_conn_install_tx_handshake_key`. * * This function returns 0 if it succeeds, or one of the following @@ -4208,11 +4184,9 @@ ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_encode_local_transport_params` encodes the local QUIC - * transport parameters in |dest| of length |destlen|. This is - * equivalent to calling `ngtcp2_conn_get_local_transport_params` and - * then `ngtcp2_encode_transport_params`. + * transport parameters in |dest| of length |destlen|. * - * This function returns the number of written, or one of the + * This function returns the number of bytes written, or one of the * following negative error codes: * * :macro:`NGTCP2_ERR_NOBUF` @@ -4226,16 +4200,16 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_encode_local_transport_params( * * `ngtcp2_conn_open_bidi_stream` opens new bidirectional stream. The * |stream_user_data| is the user data specific to the stream. The - * open stream ID is stored in |*pstream_id|. + * stream ID of the opened stream is stored in |*pstream_id|. * * Application can call this function before handshake completes. For - * 0RTT packet, application can call this function after calling - * `ngtcp2_conn_set_early_remote_transport_params`. For 1RTT packet, - * application can call this function after calling - * `ngtcp2_conn_decode_remote_transport_params` and + * 0-RTT packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_0rtt_transport_params`. For 1-RTT + * packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_remote_transport_params` and * `ngtcp2_conn_install_tx_key`. If ngtcp2 crypto support library is * used, application can call this function after calling - * `ngtcp2_crypto_derive_and_install_tx_key` for 1RTT packet. + * `ngtcp2_crypto_derive_and_install_tx_key` for 1-RTT packet. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4243,7 +4217,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_encode_local_transport_params( * :macro:`NGTCP2_ERR_NOMEM` * Out of memory * :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED` - * The remote peer does not allow |stream_id| yet. + * The remote endpoint does not allow |stream_id| yet. */ NGTCP2_EXTERN int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -4254,16 +4228,16 @@ NGTCP2_EXTERN int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, * * `ngtcp2_conn_open_uni_stream` opens new unidirectional stream. The * |stream_user_data| is the user data specific to the stream. The - * open stream ID is stored in |*pstream_id|. + * stream ID of the opened stream is stored in |*pstream_id|. * * Application can call this function before handshake completes. For - * 0RTT packet, application can call this function after calling - * `ngtcp2_conn_set_early_remote_transport_params`. For 1RTT packet, - * application can call this function after calling - * `ngtcp2_conn_decode_remote_transport_params` and + * 0-RTT packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_0rtt_transport_params`. For 1-RTT + * packet, application can call this function after calling + * `ngtcp2_conn_decode_and_set_remote_transport_params` and * `ngtcp2_conn_install_tx_key`. If ngtcp2 crypto support library is * used, application can call this function after calling - * `ngtcp2_crypto_derive_and_install_tx_key` for 1RTT packet. + * `ngtcp2_crypto_derive_and_install_tx_key` for 1-RTT packet. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4271,7 +4245,7 @@ NGTCP2_EXTERN int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, * :macro:`NGTCP2_ERR_NOMEM` * Out of memory * :macro:`NGTCP2_ERR_STREAM_ID_BLOCKED` - * The remote peer does not allow |stream_id| yet. + * The remote endpoint does not allow |stream_id| yet. */ NGTCP2_EXTERN int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -4280,14 +4254,20 @@ NGTCP2_EXTERN int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_shutdown_stream` closes stream denoted by |stream_id| - * abruptly. |app_error_code| is one of application error codes, and - * indicates the reason of shutdown. Successful call of this function - * does not immediately erase the state of the stream. The actual - * deletion is done when the remote endpoint sends acknowledgement. - * Calling this function is equivalent to call + * `ngtcp2_conn_shutdown_stream` closes a stream denoted by + * |stream_id| abruptly. |app_error_code| is one of application error + * codes, and indicates the reason of shutdown. Successful call of + * this function does not immediately erase the state of the stream. + * The actual deletion is done when the remote endpoint sends + * acknowledgement. Calling this function is equivalent to call * `ngtcp2_conn_shutdown_stream_read`, and - * `ngtcp2_conn_shutdown_stream_write` sequentially. + * `ngtcp2_conn_shutdown_stream_write` sequentially with the following + * differences. If |stream_id| refers to a local unidirectional + * stream, this function only shutdowns write side of the stream. If + * |stream_id| refers to a remote unidirectional stream, this function + * only shutdowns read side of the stream. + * + * |flags| is currently unused, and should be set to 0. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4295,46 +4275,56 @@ NGTCP2_EXTERN int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, * :macro:`NGTCP2_ERR_NOMEM` * Out of memory */ -NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, +NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, uint64_t app_error_code); /** * @function * - * `ngtcp2_conn_shutdown_stream_write` closes write-side of stream + * `ngtcp2_conn_shutdown_stream_write` closes write-side of a stream * denoted by |stream_id| abruptly. |app_error_code| is one of * application error codes, and indicates the reason of shutdown. If - * this function succeeds, no application data is sent to the remote - * endpoint. It discards all data which has not been acknowledged - * yet. + * this function succeeds, no further application data is sent to the + * remote endpoint. It discards all data which has not been + * acknowledged yet. + * + * |flags| is currently unused, and should be set to 0. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * |stream_id| refers to a remote unidirectional stream. */ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, + uint32_t flags, int64_t stream_id, uint64_t app_error_code); /** * @function * - * `ngtcp2_conn_shutdown_stream_read` closes read-side of stream + * `ngtcp2_conn_shutdown_stream_read` closes read-side of a stream * denoted by |stream_id| abruptly. |app_error_code| is one of * application error codes, and indicates the reason of shutdown. If - * this function succeeds, no application data is forwarded to an - * application layer. + * this function succeeds, no further application data is forwarded to + * an application layer. + * + * |flags| is currently unused, and should be set to 0. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * |stream_id| refers to a local unidirectional stream. */ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, + uint32_t flags, int64_t stream_id, uint64_t app_error_code); @@ -4355,15 +4345,15 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, * @macro * * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` indicates that more data may - * come and should be coalesced into the same packet if possible. + * come, and should be coalesced into the same packet if possible. */ #define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01u /** * @macro * - * :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` indicates that the passed - * data is the final part of a stream. + * :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` indicates that a passed data + * is the final part of a stream. */ #define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02u @@ -4384,20 +4374,21 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * @function * * `ngtcp2_conn_writev_stream` writes a packet containing stream data - * of stream denoted by |stream_id|. The buffer of the packet is + * of a stream denoted by |stream_id|. The buffer of the packet is * pointed by |dest| of length |destlen|. This function performs QUIC * handshake as well. * * |destlen| should be at least - * :member:`ngtcp2_settings.max_udp_payload_size`. + * :member:`ngtcp2_settings.max_tx_udp_payload_size`. * * Specifying -1 to |stream_id| means no new stream data to send. * * If |path| is not ``NULL``, this function stores the network path - * with which the packet should be sent. Each addr field must point - * to the buffer which should be at least ``sizeof(struct - * sockaddr_storage)`` bytes long. The assignment might not be done - * if nothing is written to |dest|. + * with which the packet should be sent. Each addr field + * (:member:`ngtcp2_path.local` and :member:`ngtcp2_path.remote`) must + * point to the buffer which should be at least + * sizeof(:type:`sockaddr_union`) bytes long. The assignment might + * not be done if nothing is written to |dest|. * * If |pi| is not ``NULL``, this function stores packet metadata in it * if it succeeds. The metadata includes ECN markings. When calling @@ -4405,7 +4396,10 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * :macro:`NGTCP2_ERR_WRITE_MORE`, caller must pass the same |pi| to * this function. * - * If the all given data is encoded as STREAM frame in |dest|, and if + * Stream data is specified as vector of data |datav|. |datavcnt| + * specifies the number of :type:`ngtcp2_vec` that |datav| includes. + * + * If all given data is encoded as STREAM frame in |dest|, and if * |flags| & :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` is nonzero, fin * flag is set to outgoing STREAM frame. Otherwise, fin flag in * STREAM frame is not set. @@ -4422,49 +4416,67 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * The number of data encoded in STREAM frame is stored in |*pdatalen| * if it is not ``NULL``. The caller must keep the portion of data * covered by |*pdatalen| bytes in tact until - * :type:`ngtcp2_acked_stream_data_offset` indicates that they are - * acknowledged by a remote endpoint or the stream is closed. - * - * If |flags| equals to :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE`, this - * function produces a single payload of UDP packet. If the given - * stream data is small (e.g., few bytes), the packet might be - * severely under filled. Too many small packet might increase - * overall packet processing costs. Unless there are retransmissions, - * by default, application can only send 1 STREAM frame in one QUIC - * packet. In order to include more than 1 STREAM frame in one QUIC - * packet, specify :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` in |flags|. - * This is analogous to ``MSG_MORE`` flag in :manpage:`send(2)`. If - * the :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` is used, there are 4 + * :member:`ngtcp2_callbacks.acked_stream_data_offset` indicates that + * they are acknowledged by a remote endpoint or the stream is closed. + * + * If the given stream data is small (e.g., few bytes), the packet + * might be severely under filled. Too many small packet might + * increase overall packet processing costs. Unless there are + * retransmissions, by default, application can only send 1 STREAM + * frame in one QUIC packet. In order to include more than 1 STREAM + * frame in one QUIC packet, specify + * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` in |flags|. This is + * analogous to ``MSG_MORE`` flag in :manpage:`send(2)`. If the + * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` is used, there are 4 * outcomes: * * - The function returns the written length of packet just like * without :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE`. This is because - * packet is nearly full and the library decided to make a complete - * packet. |*pdatalen| might be -1 or >= 0. + * packet is nearly full, and the library decided to make a complete + * packet. |*pdatalen| might be -1 or >= 0. It may return 0 which + * indicates that no packet transmission is possible at the moment + * for some reason. * * - The function returns :macro:`NGTCP2_ERR_WRITE_MORE`. In this - * case, |*pdatalen| >= 0 is asserted. This indicates that - * application can call this function with different stream data (or - * `ngtcp2_conn_writev_datagram` if it has data to send in + * case, |*pdatalen| >= 0 is asserted. It indicates that + * application can still call this function with different stream + * data (or `ngtcp2_conn_writev_datagram` if it has data to send in * unreliable datagram) to pack them into the same packet. * Application has to specify the same |conn|, |path|, |pi|, |dest|, * |destlen|, and |ts| parameters, otherwise the behaviour is * undefined. The application can change |flags|. * - * - The function returns :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED` which - * indicates that stream is blocked because of flow control. - * - * - The other error might be returned just like without - * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE`. + * - The function returns one of the following negative error codes: + * :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED`, + * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND`, or + * :macro:`NGTCP2_ERR_STREAM_SHUT_WR`. In this case, |*pdatalen| == + * -1 is asserted. Application can still write the stream data of + * the other streams by calling this function (or + * `ngtcp2_conn_writev_datagram` if it has data to send in + * unreliable datagram) to pack them into the same packet. + * Application has to specify the same |conn|, |path|, |pi|, |dest|, + * |destlen|, and |ts| parameters, otherwise the behaviour is + * undefined. The application can change |flags|. * - * When application sees :macro:`NGTCP2_ERR_WRITE_MORE`, it must not - * call other ngtcp2 API functions (application can still call - * `ngtcp2_conn_write_connection_close` to handle error from this - * function). Just keep calling `ngtcp2_conn_writev_stream`, - * `ngtcp2_conn_write_pkt`, or `ngtcp2_conn_writev_datagram` until it - * returns a positive number (which indicates a complete packet is - * ready). If there is no stream data to include, call this function - * with |stream_id| as -1 to stop coalescing and write a packet. + * - The other negative error codes might be returned just like + * without :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE`. These errors + * should be treated as a connection error. + * + * When application uses :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` at + * least once, it must not call other ngtcp2 API functions + * (application can still call `ngtcp2_conn_write_connection_close` to + * handle error from this function. It can also call + * `ngtcp2_conn_shutdown_stream_read`, + * `ngtcp2_conn_shutdown_stream_write`, and + * `ngtcp2_conn_shutdown_stream`), just keep calling this function (or + * `ngtcp2_conn_writev_datagram`) until it returns 0, a positive + * number (which indicates a complete packet is ready), or the error + * codes other than :macro:`NGTCP2_ERR_WRITE_MORE`, + * :macro:`NGTCP2_ERR_STREAM_DATA_BLOCKED`, + * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND`, and + * :macro:`NGTCP2_ERR_STREAM_SHUT_WR`. If there is no stream data to + * include, call this function with |stream_id| as -1 to stop + * coalescing and write a packet. * * This function returns 0 if it cannot write any frame because buffer * is too small, or packet is congestion limited. Application should @@ -4473,11 +4485,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * This function must not be called from inside the callback * functions. * - * If pacing is enabled, `ngtcp2_conn_update_pkt_tx_time` must be - * called after this function. Application may call this function - * multiple times before calling `ngtcp2_conn_update_pkt_tx_time`. - * Packet pacing is enabled if BBR congestion controller algorithm is - * used. + * `ngtcp2_conn_update_pkt_tx_time` must be called after this + * function. Application may call this function multiple times before + * calling `ngtcp2_conn_update_pkt_tx_time`. * * This function returns the number of bytes written in |dest| if it * succeeds, or one of the following negative error codes: @@ -4501,12 +4511,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * Application can call this function to pack more stream data * into the same packet. See above to know how it works. * - * In general, if the error code which satisfies - * `ngtcp2_err_is_fatal(err) ` != 0 is returned, - * the application should just close the connection by calling - * `ngtcp2_conn_write_connection_close` or just delete the QUIC - * connection using `ngtcp2_conn_del`. It is undefined to call the - * other library functions. + * If any other negative error is returned, call + * `ngtcp2_conn_write_connection_close` to get terminal packet, and + * sending it makes QUIC connection enter the closing state. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -4531,10 +4538,23 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * @macro * * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_MORE` indicates that more data - * may come and should be coalesced into the same packet if possible. + * may come, and should be coalesced into the same packet if possible. */ #define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01u +/** + * @function + * + * `ngtcp2_conn_write_datagram` is just like + * `ngtcp2_conn_writev_datagram`. The only difference is that it + * conveniently accepts a single buffer. + */ +NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_datagram_versioned( + ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, + ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted, + uint32_t flags, uint64_t dgram_id, const uint8_t *data, size_t datalen, + ngtcp2_tstamp ts); + /** * @function * @@ -4544,25 +4564,28 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * as well. * * |destlen| should be at least - * :member:`ngtcp2_settings.max_udp_payload_size`. + * :member:`ngtcp2_settings.max_tx_udp_payload_size`. * * For |path| and |pi| parameters, refer to * `ngtcp2_conn_writev_stream`. * + * Stream data is specified as vector of data |datav|. |datavcnt| + * specifies the number of :type:`ngtcp2_vec` that |datav| includes. + * * If the given data is written to the buffer, nonzero value is * assigned to |*paccepted| if it is not NULL. The data in DATAGRAM * frame cannot be fragmented; writing partial data is not possible. * * |dgram_id| is an opaque identifier which should uniquely identify - * the given DATAGRAM. It is passed to :type:`ngtcp2_ack_datagram` - * callback when a packet that contains DATAGRAM frame is - * acknowledged. It is passed to :type:`ngtcp2_lost_datagram` - * callback when a packet that contains DATAGRAM frame is declared - * lost. If an application uses neither of those callbacks, it can - * sets 0 to this parameter. + * the given DATAGRAM data. It is passed to + * :member:`ngtcp2_callbacks.ack_datagram` callback when a packet that + * contains DATAGRAM frame is acknowledged. It is also passed to + * :member:`ngtcp2_callbacks.lost_datagram` callback when a packet + * that contains DATAGRAM frame is declared lost. If an application + * uses neither of those callbacks, it can sets 0 to this parameter. * - * This function might write other frames other than DATAGRAM, just - * like `ngtcp2_conn_writev_stream`. + * This function might write other frames other than DATAGRAM frame, + * just like `ngtcp2_conn_writev_stream`. * * If the function returns 0, it means that no more data cannot be * sent because of congestion control limit; or, data does not fit @@ -4593,10 +4616,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * When application sees :macro:`NGTCP2_ERR_WRITE_MORE`, it must not * call other ngtcp2 API functions (application can still call * `ngtcp2_conn_write_connection_close` to handle error from this - * function). Just keep calling `ngtcp2_conn_writev_datagram`, - * `ngtcp2_conn_writev_stream` or `ngtcp2_conn_write_pkt` until it - * returns a positive number (which indicates a complete packet is - * ready). + * function. It can also call `ngtcp2_conn_shutdown_stream_read`, + * `ngtcp2_conn_shutdown_stream_write`, and + * `ngtcp2_conn_shutdown_stream`). Just keep calling this function + * (or `ngtcp2_conn_writev_stream`) until it returns a positive number + * (which indicates a complete packet is ready). * * This function returns the number of bytes written in |dest| if it * succeeds, or one of the following negative error codes: @@ -4617,12 +4641,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * The provisional DATAGRAM frame size exceeds the maximum * DATAGRAM frame size that a remote endpoint can receive. * - * In general, if the error code which satisfies - * `ngtcp2_err_is_fatal(err) ` != 0 is returned, - * the application should just close the connection by calling - * `ngtcp2_conn_write_connection_close` or just delete the QUIC - * connection using `ngtcp2_conn_del`. It is undefined to call the - * other library functions. + * If any other negative error is returned, call + * `ngtcp2_conn_write_connection_close` to get terminal packet, and + * sending it makes QUIC connection enter the closing state. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, @@ -4633,30 +4654,34 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( /** * @function * - * `ngtcp2_conn_is_in_closing_period` returns nonzero if |conn| is in - * the closing period. + * `ngtcp2_conn_in_closing_period` returns nonzero if |conn| is in the + * closing period. */ -NGTCP2_EXTERN int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn); +NGTCP2_EXTERN int ngtcp2_conn_in_closing_period(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_is_in_draining_period` returns nonzero if |conn| is in + * `ngtcp2_conn_in_draining_period` returns nonzero if |conn| is in * the draining period. */ -NGTCP2_EXTERN int ngtcp2_conn_is_in_draining_period(ngtcp2_conn *conn); +NGTCP2_EXTERN int ngtcp2_conn_in_draining_period(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_extend_max_stream_offset` extends stream's max stream - * data value by |datalen|. + * `ngtcp2_conn_extend_max_stream_offset` extends the maximum stream + * data that a remote endpoint can send by |datalen|. |stream_id| + * specifies the stream ID. This function only extends stream-level + * flow control window. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory. + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * |stream_id| refers to a local unidirectional stream. */ NGTCP2_EXTERN int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, @@ -4666,7 +4691,8 @@ NGTCP2_EXTERN int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_extend_max_offset` extends max data offset by - * |datalen|. + * |datalen|. This function only extends connection-level flow + * control window. */ NGTCP2_EXTERN void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, uint64_t datalen); @@ -4675,12 +4701,13 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_extend_max_streams_bidi` extends the number of maximum - * local bidirectional streams that a remote endpoint can open by |n|. + * remote bidirectional streams that a remote endpoint can open by + * |n|. * * The library does not increase maximum stream limit automatically. * The exception is when a stream is closed without - * :type:`ngtcp2_stream_open` callback being called. In this case, - * stream limit is increased automatically. + * :member:`ngtcp2_callbacks.stream_open` callback being called. In + * this case, stream limit is increased automatically. */ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_bidi(ngtcp2_conn *conn, size_t n); @@ -4689,13 +4716,13 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_bidi(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_extend_max_streams_uni` extends the number of maximum - * local unidirectional streams that a remote endpoint can open by + * remote unidirectional streams that a remote endpoint can open by * |n|. * * The library does not increase maximum stream limit automatically. * The exception is when a stream is closed without - * :type:`ngtcp2_stream_open` callback being called. In this case, - * stream limit is increased automatically. + * :member:`ngtcp2_callbacks.stream_open` callback being called. In + * this case, stream limit is increased automatically. */ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, size_t n); @@ -4703,9 +4730,10 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_get_dcid` returns the non-NULL pointer to destination - * connection ID. If no destination connection ID is present, the - * return value is not ``NULL``, and its datalen field is 0. + * `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 + * ` field is 0. */ NGTCP2_EXTERN const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn); @@ -4714,7 +4742,9 @@ NGTCP2_EXTERN const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn); * * `ngtcp2_conn_get_client_initial_dcid` returns the non-NULL pointer * to the Destination Connection ID that client sent in its Initial - * packet. + * packet. If the Destination Connection ID is not present, the + * return value is not ``NULL``, and its :member:`datalen + * ` field is 0. */ NGTCP2_EXTERN const ngtcp2_cid * ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn); @@ -4722,31 +4752,17 @@ ngtcp2_conn_get_client_initial_dcid(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_num_scid` returns the number of source connection - * IDs which the local endpoint has provided to the peer and have not - * retired. - */ -NGTCP2_EXTERN size_t ngtcp2_conn_get_num_scid(ngtcp2_conn *conn); - -/** - * @function - * - * `ngtcp2_conn_get_scid` writes the all source connection IDs which - * the local endpoint has provided to the peer and have not retired in - * |dest|. The buffer pointed by |dest| must have - * ``sizeof(ngtcp2_cid) * n`` bytes available, where n is the return - * value of `ngtcp2_conn_get_num_scid()`. + * `ngtcp2_conn_get_scid` writes the 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_scid` + * with |dest| == NULL. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest); -/** - * @function - * - * `ngtcp2_conn_get_num_active_dcid` returns the number of the active - * destination connection ID. - */ -NGTCP2_EXTERN size_t ngtcp2_conn_get_num_active_dcid(ngtcp2_conn *conn); - /** * @struct * @@ -4763,8 +4779,8 @@ typedef struct ngtcp2_cid_token { */ ngtcp2_cid cid; /** - * :member:`ps` is the path which is associated to this Connection - * ID. + * :member:`ps` is the path which this Connection ID is associated + * with. */ ngtcp2_path_storage ps; /** @@ -4782,10 +4798,15 @@ typedef struct ngtcp2_cid_token { /** * @function * - * `ngtcp2_conn_get_active_dcid` writes the all active destination - * connection IDs and tokens to |dest|. The buffer pointed by |dest| - * must have ``sizeof(ngtcp2_cid_token) * n`` bytes available, where n - * is the return value of `ngtcp2_conn_get_num_active_dcid()`. + * `ngtcp2_conn_get_active_dcid` writes the 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_token`) * n bytes available, where n is + * the return value of `ngtcp2_conn_get_active_dcid` with |dest| == + * NULL. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest); @@ -4801,7 +4822,8 @@ NGTCP2_EXTERN uint32_t ngtcp2_conn_get_client_chosen_version(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_negotiated_version` returns the negotiated version. + * `ngtcp2_conn_get_negotiated_version` returns the negotiated + * version. * * Until the version is negotiated, this function returns 0. */ @@ -4810,44 +4832,59 @@ NGTCP2_EXTERN uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_early_data_rejected` tells |conn| that early data was - * rejected by a server. |conn| discards the following connection - * states: + * `ngtcp2_conn_tls_early_data_rejected` tells |conn| that early data + * was rejected by a server during TLS handshake, or client decided + * not to attempt early data for some reason. |conn| discards the + * following connection states: * - * - Any opended streams. + * - Any opened streams. * - Stream identifier allocations. * - Max data extended by `ngtcp2_conn_extend_max_offset`. * - Max bidi streams extended by `ngtcp2_conn_extend_max_streams_bidi`. * - Max uni streams extended by `ngtcp2_conn_extend_max_streams_uni`. * * Application which wishes to retransmit early data, it has to open - * streams and send stream data again. + * streams, and send stream data again. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` + * User callback failed + */ +NGTCP2_EXTERN int ngtcp2_conn_tls_early_data_rejected(ngtcp2_conn *conn); + +/** + * @function + * + * `ngtcp2_conn_get_tls_early_data_rejected` returns nonzero if + * `ngtcp2_conn_tls_early_data_rejected` has been called. */ -NGTCP2_EXTERN void ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn); +NGTCP2_EXTERN int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_conn_stat` assigns connection statistics data to - * |*cstat|. + * `ngtcp2_conn_get_conn_info` assigns connection statistics data to + * |*cinfo|. */ -NGTCP2_EXTERN void ngtcp2_conn_get_conn_stat_versioned(ngtcp2_conn *conn, - int conn_stat_version, - ngtcp2_conn_stat *cstat); +NGTCP2_EXTERN void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn, + int conn_info_version, + ngtcp2_conn_info *cinfo); /** * @function * - * `ngtcp2_conn_submit_crypto_data` submits crypto stream data |data| - * of length |datalen| to the library for transmission. The - * encryption level is given in |crypto_level|. + * `ngtcp2_conn_submit_crypto_data` submits crypto data |data| of + * length |datalen| to the library for transmission. + * |encryption_level| specifies the encryption level of data. * * The library makes a copy of the buffer pointed by |data| of length * |datalen|. Application can discard |data|. */ NGTCP2_EXTERN int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, const uint8_t *data, const size_t datalen); /** @@ -4874,7 +4911,8 @@ NGTCP2_EXTERN int ngtcp2_conn_submit_new_token(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_set_local_addr` sets local endpoint address |addr| to - * the current path of |conn|. + * the current path of |conn|. This function is provided for testing + * purpose only. */ NGTCP2_EXTERN void ngtcp2_conn_set_local_addr(ngtcp2_conn *conn, const ngtcp2_addr *addr); @@ -4898,34 +4936,34 @@ NGTCP2_EXTERN const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_max_udp_payload_size` returns the maximum UDP + * `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_udp_payload_size` that is + * value of :member:`ngtcp2_settings.max_tx_udp_payload_size` that is * passed to `ngtcp2_conn_client_new` or `ngtcp2_conn_server_new`. */ -NGTCP2_EXTERN size_t ngtcp2_conn_get_max_udp_payload_size(ngtcp2_conn *conn); +NGTCP2_EXTERN size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_path_max_udp_payload_size` returns the maximum UDP - * payload size for the current path. If - * :member:`ngtcp2_settings.no_udp_payload_size_shaping` is set to + * `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 * nonzero, this function is equivalent to - * `ngtcp2_conn_get_max_udp_payload_size`. Otherwise, it returns the - * maximum UDP payload size that is probed for the current path. + * `ngtcp2_conn_get_max_tx_udp_payload_size`. Otherwise, it returns + * the maximum UDP payload size that is probed for the current path. */ NGTCP2_EXTERN size_t -ngtcp2_conn_get_path_max_udp_payload_size(ngtcp2_conn *conn); +ngtcp2_conn_get_path_max_tx_udp_payload_size(ngtcp2_conn *conn); /** * @function * * `ngtcp2_conn_initiate_immediate_migration` starts connection - * migration to the given |path|. - * Only client can initiate migration. This function does - * immediate migration; it does not probe peer reachability from a new - * local address. + * migration to the given |path|. Only client can initiate migration. + * This function does immediate migration; while the path validation + * is nonetheless performed, this function does not wait for it to + * succeed. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -4936,7 +4974,8 @@ ngtcp2_conn_get_path_max_udp_payload_size(ngtcp2_conn *conn); * :macro:`NGTCP2_ERR_CONN_ID_BLOCKED` * No unused connection ID is available. * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` - * |local_addr| equals the current local address. + * :member:`local ` field of |path| equals the + * current local address. * :macro:`NGTCP2_ERR_NOMEM` * Out of memory */ @@ -4949,7 +4988,7 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_immediate_migration( * `ngtcp2_conn_initiate_migration` starts connection migration to the * given |path|. Only client can initiate migration. Unlike * `ngtcp2_conn_initiate_immediate_migration`, this function starts a - * path validation with a new path and migrate to the new path after + * path validation with a new path, and migrate to the new path after * successful path validation. * * This function returns 0 if it succeeds, or one of the following @@ -4961,7 +5000,8 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_immediate_migration( * :macro:`NGTCP2_ERR_CONN_ID_BLOCKED` * No unused connection ID is available. * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` - * |local_addr| equals the current local address. + * :member:`local ` field of |path| equals the + * current local address. * :macro:`NGTCP2_ERR_NOMEM` * Out of memory */ @@ -4969,19 +5009,12 @@ NGTCP2_EXTERN int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_tstamp ts); -/** - * @function - * - * `ngtcp2_conn_get_max_local_streams_uni` returns the cumulative - * number of streams which local endpoint can open. - */ -NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_local_streams_uni(ngtcp2_conn *conn); - /** * @function * * `ngtcp2_conn_get_max_data_left` returns the number of bytes that - * this local endpoint can send in this connection. + * this local endpoint can send in this connection without violating + * connection-level flow control. */ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn); @@ -4990,7 +5023,8 @@ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn); * * `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|. If no such stream is found, this function returns 0. + * |stream_id| without violating stream-level flow control. If no + * such stream is found, this function returns 0. */ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_stream_data_left(ngtcp2_conn *conn, int64_t stream_id); @@ -5046,7 +5080,7 @@ ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_crypto_ctx` sets |ctx| for Handshake/1RTT packet + * `ngtcp2_conn_set_crypto_ctx` sets |ctx| for Handshake/1-RTT packet * encryption. The passed data will be passed to * :type:`ngtcp2_encrypt`, :type:`ngtcp2_decrypt` and * :type:`ngtcp2_hp_mask` callbacks. @@ -5057,114 +5091,113 @@ NGTCP2_EXTERN void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_get_tls_native_handle` returns TLS native handle set by - * `ngtcp2_conn_set_tls_native_handle()`. + * `ngtcp2_conn_get_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` + * object for Handshake/1-RTT packet encryption. */ -NGTCP2_EXTERN void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn); +NGTCP2_EXTERN const ngtcp2_crypto_ctx * +ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_tls_native_handle` sets TLS native handle - * |tls_native_handle| to |conn|. Internally, it is used as an opaque - * pointer. + * `ngtcp2_conn_set_0rtt_crypto_ctx` sets |ctx| for 0-RTT packet + * encryption. The passed data will be passed to + * :type:`ngtcp2_encrypt`, :type:`ngtcp2_decrypt` and + * :type:`ngtcp2_hp_mask` callbacks. */ -NGTCP2_EXTERN void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, - void *tls_native_handle); +NGTCP2_EXTERN void +ngtcp2_conn_set_0rtt_crypto_ctx(ngtcp2_conn *conn, + const ngtcp2_crypto_ctx *ctx); /** * @function * - * `ngtcp2_conn_set_retry_aead` sets |aead| and |aead_ctx| for Retry - * integrity tag verification. |aead| must be AEAD_AES_128_GCM. - * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as - * encryption key. This function must be called if |conn| is - * initialized as client. Server does not verify the tag and has no - * need to call this function. - * - * If this function succeeds, |conn| takes ownership of |aead_ctx|. - * :type:`ngtcp2_delete_crypto_aead_ctx` will be called to delete this - * object when it is no longer used. If this function fails, the - * caller is responsible to delete it. + * `ngtcp2_conn_get_0rtt_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` + * object for 0-RTT packet encryption. */ -NGTCP2_EXTERN void -ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, const ngtcp2_crypto_aead *aead, - const ngtcp2_crypto_aead_ctx *aead_ctx); +NGTCP2_EXTERN const ngtcp2_crypto_ctx * +ngtcp2_conn_get_0rtt_crypto_ctx(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_crypto_ctx` returns :type:`ngtcp2_crypto_ctx` - * object for Handshake/1RTT packet encryption. + * `ngtcp2_conn_get_tls_native_handle` returns TLS native handle set + * by `ngtcp2_conn_set_tls_native_handle`. */ -NGTCP2_EXTERN const ngtcp2_crypto_ctx * -ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn); +NGTCP2_EXTERN void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_set_early_crypto_ctx` sets |ctx| for 0RTT packet - * encryption. The passed data will be passed to - * :type:`ngtcp2_encrypt`, :type:`ngtcp2_decrypt` and - * :type:`ngtcp2_hp_mask` callbacks. + * `ngtcp2_conn_set_tls_native_handle` sets TLS native handle + * |tls_native_handle| to |conn|. Internally, it is used as an opaque + * pointer. */ -NGTCP2_EXTERN void -ngtcp2_conn_set_early_crypto_ctx(ngtcp2_conn *conn, - const ngtcp2_crypto_ctx *ctx); +NGTCP2_EXTERN void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, + void *tls_native_handle); /** * @function * - * `ngtcp2_conn_get_early_crypto_ctx` returns - * :type:`ngtcp2_crypto_ctx` object for 0RTT packet encryption. + * `ngtcp2_conn_set_retry_aead` sets |aead| and |aead_ctx| for Retry + * integrity tag verification. |aead| must be AEAD_AES_128_GCM. + * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as + * encryption key. This function must be called if |conn| is + * initialized as client. Server does not verify the tag, and has no + * need to call this function. + * + * |conn| takes ownership of |aead_ctx|. + * :member:`ngtcp2_callbacks.delete_crypto_aead_ctx` will be called to + * delete this object when it is no longer used. */ -NGTCP2_EXTERN const ngtcp2_crypto_ctx * -ngtcp2_conn_get_early_crypto_ctx(ngtcp2_conn *conn); +NGTCP2_EXTERN void +ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, const ngtcp2_crypto_aead *aead, + const ngtcp2_crypto_aead_ctx *aead_ctx); /** * @enum * - * :type:`ngtcp2_connection_close_error_code_type` defines connection - * error code type. + * :type:`ngtcp2_ccerr_type` defines connection error type. */ -typedef enum ngtcp2_connection_close_error_code_type { +typedef enum ngtcp2_ccerr_type { /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT` - * indicates the error code is QUIC transport error code. + * :enum:`NGTCP2_CCERR_TYPE_TRANSPORT` indicates the QUIC transport + * error, and the error code is QUIC transport error code. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT, + NGTCP2_CCERR_TYPE_TRANSPORT, /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION` - * indicates the error code is application error code. + * :enum:`NGTCP2_CCERR_TYPE_APPLICATION` indicates an application + * error, and the error code is application error code. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION, + NGTCP2_CCERR_TYPE_APPLICATION, /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION` - * is a special case of QUIC transport error, and it indicates that - * client receives Version Negotiation packet. + * :enum:`NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION` is a special case + * of QUIC transport error, and it indicates that client receives + * Version Negotiation packet. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION, + NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION, /** - * :enum:`NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE` - * is a special case of QUIC transport error, and it indicates that - * connection is closed because of idle timeout. + * :enum:`NGTCP2_CCERR_TYPE_IDLE_CLOSE` is a special case of QUIC + * transport error, and it indicates that connection is closed + * because of idle timeout. */ - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE -} ngtcp2_connection_close_error_code_type; + NGTCP2_CCERR_TYPE_IDLE_CLOSE +} ngtcp2_ccerr_type; /** * @struct * - * :type:`ngtcp2_connection_close_error` contains connection - * error code, its type, and the optional reason phrase. + * :type:`ngtcp2_ccerr` contains connection error code, its type, a + * frame type that caused this error, and the optional reason phrase. */ -typedef struct ngtcp2_connection_close_error { +typedef struct ngtcp2_ccerr { /** - * :member:`type` is the type of :member:`error_code`. + * :member:`type` is the type of this error. */ - ngtcp2_connection_close_error_code_type type; + ngtcp2_ccerr_type type; /** * :member:`error_code` is the error code for connection closure. + * Its interpretation depends on :member:`type`. */ uint64_t error_code; /** @@ -5179,109 +5212,106 @@ typedef struct ngtcp2_connection_close_error { * received from a remote endpoint, it is truncated to at most 1024 * bytes. */ - uint8_t *reason; + const uint8_t *reason; /** * :member:`reasonlen` is the length of data pointed by * :member:`reason`. */ size_t reasonlen; -} ngtcp2_connection_close_error; +} ngtcp2_ccerr; /** * @function * - * `ngtcp2_connection_close_error_default` initializes |ccerr| with - * the default values. It sets the following fields: + * `ngtcp2_ccerr_default` initializes |ccerr| with the default values. + * It sets the following fields: * - * - :member:`type ` = - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT` - * - :member:`error_code ` = + * - :member:`type ` = + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT` + * - :member:`error_code ` = * :macro:`NGTCP2_NO_ERROR`. - * - :member:`frame_type ` = - * 0 - * - :member:`reason ` = NULL - * - :member:`reasonlen ` = 0 + * - :member:`frame_type ` = 0 + * - :member:`reason ` = NULL + * - :member:`reasonlen ` = 0 */ -NGTCP2_EXTERN void -ngtcp2_connection_close_error_default(ngtcp2_connection_close_error *ccerr); +NGTCP2_EXTERN void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr); /** * @function * - * `ngtcp2_connection_close_error_set_transport_error` sets - * :member:`ccerr->type ` to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * and :member:`ccerr->error_code - * ` to |error_code|. - * |reason| is the reason phrase of length |reasonlen|. This function - * does not make a copy of the reason phrase. + * `ngtcp2_ccerr_set_transport_error` sets :member:`ccerr->type + * ` to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, and + * :member:`ccerr->error_code ` to + * |error_code|. |reason| is the reason phrase of length |reasonlen|. + * This function does not make a copy of the reason phrase. */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_transport_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_transport_error(ngtcp2_ccerr *ccerr, + uint64_t error_code, + const uint8_t *reason, + size_t reasonlen); /** * @function * - * `ngtcp2_connection_close_error_set_transport_error_liberr` sets - * type and error_code based on |liberr|. + * `ngtcp2_ccerr_set_liberr` sets type and error_code based on + * |liberr|. + * + * |reason| is the reason phrase of length |reasonlen|. This function + * does not make a copy of the reason phrase. * * If |liberr| is :macro:`NGTCP2_ERR_RECV_VERSION_NEGOTIATION`, - * :member:`ccerr->type ` is set - * to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION`, - * and :member:`ccerr->error_code - * ` to - * :macro:`NGTCP2_NO_ERROR`. If |liberr| is - * :macro:`NGTCP2_ERR_IDLE_CLOSE`, :member:`ccerr->type - * ` is set to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE`, - * and :member:`ccerr->error_code - * ` to - * :macro:`NGTCP2_NO_ERROR`. Otherwise, :member:`ccerr->type - * ` is set to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * and :member:`ccerr->error_code - * ` is set to an error code - * inferred by |liberr| (see - * `ngtcp2_err_infer_quic_transport_error_code`). |reason| is the - * reason phrase of length |reasonlen|. This function does not make a - * copy of the reason phrase. + * :member:`ccerr->type ` is set to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION`, + * and :member:`ccerr->error_code ` to + * :macro:`NGTCP2_NO_ERROR`. + * + * If |liberr| is :macro:`NGTCP2_ERR_IDLE_CLOSE`, :member:`ccerr->type + * ` is set to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_IDLE_CLOSE`, and + * :member:`ccerr->error_code ` to + * :macro:`NGTCP2_NO_ERROR`. + * + * Otherwise, :member:`ccerr->type ` is set to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, and + * :member:`ccerr->error_code ` is set to an + * error code inferred by |liberr| (see + * `ngtcp2_err_infer_quic_transport_error_code`). */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_transport_error_liberr( - ngtcp2_connection_close_error *ccerr, int liberr, const uint8_t *reason, - size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_liberr(ngtcp2_ccerr *ccerr, int liberr, + const uint8_t *reason, + size_t reasonlen); /** * @function * - * `ngtcp2_connection_close_error_set_transport_error_tls_alert` sets - * :member:`ccerr->type ` to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * and :member:`ccerr->error_code - * ` to bitwise-OR of - * :macro:`NGTCP2_CRYPTO_ERROR` and |tls_alert|. |reason| is the + * `ngtcp2_ccerr_set_tls_alert` sets :member:`ccerr->type + * ` to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, and + * :member:`ccerr->error_code ` to bitwise-OR + * of :macro:`NGTCP2_CRYPTO_ERROR` and |tls_alert|. |reason| is the * reason phrase of length |reasonlen|. This function does not make a * copy of the reason phrase. */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_transport_error_tls_alert( - ngtcp2_connection_close_error *ccerr, uint8_t tls_alert, - const uint8_t *reason, size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_tls_alert(ngtcp2_ccerr *ccerr, + uint8_t tls_alert, + const uint8_t *reason, + size_t reasonlen); /** * @function * - * `ngtcp2_connection_close_error_set_application_error` sets - * :member:`ccerr->type ` to - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION`, - * and :member:`ccerr->error_code - * ` to |error_code|. - * |reason| is the reason phrase of length |reasonlen|. This function - * does not make a copy of the reason phrase. + * `ngtcp2_ccerr_set_application_error` sets :member:`ccerr->type + * ` to + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_APPLICATION`, and + * :member:`ccerr->error_code ` to + * |error_code|. |reason| is the reason phrase of length |reasonlen|. + * This function does not make a copy of the reason phrase. */ -NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen); +NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr, + uint64_t error_code, + const uint8_t *reason, + size_t reasonlen); /** * @function @@ -5295,20 +5325,20 @@ NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( * * If |path| is not ``NULL``, this function stores the network path * with which the packet should be sent. Each addr field must point - * to the buffer which should be at least ``sizeof(struct - * sockaddr_storage)`` bytes long. The assignment might not be done - * if nothing is written to |dest|. + * to the buffer which should be at least + * sizeof(:type:`ngtcp2_sockaddr_union`) bytes long. The assignment + * might not be done if nothing is written to |dest|. * * If |pi| is not ``NULL``, this function stores packet metadata in it * if it succeeds. The metadata includes ECN markings. * - * If :member:`ccerr->type ` == - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT`, - * this function sends CONNECTION_CLOSE (type 0x1c) frame. If - * :member:`ccerr->type ` == - * :enum:`ngtcp2_connection_close_error_code_type.NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION`, - * it sends CONNECTION_CLOSE (type 0x1d) frame. Otherwise, it does - * not produce any data, and returns 0. + * If :member:`ccerr->type ` == + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, this + * function sends CONNECTION_CLOSE (type 0x1c) frame. If + * :member:`ccerr->type ` == + * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_APPLICATION`, it sends + * CONNECTION_CLOSE (type 0x1d) frame. Otherwise, it does not produce + * any data, and returns 0. * * This function must not be called from inside the callback * functions. @@ -5325,7 +5355,8 @@ NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( * :macro:`NGTCP2_ERR_NOBUF` * Buffer is too small * :macro:`NGTCP2_ERR_INVALID_STATE` - * The current state does not allow sending CONNECTION_CLOSE. + * The current state does not allow sending CONNECTION_CLOSE + * frame. * :macro:`NGTCP2_ERR_PKT_NUM_EXHAUSTED` * Packet number is exhausted, and cannot send any more packet. * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` @@ -5334,23 +5365,22 @@ NGTCP2_EXTERN void ngtcp2_connection_close_error_set_application_error( NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - const ngtcp2_connection_close_error *ccerr, ngtcp2_tstamp ts); + const ngtcp2_ccerr *ccerr, ngtcp2_tstamp ts); /** * @function * - * `ngtcp2_conn_get_connection_close_error` stores the received - * connection close error in |ccerr|. + * `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`. */ -NGTCP2_EXTERN void -ngtcp2_conn_get_connection_close_error(ngtcp2_conn *conn, - ngtcp2_connection_close_error *ccerr); +NGTCP2_EXTERN const ngtcp2_ccerr *ngtcp2_conn_get_ccerr(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_is_local_stream` returns nonzero if |stream_id| denotes the - * stream which a local endpoint issues. + * `ngtcp2_conn_is_local_stream` returns nonzero if |stream_id| + * denotes a locally initiated stream. */ NGTCP2_EXTERN int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id); @@ -5367,7 +5397,7 @@ NGTCP2_EXTERN int ngtcp2_conn_is_server(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_after_retry` returns nonzero if |conn| as a client has - * received Retry packet from server and successfully validated it. + * received Retry packet from server, and successfully validated it. */ NGTCP2_EXTERN int ngtcp2_conn_after_retry(ngtcp2_conn *conn); @@ -5391,12 +5421,11 @@ NGTCP2_EXTERN int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_update_pkt_tx_time` sets the time instant of the next - * packet transmission. This function is noop if packet pacing is - * disabled. If packet pacing is enabled, this function must be - * called after (multiple invocation of) `ngtcp2_conn_writev_stream`. - * If packet aggregation (e.g., packet batching, GSO) is used, call - * this function after all aggregated datagrams are sent, which - * indicates multiple invocation of `ngtcp2_conn_writev_stream`. + * packet transmission to pace packets. This function must be called + * after (multiple invocation of) `ngtcp2_conn_writev_stream`. If + * packet aggregation (e.g., packet batching, GSO) is used, call this + * function after all aggregated datagrams are sent, which indicates + * multiple invocation of `ngtcp2_conn_writev_stream`. */ NGTCP2_EXTERN void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts); @@ -5405,8 +5434,7 @@ NGTCP2_EXTERN void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_get_send_quantum` returns the maximum number of bytes - * that can be sent in one go without packet spacing. If packet - * pacing is disabled, this function returns SIZE_MAX. + * that can be sent in one go without packet spacing. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn); @@ -5427,8 +5455,8 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, * * `ngtcp2_strerror` returns the text representation of |liberr|. * |liberr| must be one of ngtcp2 library error codes (which is - * defined as NGTCP2_ERR_* macro, such as - * :macro:`NGTCP2_ERR_DECRYPT`). + * defined as :macro:`NGTCP2_ERR_* ` + * macros). */ NGTCP2_EXTERN const char *ngtcp2_strerror(int liberr); @@ -5437,8 +5465,8 @@ NGTCP2_EXTERN const char *ngtcp2_strerror(int liberr); * * `ngtcp2_err_is_fatal` returns nonzero if |liberr| is a fatal error. * |liberr| must be one of ngtcp2 library error codes (which is - * defined as NGTCP2_ERR_* macro, such as - * :macro:`NGTCP2_ERR_DECRYPT`). + * defined as :macro:`NGTCP2_ERR_* ` + * macros). */ NGTCP2_EXTERN int ngtcp2_err_is_fatal(int liberr); @@ -5448,7 +5476,7 @@ NGTCP2_EXTERN int ngtcp2_err_is_fatal(int liberr); * `ngtcp2_err_infer_quic_transport_error_code` returns a QUIC * transport error code which corresponds to |liberr|. |liberr| must * be one of ngtcp2 library error codes (which is defined as - * NGTCP2_ERR_* macro, such as :macro:`NGTCP2_ERR_DECRYPT`). + * :macro:`NGTCP2_ERR_* ` macros). */ NGTCP2_EXTERN uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr); @@ -5501,7 +5529,7 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps); * @function * * `ngtcp2_settings_default` initializes |settings| with the default - * values. First this function fills |settings| with 0 and set the + * values. First this function fills |settings| with 0, and set the * default value to the following fields: * * * :type:`cc_algo ` = @@ -5509,10 +5537,10 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps); * * :type:`initial_rtt ` = * :macro:`NGTCP2_DEFAULT_INITIAL_RTT` * * :type:`ack_thresh ` = 2 - * * :type:`max_udp_payload_size - * ` = 1452 + * * :type:`max_tx_udp_payload_size + * ` = 1452 * * :type:`handshake_timeout ` = - * :macro:`NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT`. + * ``UINT64_MAX`` */ NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version, ngtcp2_settings *settings); @@ -5521,7 +5549,7 @@ NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version, * @function * * `ngtcp2_transport_params_default` initializes |params| with the - * default values. First this function fills |params| with 0 and set + * default values. First this function fills |params| with 0, and set * the default value to the following fields: * * * :type:`max_udp_payload_size @@ -5564,7 +5592,7 @@ NGTCP2_EXTERN const ngtcp2_mem *ngtcp2_mem_default(void); /** * @struct * - * :type:`ngtcp2_info` is what `ngtcp2_version()` returns. It holds + * :type:`ngtcp2_info` is what `ngtcp2_version` returns. It holds * information about the particular ngtcp2 version. */ typedef struct ngtcp2_info { @@ -5576,12 +5604,12 @@ typedef struct ngtcp2_info { int age; /** * :member:`version_num` is the :macro:`NGTCP2_VERSION_NUM` number - * (since age ==1) + * (since :member:`age` ==1) */ int version_num; /** * :member:`version_str` points to the :macro:`NGTCP2_VERSION` - * string (since age ==1) + * string (since :member:`age` ==1) */ const char *version_str; /* -------- the above fields all exist when age == 1 */ @@ -5590,10 +5618,10 @@ typedef struct ngtcp2_info { /** * @function * - * `ngtcp2_version` returns a pointer to a ngtcp2_info struct with - * version information about the run-time library in use. The + * `ngtcp2_version` returns a pointer to a :type:`ngtcp2_info` struct + * with version information about the run-time library in use. The * |least_version| argument can be set to a 24 bit numerical value for - * the least accepted version number and if the condition is not met, + * the least accepted version number, and if the condition is not met, * this function will return a ``NULL``. Pass in 0 to skip the * version checking. */ @@ -5628,12 +5656,12 @@ NGTCP2_EXTERN int ngtcp2_path_eq(const ngtcp2_path *a, const ngtcp2_path *b); /** * @function * - * `ngtcp2_is_supported_version` returns nonzero if the library supports - * QUIC version |version|. + * `ngtcp2_is_supported_version` returns nonzero if the library + * supports QUIC version |version|. */ NGTCP2_EXTERN int ngtcp2_is_supported_version(uint32_t version); -/* +/** * @function * * `ngtcp2_is_reserved_version` returns nonzero if |version| is a @@ -5649,9 +5677,9 @@ NGTCP2_EXTERN int ngtcp2_is_reserved_version(uint32_t version); * |preferred_versions| of |preferred_versionslen| elements specifies * the preference of versions, which is sorted in the order of * preference. All versions included in |preferred_versions| must be - * supported by the library, that is, passing a version to - * `ngtcp2_is_supported_version` must return nonzero. This function - * is intended to be used by client when it receives Version + * supported by the library, that is, passing any version in the array + * to `ngtcp2_is_supported_version` must return nonzero. This + * function is intended to be used by client when it receives Version * Negotiation packet. If no version is selected, this function * returns 0. */ @@ -5703,6 +5731,17 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (DEST), (DESTLEN), \ (PDATALEN), (FLAGS), (STREAM_ID), (DATAV), (DATAVCNT), (TS)) +/* + * `ngtcp2_conn_write_datagram` is a wrapper around + * `ngtcp2_conn_write_datagram_versioned` to set the correct struct + * version. + */ +#define ngtcp2_conn_write_datagram(CONN, PATH, PI, DEST, DESTLEN, PACCEPTED, \ + FLAGS, DGRAM_ID, DATA, DATALEN, TS) \ + ngtcp2_conn_write_datagram_versioned( \ + (CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (DEST), (DESTLEN), \ + (PACCEPTED), (FLAGS), (DGRAM_ID), (DATA), (DATALEN), (TS)) + /* * `ngtcp2_conn_writev_datagram` is a wrapper around * `ngtcp2_conn_writev_datagram_versioned` to set the correct struct @@ -5726,22 +5765,22 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (CCERR), (TS)) /* - * `ngtcp2_encode_transport_params` is a wrapper around - * `ngtcp2_encode_transport_params_versioned` to set the correct + * `ngtcp2_transport_params_encode` is a wrapper around + * `ngtcp2_transport_params_encode_versioned` to set the correct * struct version. */ -#define ngtcp2_encode_transport_params(DEST, DESTLEN, EXTTYPE, PARAMS) \ - ngtcp2_encode_transport_params_versioned( \ - (DEST), (DESTLEN), (EXTTYPE), NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS)) +#define ngtcp2_transport_params_encode(DEST, DESTLEN, PARAMS) \ + ngtcp2_transport_params_encode_versioned( \ + (DEST), (DESTLEN), NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS)) /* - * `ngtcp2_decode_transport_params` is a wrapper around - * `ngtcp2_decode_transport_params_versioned` to set the correct + * `ngtcp2_transport_params_decode` is a wrapper around + * `ngtcp2_transport_params_decode_versioned` to set the correct * struct version. */ -#define ngtcp2_decode_transport_params(PARAMS, EXTTYPE, DATA, DATALEN) \ - ngtcp2_decode_transport_params_versioned( \ - NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS), (EXTTYPE), (DATA), (DATALEN)) +#define ngtcp2_transport_params_decode(PARAMS, DATA, DATALEN) \ + ngtcp2_transport_params_decode_versioned(NGTCP2_TRANSPORT_PARAMS_VERSION, \ + (PARAMS), (DATA), (DATALEN)) /* * `ngtcp2_conn_client_new` is a wrapper around @@ -5767,15 +5806,6 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (CALLBACKS), NGTCP2_SETTINGS_VERSION, (SETTINGS), \ NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS), (MEM), (USER_DATA)) -/* - * `ngtcp2_conn_set_early_remote_transport_params` is a wrapper around - * `ngtcp2_conn_set_early_remote_transport_params_versioned` to set - * the correct struct version. - */ -#define ngtcp2_conn_set_early_remote_transport_params(CONN, PARAMS) \ - ngtcp2_conn_set_early_remote_transport_params_versioned( \ - (CONN), NGTCP2_TRANSPORT_PARAMS_VERSION, (PARAMS)) - /* * `ngtcp2_conn_set_local_transport_params` is a wrapper around * `ngtcp2_conn_set_local_transport_params_versioned` to set the @@ -5795,12 +5825,12 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions, (PARAMS)) /* - * `ngtcp2_conn_get_conn_stat` is a wrapper around - * `ngtcp2_conn_get_conn_stat_versioned` to set the correct struct + * `ngtcp2_conn_get_conn_info` is a wrapper around + * `ngtcp2_conn_get_conn_info_versioned` to set the correct struct * version. */ -#define ngtcp2_conn_get_conn_stat(CONN, CSTAT) \ - ngtcp2_conn_get_conn_stat_versioned((CONN), NGTCP2_CONN_STAT_VERSION, (CSTAT)) +#define ngtcp2_conn_get_conn_info(CONN, CINFO) \ + ngtcp2_conn_get_conn_info_versioned((CONN), NGTCP2_CONN_INFO_VERSION, (CINFO)) /* * `ngtcp2_settings_default` is a wrapper around diff --git a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h index 9f7592b84a4585..66a70ffe962964 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 "0.8.1" +#define NGTCP2_VERSION "1.1.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 0x000801 +#define NGTCP2_VERSION_NUM 0x010100 #endif /* VERSION_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c index 02c45de90d112a..d4778d66accf31 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c @@ -27,6 +27,9 @@ #include #include "ngtcp2_macro.h" +#include "ngtcp2_tstamp.h" + +ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent); static void acktr_entry_init(ngtcp2_acktr_entry *ent, int64_t pkt_num, ngtcp2_tstamp tstamp) { @@ -66,7 +69,7 @@ int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log, rv = ngtcp2_ringbuf_init(&acktr->acks, 32, sizeof(ngtcp2_acktr_ack_entry), mem); if (rv != 0) { - return rv; + goto fail_acks_init; } ngtcp2_ksl_init(&acktr->ents, greater, sizeof(int64_t), mem); @@ -78,6 +81,10 @@ int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log, acktr->rx_npkt = 0; return 0; + +fail_acks_init: + ngtcp2_objalloc_free(&acktr->objalloc); + return rv; } void ngtcp2_acktr_free(ngtcp2_acktr *acktr) { @@ -286,16 +293,16 @@ void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr) { return; } - min_ack = largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = largest_ack - (int64_t)fr->first_ack_range; if (min_ack <= ent->pkt_num && ent->pkt_num <= largest_ack) { acktr_on_ack(acktr, rb, j); return; } - for (i = 0; i < fr->num_blks && j < nacks; ++i) { - largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2; - min_ack = largest_ack - (int64_t)fr->blks[i].blklen; + for (i = 0; i < fr->rangecnt && j < nacks; ++i) { + largest_ack = min_ack - (int64_t)fr->ranges[i].gap - 2; + min_ack = largest_ack - (int64_t)fr->ranges[i].len; for (;;) { if (ent->pkt_num > largest_ack) { @@ -326,8 +333,7 @@ void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) { int ngtcp2_acktr_require_active_ack(ngtcp2_acktr *acktr, ngtcp2_duration max_ack_delay, ngtcp2_tstamp ts) { - return acktr->first_unacked_ts != UINT64_MAX && - acktr->first_unacked_ts + max_ack_delay <= ts; + return ngtcp2_tstamp_elapsed(acktr->first_unacked_ts, max_ack_delay, ts); } void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h index 1b00d64fe62cb6..809fb692adc3c8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h @@ -65,7 +65,7 @@ typedef struct ngtcp2_acktr_entry { }; } ngtcp2_acktr_entry; -ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent); +ngtcp2_objalloc_decl(acktr_entry, ngtcp2_acktr_entry, oplent); /* * ngtcp2_acktr_entry_objalloc_new allocates memory for ent, and @@ -124,7 +124,8 @@ typedef struct ngtcp2_acktr { /* first_unacked_ts is timestamp when ngtcp2_acktr_entry is added first time after the last outgoing ACK frame. */ ngtcp2_tstamp first_unacked_ts; - /* rx_npkt is the number of packets received without sending ACK. */ + /* rx_npkt is the number of ACK eliciting packets received without + sending ACK. */ size_t rx_npkt; } ngtcp2_acktr; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c index daab5dd7ce664b..f389abe76d71c8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c @@ -27,6 +27,8 @@ #include #include +#include "ngtcp2_unreachable.h" + ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr, ngtcp2_socklen addrlen) { dest->addrlen = addrlen; @@ -66,8 +68,7 @@ static int sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) { memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0; } default: - assert(0); - abort(); + ngtcp2_unreachable(); } } @@ -109,8 +110,7 @@ uint32_t ngtcp2_addr_compare(const ngtcp2_addr *aa, const ngtcp2_addr *bb) { return flags; } default: - assert(0); - abort(); + ngtcp2_unreachable(); } } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h index f1d7f7bdc70ea9..8e3a9f591d9977 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h @@ -38,8 +38,10 @@ */ void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src); -/* - * ngtcp2_addr_eq returns nonzero if |a| equals |b|. +/** + * @function + * + * `ngtcp2_addr_eq` returns nonzero if |a| equals |b|. */ int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c index 0816d69b816c52..27c4667c03924a 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c @@ -9,7 +9,7 @@ * 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 following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. @@ -25,668 +25,1426 @@ #include "ngtcp2_bbr.h" #include +#include #include "ngtcp2_log.h" #include "ngtcp2_macro.h" #include "ngtcp2_mem.h" #include "ngtcp2_rcvry.h" #include "ngtcp2_rst.h" +#include "ngtcp2_conn_stat.h" -static const double pacing_gain_cycle[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1}; +#define NGTCP2_BBR_MAX_BW_FILTERLEN 2 -#define NGTCP2_BBR_GAIN_CYCLELEN \ - (sizeof(pacing_gain_cycle) / sizeof(pacing_gain_cycle[0])) +#define NGTCP2_BBR_EXTRA_ACKED_FILTERLEN 10 + +#define NGTCP2_BBR_STARTUP_PACING_GAIN_H 277 + +#define NGTCP2_BBR_STARTUP_CWND_GAIN_H 200 + +#define NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H 50 + +#define NGTCP2_BBR_BETA_NUMER 7 +#define NGTCP2_BBR_BETA_DENOM 10 + +#define NGTCP2_BBR_LOSS_THRESH_NUMER 2 +#define NGTCP2_BBR_LOSS_THRESH_DENOM 100 + +#define NGTCP2_BBR_HEADROOM_NUMER 15 +#define NGTCP2_BBR_HEADROOM_DENOM 100 + +#define NGTCP2_BBR_PROBE_RTT_INTERVAL (5 * NGTCP2_SECONDS) +#define NGTCP2_BBR_MIN_RTT_FILTERLEN (10 * NGTCP2_SECONDS) -#define NGTCP2_BBR_HIGH_GAIN 2.89 #define NGTCP2_BBR_PROBE_RTT_DURATION (200 * NGTCP2_MILLISECONDS) -#define NGTCP2_RTPROP_FILTERLEN (10 * NGTCP2_SECONDS) -#define NGTCP2_BBR_BTL_BW_FILTERLEN 10 -static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, +#define NGTCP2_BBR_PACING_MARGIN_PERCENT 1 + +static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp initial_ts); + +static void bbr_on_transmit(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr); + +static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr); + +static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr); + +static void bbr_init_full_pipe(ngtcp2_cc_bbr *bbr); + +static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t pacing_gain_h); + +static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_enter_startup(ngtcp2_cc_bbr *bbr); + +static void bbr_check_startup_done(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_ack *ack); + +static void bbr_update_on_ack(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc, + +static void bbr_update_model_and_state(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc, + +static void bbr_update_control_parameters(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack); -static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_init_round_counting(ngtcp2_bbr_cc *cc); -static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack); -static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); -static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); -static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc, + +static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); + +static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, - double pacing_gain); -static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); -static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat); -static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat); -static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); -static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts); -static void bbr_enter_startup(ngtcp2_bbr_cc *cc); -static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc); -static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc); -static void bbr_enter_drain(ngtcp2_bbr_cc *cc); -static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr); + +static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr); + +static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_update_round(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack); + +static void bbr_start_round(ngtcp2_cc_bbr *bbr); + +static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr); + +static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts); + +static void bbr_enter_drain(ngtcp2_cc_bbr *bbr); + +static void bbr_check_drain(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts); -static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts); -static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + +static void bbr_enter_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts); + +static void bbr_start_probe_bw_down(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts); + +static void bbr_start_probe_bw_cruise(ngtcp2_cc_bbr *bbr); + +static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr); + +static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts); + +static int bbr_check_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_duration interval, ngtcp2_tstamp ts); + +static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); -static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat); -static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + +static int bbr_check_time_to_probe_bw(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr); + +static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static int is_inflight_too_high(const ngtcp2_rs *rs); + +static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_rs *rs, ngtcp2_tstamp ts); + +static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); + +static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr, + const ngtcp2_rs *rs, + const ngtcp2_cc_pkt *pkt); + +static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts); + +static void bbr_check_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc); -static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, + +static void bbr_enter_probe_rtt(ngtcp2_cc_bbr *bbr); + +static void bbr_handle_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts); - -void ngtcp2_bbr_cc_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_rst *rst, ngtcp2_tstamp initial_ts, - ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx, - ngtcp2_log *log) { - cc->ccb.log = log; - cc->rst = rst; - cc->rand = rand; - cc->rand_ctx = *rand_ctx; - cc->initial_cwnd = cstat->cwnd; - bbr_init(cc, cstat, initial_ts); -} - -void ngtcp2_bbr_cc_free(ngtcp2_bbr_cc *cc) { (void)cc; } - -int ngtcp2_cc_bbr_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem) { - ngtcp2_bbr_cc *bbr_cc; - - bbr_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_bbr_cc)); - if (bbr_cc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_bbr_cc_init(bbr_cc, cstat, rst, initial_ts, rand, rand_ctx, log); - - cc->ccb = &bbr_cc->ccb; - cc->on_pkt_acked = ngtcp2_cc_bbr_cc_on_pkt_acked; - cc->congestion_event = ngtcp2_cc_bbr_cc_congestion_event; - cc->on_spurious_congestion = ngtcp2_cc_bbr_cc_on_spurious_congestion; - cc->on_persistent_congestion = ngtcp2_cc_bbr_cc_on_persistent_congestion; - cc->on_ack_recv = ngtcp2_cc_bbr_cc_on_ack_recv; - cc->on_pkt_sent = ngtcp2_cc_bbr_cc_on_pkt_sent; - cc->new_rtt_sample = ngtcp2_cc_bbr_cc_new_rtt_sample; - cc->reset = ngtcp2_cc_bbr_cc_reset; - cc->event = ngtcp2_cc_bbr_cc_event; - return 0; -} +static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); + +static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts); + +static void bbr_handle_restart_from_idle(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t bw, + uint64_t gain_h); + +static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t inflight); + +static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + uint64_t bw, uint64_t gain_h); + +static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static uint64_t min_pipe_cwnd(size_t max_udp_payload_size); + +static void bbr_advance_max_bw_filter(ngtcp2_cc_bbr *bbr); + +static void bbr_modulate_cwnd_for_recovery(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); + +static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); + +static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); + +static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, + ngtcp2_tstamp sent_time); + +static void bbr_handle_recovery(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); + +static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp initial_ts) { + ngtcp2_window_filter_init(&bbr->max_bw_filter, NGTCP2_BBR_MAX_BW_FILTERLEN); + ngtcp2_window_filter_init(&bbr->extra_acked_filter, + NGTCP2_BBR_EXTRA_ACKED_FILTERLEN); + + bbr->min_rtt = UINT64_MAX; + bbr->min_rtt_stamp = initial_ts; + /* remark: Use UINT64_MAX instead of 0 for consistency. */ + bbr->probe_rtt_done_stamp = UINT64_MAX; + bbr->probe_rtt_round_done = 0; + bbr->prior_cwnd = 0; + bbr->idle_restart = 0; + bbr->extra_acked_interval_start = initial_ts; + bbr->extra_acked_delivered = 0; + + bbr_reset_congestion_signals(bbr); + bbr_reset_lower_bounds(bbr); + bbr_init_round_counting(bbr); + bbr_init_full_pipe(bbr); + bbr_init_pacing_rate(bbr, cstat); + bbr_enter_startup(bbr); + + cstat->send_quantum = cstat->max_tx_udp_payload_size * 10; + + /* Missing in documentation */ + bbr->loss_round_start = 0; + bbr->loss_round_delivered = UINT64_MAX; + + bbr->rounds_since_bw_probe = 0; + + bbr->max_bw = 0; + bbr->bw = 0; + + bbr->cycle_count = 0; + + bbr->extra_acked = 0; + + bbr->bytes_lost_in_round = 0; + bbr->loss_events_in_round = 0; -void ngtcp2_cc_bbr_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_bbr_cc, ccb); + bbr->offload_budget = 0; - ngtcp2_bbr_cc_free(bbr_cc); - ngtcp2_mem_free(mem, bbr_cc); + bbr->probe_up_cnt = UINT64_MAX; + bbr->cycle_stamp = UINT64_MAX; + bbr->ack_phase = 0; + bbr->bw_probe_wait = 0; + bbr->bw_probe_samples = 0; + bbr->bw_probe_up_rounds = 0; + bbr->bw_probe_up_acks = 0; + + bbr->inflight_hi = UINT64_MAX; + bbr->bw_hi = UINT64_MAX; + + bbr->probe_rtt_expired = 0; + bbr->probe_rtt_min_delay = UINT64_MAX; + bbr->probe_rtt_min_stamp = initial_ts; + + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + + bbr->max_inflight = 0; + + bbr->congestion_recovery_start_ts = UINT64_MAX; + bbr->congestion_recovery_next_round_delivered = 0; + + bbr->prior_inflight_lo = 0; + bbr->prior_inflight_hi = 0; + bbr->prior_bw_lo = 0; } -void ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)pkt; - (void)ts; +static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) { + bbr->loss_in_round = 0; + bbr->bw_latest = 0; + bbr->inflight_latest = 0; } -static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_time) { - return cstat->congestion_recovery_start_ts != UINT64_MAX && - sent_time <= cstat->congestion_recovery_start_ts; +static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) { + bbr->bw_lo = UINT64_MAX; + bbr->inflight_lo = UINT64_MAX; } -void ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_ts, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); +static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr) { + bbr->next_round_delivered = 0; + bbr->round_start = 0; + bbr->round_count = 0; +} - if (cc->in_loss_recovery || cc->congestion_recovery_start_ts != UINT64_MAX || - in_congestion_recovery(cstat, sent_ts)) { +static void bbr_init_full_pipe(ngtcp2_cc_bbr *bbr) { + bbr->filled_pipe = 0; + bbr->full_bw = 0; + bbr->full_bw_count = 0; +} + +static void bbr_check_startup_full_bandwidth(ngtcp2_cc_bbr *bbr) { + if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { return; } - cc->congestion_recovery_start_ts = ts; -} + if (bbr->max_bw * 100 >= bbr->full_bw * 125) { + bbr->full_bw = bbr->max_bw; + bbr->full_bw_count = 0; + } -void ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - (void)ts; + ++bbr->full_bw_count; - cc->congestion_recovery_start_ts = UINT64_MAX; - cstat->congestion_recovery_start_ts = UINT64_MAX; + if (bbr->full_bw_count >= 3) { + bbr->filled_pipe = 1; - if (cc->in_loss_recovery) { - cc->in_loss_recovery = 0; - cc->packet_conservation = 0; - bbr_restore_cwnd(cc, cstat); + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr filled pipe, full_bw=%" PRIu64, bbr->full_bw); } } -void ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - (void)ts; +static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_ack *ack) { + if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { + return; + } - cstat->congestion_recovery_start_ts = UINT64_MAX; - cc->congestion_recovery_start_ts = UINT64_MAX; - cc->in_loss_recovery = 0; - cc->packet_conservation = 0; + if (bbr->loss_events_in_round <= 3) { + return; + } - bbr_save_cwnd(cc, cstat); - cstat->cwnd = 2 * cstat->max_udp_payload_size; -} + /* loss_thresh = 2% */ + if (bbr->bytes_lost_in_round * 100 <= ack->prior_bytes_in_flight * 2) { + return; + } -void ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); + bbr->filled_pipe = 1; +} - bbr_update_on_ack(bbr_cc, cstat, ack, ts); +static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + cstat->pacing_interval = NGTCP2_MILLISECONDS * 100 / + NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd; } -void ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - (void)pkt; +static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t pacing_gain_h) { + ngtcp2_duration interval; + + if (bbr->bw == 0) { + return; + } + + interval = NGTCP2_SECONDS * 100 * 100 / pacing_gain_h / bbr->bw / + (100 - NGTCP2_BBR_PACING_MARGIN_PERCENT); - bbr_on_transmit(bbr_cc, cstat); + if (bbr->filled_pipe || interval < cstat->pacing_interval) { + cstat->pacing_interval = interval; + } } -void ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)ts; +static void bbr_set_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + bbr_set_pacing_rate_with_gain(bbr, cstat, bbr->pacing_gain_h); } -void ngtcp2_cc_bbr_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb); - bbr_init(bbr_cc, cstat, ts); +static void bbr_enter_startup(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr enter Startup"); + + bbr->state = NGTCP2_BBR_STATE_STARTUP; + bbr->pacing_gain_h = NGTCP2_BBR_STARTUP_PACING_GAIN_H; + bbr->cwnd_gain_h = NGTCP2_BBR_STARTUP_CWND_GAIN_H; } -void ngtcp2_cc_bbr_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_cc_event_type event, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)event; - (void)ts; +static void bbr_check_startup_done(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_ack *ack) { + bbr_check_startup_full_bandwidth(bbr); + bbr_check_startup_high_loss(bbr, ack); + + if (bbr->state == NGTCP2_BBR_STATE_STARTUP && bbr->filled_pipe) { + bbr_enter_drain(bbr); + } +} + +static void bbr_on_transmit(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + bbr_handle_restart_from_idle(bbr, cstat, ts); } -static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, +static void bbr_update_on_ack(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - bbr_update_model_and_state(cc, cstat, ack, ts); - bbr_update_control_parameters(cc, cstat, ack); + bbr_update_model_and_state(bbr, cstat, ack, ts); + bbr_update_control_parameters(bbr, cstat, ack); } -static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc, +static void bbr_update_model_and_state(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - bbr_update_btl_bw(cc, cstat, ack); - bbr_check_cycle_phase(cc, cstat, ack, ts); - bbr_check_full_pipe(cc); - bbr_check_drain(cc, cstat, ts); - bbr_update_rtprop(cc, cstat, ts); - bbr_check_probe_rtt(cc, cstat, ts); + bbr_update_latest_delivery_signals(bbr, cstat); + bbr_update_congestion_signals(bbr, cstat, ack); + bbr_update_ack_aggregation(bbr, cstat, ack, ts); + bbr_check_startup_done(bbr, ack); + bbr_check_drain(bbr, cstat, ts); + bbr_update_probe_bw_cycle_phase(bbr, cstat, ack, ts); + bbr_update_min_rtt(bbr, ack, ts); + bbr_check_probe_rtt(bbr, cstat, ts); + bbr_advance_latest_delivery_signals(bbr, cstat); + bbr_bound_bw_for_model(bbr); } -static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc, +static void bbr_update_control_parameters(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack) { - bbr_set_pacing_rate(cc, cstat); - bbr_set_send_quantum(cc, cstat); - bbr_set_cwnd(cc, cstat, ack); + bbr_set_pacing_rate(bbr, cstat); + bbr_set_send_quantum(bbr, cstat); + bbr_set_cwnd(bbr, cstat, ack); } -static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - bbr_handle_restart_from_idle(cc, cstat); +static void bbr_update_on_loss(ngtcp2_cc_bbr *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { + bbr_handle_lost_packet(cc, cstat, pkt, ts); } -static void bbr_init_round_counting(ngtcp2_bbr_cc *cc) { - cc->next_round_delivered = 0; - cc->round_start = 0; - cc->round_count = 0; -} - -static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack) { - if (ack->pkt_delivered >= cc->next_round_delivered) { - cc->next_round_delivered = cc->rst->delivered; - ++cc->round_count; - cc->round_start = 1; +static void bbr_update_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + bbr->loss_round_start = 0; + bbr->bw_latest = ngtcp2_max(bbr->bw_latest, cstat->delivery_rate_sec); + bbr->inflight_latest = + ngtcp2_max(bbr->inflight_latest, bbr->rst->rs.delivered); - return; + if (bbr->rst->rs.prior_delivered >= bbr->loss_round_delivered) { + bbr->loss_round_delivered = bbr->rst->delivered; + bbr->loss_round_start = 1; } +} - cc->round_start = 0; +static void bbr_advance_latest_delivery_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + if (bbr->loss_round_start) { + bbr->bw_latest = cstat->delivery_rate_sec; + bbr->inflight_latest = bbr->rst->rs.delivered; + } } -static void bbr_handle_recovery(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (cc->in_loss_recovery) { - if (ack->pkt_delivered >= cc->congestion_recovery_next_round_delivered) { - cc->packet_conservation = 0; - } +static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + bbr_update_max_bw(bbr, cstat, ack); + + if (ack->bytes_lost) { + bbr->bytes_lost_in_round += ack->bytes_lost; + ++bbr->loss_events_in_round; - if (!in_congestion_recovery(cstat, ack->largest_acked_sent_ts)) { - cc->in_loss_recovery = 0; - cc->packet_conservation = 0; - bbr_restore_cwnd(cc, cstat); + if (!bbr->loss_in_round) { + bbr->loss_in_round = 1; + bbr->loss_round_delivered = bbr->rst->delivered; } + } + if (!bbr->loss_round_start) { return; } - if (cc->congestion_recovery_start_ts != UINT64_MAX) { - cc->in_loss_recovery = 1; - bbr_save_cwnd(cc, cstat); - cstat->cwnd = cstat->bytes_in_flight + - ngtcp2_max(ack->bytes_delivered, cstat->max_udp_payload_size); + bbr_adapt_lower_bounds_from_congestion(bbr, cstat); - cstat->congestion_recovery_start_ts = cc->congestion_recovery_start_ts; - cc->congestion_recovery_start_ts = UINT64_MAX; - cc->packet_conservation = 1; - cc->congestion_recovery_next_round_delivered = cc->rst->delivered; + bbr->loss_in_round = 0; +} + +static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + if (bbr_is_in_probe_bw_state(bbr)) { + return; + } + + if (bbr->loss_in_round) { + bbr_init_lower_bounds(bbr, cstat); + bbr_loss_lower_bounds(bbr); } } -static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_round(cc, ack); - bbr_handle_recovery(cc, cstat, ack); +static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + if (bbr->bw_lo == UINT64_MAX) { + bbr->bw_lo = bbr->max_bw; + } - if (cstat->delivery_rate_sec < cc->btl_bw && cc->rst->rs.is_app_limited) { - return; + if (bbr->inflight_lo == UINT64_MAX) { + bbr->inflight_lo = cstat->cwnd; } +} - ngtcp2_window_filter_update(&cc->btl_bw_filter, cstat->delivery_rate_sec, - cc->round_count); +static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr) { + bbr->bw_lo = ngtcp2_max(bbr->bw_latest, bbr->bw_lo * NGTCP2_BBR_BETA_NUMER / + NGTCP2_BBR_BETA_DENOM); + bbr->inflight_lo = ngtcp2_max(bbr->inflight_latest, + bbr->inflight_lo * NGTCP2_BBR_BETA_NUMER / + NGTCP2_BBR_BETA_DENOM); +} - cc->btl_bw = ngtcp2_window_filter_get_best(&cc->btl_bw_filter); +static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr) { + bbr->bw = ngtcp2_min(bbr->max_bw, bbr->bw_lo); + bbr->bw = ngtcp2_min(bbr->bw, bbr->bw_hi); } -static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - cc->rtprop_expired = ts > cc->rtprop_stamp + NGTCP2_RTPROP_FILTERLEN; +static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + bbr_update_round(bbr, ack); - /* Need valid RTT sample */ - if (cstat->latest_rtt && - (cstat->latest_rtt <= cc->rt_prop || cc->rtprop_expired)) { - cc->rt_prop = cstat->latest_rtt; - cc->rtprop_stamp = ts; + if (cstat->delivery_rate_sec >= bbr->max_bw || !bbr->rst->rs.is_app_limited) { + ngtcp2_window_filter_update(&bbr->max_bw_filter, cstat->delivery_rate_sec, + bbr->cycle_count); - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr update RTprop=%" PRIu64, cc->rt_prop); + bbr->max_bw = ngtcp2_window_filter_get_best(&bbr->max_bw_filter); } } -static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - double nominal_bandwidth = - (double)cc->initial_cwnd / (double)NGTCP2_MILLISECONDS; +static void bbr_update_round(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack) { + if (ack->pkt_delivered >= bbr->next_round_delivered) { + bbr_start_round(bbr); - cstat->pacing_rate = cc->pacing_gain * nominal_bandwidth; -} + ++bbr->round_count; + ++bbr->rounds_since_bw_probe; + bbr->round_start = 1; -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat, - double pacing_gain) { - double rate = pacing_gain * (double)cc->btl_bw / NGTCP2_SECONDS; + bbr->bytes_lost_in_round = 0; + bbr->loss_events_in_round = 0; + + bbr->rst->is_cwnd_limited = 0; - if (cc->filled_pipe || rate > cstat->pacing_rate) { - cstat->pacing_rate = rate; + return; } + + bbr->round_start = 0; } -static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - bbr_set_pacing_rate_with_gain(cc, cstat, cc->pacing_gain); +static void bbr_start_round(ngtcp2_cc_bbr *bbr) { + bbr->next_round_delivered = bbr->rst->delivered; } -static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - uint64_t send_quantum; - (void)cc; +static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr) { + switch (bbr->state) { + case NGTCP2_BBR_STATE_PROBE_BW_DOWN: + case NGTCP2_BBR_STATE_PROBE_BW_CRUISE: + case NGTCP2_BBR_STATE_PROBE_BW_REFILL: + case NGTCP2_BBR_STATE_PROBE_BW_UP: + return 1; + default: + return 0; + } +} - if (cstat->pacing_rate < 1.2 * 1024 * 1024 / 8 / NGTCP2_SECONDS) { - cstat->send_quantum = cstat->max_udp_payload_size; - } else if (cstat->pacing_rate < 24.0 * 1024 * 1024 / 8 / NGTCP2_SECONDS) { - cstat->send_quantum = cstat->max_udp_payload_size * 2; - } else { - send_quantum = - (uint64_t)(cstat->pacing_rate * (double)(cstat->min_rtt == UINT64_MAX - ? NGTCP2_MILLISECONDS - : cstat->min_rtt)); - cstat->send_quantum = (size_t)ngtcp2_min(send_quantum, 64 * 1024); +static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts) { + ngtcp2_duration interval = ts - bbr->extra_acked_interval_start; + uint64_t expected_delivered = bbr->bw * interval / NGTCP2_SECONDS; + uint64_t extra; + + if (bbr->extra_acked_delivered <= expected_delivered) { + bbr->extra_acked_delivered = 0; + bbr->extra_acked_interval_start = ts; + expected_delivered = 0; } - cstat->send_quantum = - ngtcp2_max(cstat->send_quantum, cstat->max_udp_payload_size * 10); + bbr->extra_acked_delivered += ack->bytes_delivered; + extra = bbr->extra_acked_delivered - expected_delivered; + extra = ngtcp2_min(extra, cstat->cwnd); + + ngtcp2_window_filter_update(&bbr->extra_acked_filter, extra, + bbr->round_count); + + bbr->extra_acked = ngtcp2_window_filter_get_best(&bbr->extra_acked_filter); } -static uint64_t bbr_inflight(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - double gain) { - uint64_t quanta = 3 * cstat->send_quantum; - double estimated_bdp; +static void bbr_enter_drain(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr enter Drain"); + + bbr->state = NGTCP2_BBR_STATE_DRAIN; + bbr->pacing_gain_h = 100 * 100 / NGTCP2_BBR_STARTUP_CWND_GAIN_H; + bbr->cwnd_gain_h = NGTCP2_BBR_STARTUP_CWND_GAIN_H; +} - if (cc->rt_prop == UINT64_MAX) { - /* no valid RTT samples yet */ - return cc->initial_cwnd; +static void bbr_check_drain(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr->state == NGTCP2_BBR_STATE_DRAIN && + cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->bw, 100)) { + bbr_enter_probe_bw(bbr, ts); } +} - estimated_bdp = (double)cc->btl_bw * (double)cc->rt_prop / NGTCP2_SECONDS; +static void bbr_enter_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) { + bbr_start_probe_bw_down(bbr, ts); +} - return (uint64_t)(gain * estimated_bdp) + quanta; +static void bbr_start_probe_bw_down(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr start ProbeBW_DOWN"); + + bbr_reset_congestion_signals(bbr); + + bbr->probe_up_cnt = UINT64_MAX; + + bbr_pick_probe_wait(bbr); + + bbr->cycle_stamp = ts; + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING; + + bbr_start_round(bbr); + + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_DOWN; + bbr->pacing_gain_h = 90; + bbr->cwnd_gain_h = 200; } -static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - cc->target_cwnd = bbr_inflight(cc, cstat, cc->cwnd_gain); +static void bbr_start_probe_bw_cruise(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr start ProbeBW_CRUISE"); + + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_CRUISE; + bbr->pacing_gain_h = 100; + bbr->cwnd_gain_h = 200; } -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (ack->bytes_lost > 0) { - if (cstat->cwnd > ack->bytes_lost) { - cstat->cwnd -= ack->bytes_lost; - cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_udp_payload_size); - } else { - cstat->cwnd = cstat->max_udp_payload_size; - } +static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr start ProbeBW_REFILL"); + + bbr_reset_lower_bounds(bbr); + + bbr->bw_probe_up_rounds = 0; + bbr->bw_probe_up_acks = 0; + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_REFILLING; + + bbr_start_round(bbr); + + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_REFILL; + bbr->pacing_gain_h = 100; + bbr->cwnd_gain_h = 200; +} + +static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr start ProbeBW_UP"); + + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING; + + bbr_start_round(bbr); + + bbr->cycle_stamp = ts; + bbr->state = NGTCP2_BBR_STATE_PROBE_BW_UP; + bbr->pacing_gain_h = 125; + bbr->cwnd_gain_h = 225; + + bbr_raise_inflight_hi_slope(bbr, cstat); +} + +static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts) { + if (!bbr->filled_pipe) { + return; } - if (cc->packet_conservation) { - cstat->cwnd = - ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered); + bbr_adapt_upper_bounds(bbr, cstat, ack, ts); + + if (!bbr_is_in_probe_bw_state(bbr)) { + return; + } + + switch (bbr->state) { + case NGTCP2_BBR_STATE_PROBE_BW_DOWN: + if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { + return; + } + + if (bbr_check_time_to_cruise(bbr, cstat, ts)) { + bbr_start_probe_bw_cruise(bbr); + } + + break; + case NGTCP2_BBR_STATE_PROBE_BW_CRUISE: + if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { + return; + } + + break; + case NGTCP2_BBR_STATE_PROBE_BW_REFILL: + if (bbr->round_start) { + bbr->bw_probe_samples = 1; + bbr_start_probe_bw_up(bbr, cstat, ts); + } + + break; + case NGTCP2_BBR_STATE_PROBE_BW_UP: + if (bbr_has_elapsed_in_phase(bbr, bbr->min_rtt, ts) && + cstat->bytes_in_flight > bbr_inflight(bbr, cstat, bbr->max_bw, 125)) { + bbr_start_probe_bw_down(bbr, ts); + } + + break; + default: + break; } } -static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - if (!cc->in_loss_recovery && cc->state != NGTCP2_BBR_STATE_PROBE_RTT) { - cc->prior_cwnd = cstat->cwnd; - return; +static int bbr_check_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + (void)ts; + + if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) { + return 0; } - cc->prior_cwnd = ngtcp2_max(cc->prior_cwnd, cstat->cwnd); + if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->max_bw, 100)) { + return 1; + } + + return 0; } -static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) { - cstat->cwnd = ngtcp2_max(cstat->cwnd, cc->prior_cwnd); +static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr, + ngtcp2_duration interval, + ngtcp2_tstamp ts) { + return ts > bbr->cycle_stamp + interval; } -static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) { - return max_udp_payload_size * 4; +static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t headroom; + uint64_t mpcwnd; + if (bbr->inflight_hi == UINT64_MAX) { + return UINT64_MAX; + } + + headroom = ngtcp2_max(cstat->max_tx_udp_payload_size, + bbr->inflight_hi * NGTCP2_BBR_HEADROOM_NUMER / + NGTCP2_BBR_HEADROOM_DENOM); + mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); + + if (bbr->inflight_hi > headroom) { + return ngtcp2_max(bbr->inflight_hi - headroom, mpcwnd); + } + + return mpcwnd; } -static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat) { - if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) { - cstat->cwnd = - ngtcp2_min(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size)); +static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t growth_this_round = cstat->max_tx_udp_payload_size + << bbr->bw_probe_up_rounds; + + 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) * + cstat->max_tx_udp_payload_size; +} + +static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + uint64_t delta; + + if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_hi) { + return; + } + + bbr->bw_probe_up_acks += ack->bytes_delivered; + + if (bbr->bw_probe_up_acks >= bbr->probe_up_cnt) { + delta = bbr->bw_probe_up_acks / bbr->probe_up_cnt; + bbr->bw_probe_up_acks -= delta * bbr->probe_up_cnt; + bbr->inflight_hi += delta * cstat->max_tx_udp_payload_size; + } + + if (bbr->round_start) { + bbr_raise_inflight_hi_slope(bbr, cstat); } } -static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_target_cwnd(cc, cstat); - bbr_modulate_cwnd_for_recovery(cc, cstat, ack); - - if (!cc->packet_conservation) { - if (cc->filled_pipe) { - cstat->cwnd = - ngtcp2_min(cstat->cwnd + ack->bytes_delivered, cc->target_cwnd); - } else if (cstat->cwnd < cc->target_cwnd || - cc->rst->delivered < cc->initial_cwnd) { - cstat->cwnd += ack->bytes_delivered; +static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { + if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING && + bbr->round_start) { + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK; + } + + if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING && + bbr->round_start) { + if (bbr_is_in_probe_bw_state(bbr) && !bbr->rst->rs.is_app_limited) { + bbr_advance_max_bw_filter(bbr); } + } - cstat->cwnd = - ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size)); + if (!bbr_check_inflight_too_high(bbr, cstat, ts)) { + /* bbr->bw_hi never be updated */ + if (bbr->inflight_hi == UINT64_MAX /* || bbr->bw_hi == UINT64_MAX */) { + return; + } + + if (bbr->rst->rs.tx_in_flight > bbr->inflight_hi) { + bbr->inflight_hi = bbr->rst->rs.tx_in_flight; + } + + if (cstat->delivery_rate_sec > bbr->bw_hi) { + bbr->bw_hi = cstat->delivery_rate_sec; + } + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) { + bbr_probe_inflight_hi_upward(bbr, cstat, ack); + } + } +} + +static int bbr_check_time_to_probe_bw(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr_has_elapsed_in_phase(bbr, bbr->bw_probe_wait, ts) || + bbr_is_reno_coexistence_probe_time(bbr, cstat)) { + bbr_start_probe_bw_refill(bbr); + + return 1; } - bbr_modulate_cwnd_for_probe_rtt(cc, cstat); + return 0; } -static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts) { - cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN; - cc->prior_cwnd = 0; - cc->target_cwnd = 0; - cc->btl_bw = 0; - cc->rt_prop = UINT64_MAX; - cc->rtprop_stamp = initial_ts; - cc->cycle_stamp = UINT64_MAX; - cc->probe_rtt_done_stamp = UINT64_MAX; - cc->cycle_index = 0; - cc->rtprop_expired = 0; - cc->idle_restart = 0; - cc->packet_conservation = 0; - cc->probe_rtt_round_done = 0; +static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr) { + uint8_t rand; - cc->congestion_recovery_start_ts = UINT64_MAX; - cc->congestion_recovery_next_round_delivered = 0; - cc->in_loss_recovery = 0; + bbr->rand(&rand, 1, &bbr->rand_ctx); - cstat->send_quantum = cstat->max_udp_payload_size * 10; + bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256); - ngtcp2_window_filter_init(&cc->btl_bw_filter, NGTCP2_BBR_BTL_BW_FILTERLEN); + bbr->rand(&rand, 1, &bbr->rand_ctx); - bbr_init_round_counting(cc); - bbr_init_full_pipe(cc); - bbr_init_pacing_rate(cc, cstat); - bbr_enter_startup(cc); + bbr->bw_probe_wait = + 2 * NGTCP2_SECONDS + (ngtcp2_tstamp)(NGTCP2_SECONDS * rand / 255); } -static void bbr_enter_startup(ngtcp2_bbr_cc *cc) { - cc->state = NGTCP2_BBR_STATE_STARTUP; - cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN; - cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN; +static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t reno_rounds = + bbr_target_inflight(bbr, cstat) / cstat->max_tx_udp_payload_size; + + return bbr->rounds_since_bw_probe >= ngtcp2_min(reno_rounds, 63); } -static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc) { - cc->filled_pipe = 0; - cc->full_bw = 0; - cc->full_bw_count = 0; +static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t bdp = bbr_inflight(bbr, cstat, bbr->bw, 100); + + return ngtcp2_min(bdp, cstat->cwnd); } -static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc) { - if (cc->filled_pipe || !cc->round_start || cc->rst->rs.is_app_limited) { - /* no need to check for a full pipe now. */ - return; +static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (is_inflight_too_high(&bbr->rst->rs)) { + if (bbr->bw_probe_samples) { + bbr_handle_inflight_too_high(bbr, cstat, &bbr->rst->rs, ts); + } + + return 1; } - /* cc->btl_bw still growing? */ - if (cc->btl_bw * 100 >= cc->full_bw * 125) { - /* record new baseline level */ - cc->full_bw = cc->btl_bw; - cc->full_bw_count = 0; + return 0; +} + +static int is_inflight_too_high(const ngtcp2_rs *rs) { + return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM > + rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER; +} + +static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_rs *rs, + ngtcp2_tstamp ts) { + bbr->bw_probe_samples = 0; + + if (!rs->is_app_limited) { + bbr->inflight_hi = ngtcp2_max( + rs->tx_in_flight, bbr_target_inflight(bbr, cstat) * + NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); + } + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) { + bbr_start_probe_bw_down(bbr, ts); + } +} + +static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { + ngtcp2_rs rs = {0}; + + if (!bbr->bw_probe_samples) { return; } - /* another round w/o much growth */ - ++cc->full_bw_count; - if (cc->full_bw_count >= 3) { - cc->filled_pipe = 1; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr filled pipe, btl_bw=%" PRIu64, cc->btl_bw); + + rs.tx_in_flight = pkt->tx_in_flight; + /* bbr->rst->lost is not incremented for pkt yet */ + rs.lost = bbr->rst->lost + pkt->pktlen - pkt->lost; + rs.is_app_limited = pkt->is_app_limited; + + if (is_inflight_too_high(&rs)) { + rs.tx_in_flight = bbr_inflight_hi_from_lost_packet(bbr, &rs, pkt); + + bbr_handle_inflight_too_high(bbr, cstat, &rs, ts); } } -static void bbr_enter_drain(ngtcp2_bbr_cc *cc) { - cc->state = NGTCP2_BBR_STATE_DRAIN; - /* pace slowly */ - cc->pacing_gain = 1.0 / NGTCP2_BBR_HIGH_GAIN; - /* maintain cwnd */ - cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN; +static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr, + const ngtcp2_rs *rs, + const ngtcp2_cc_pkt *pkt) { + uint64_t inflight_prev, lost_prev, lost_prefix; + (void)bbr; + + assert(rs->tx_in_flight >= pkt->pktlen); + + inflight_prev = rs->tx_in_flight - pkt->pktlen; + + assert(rs->lost >= pkt->pktlen); + + lost_prev = rs->lost - pkt->pktlen; + + if (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER < + lost_prev * NGTCP2_BBR_LOSS_THRESH_DENOM) { + return inflight_prev; + } + + lost_prefix = (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER - + lost_prev * NGTCP2_BBR_LOSS_THRESH_DENOM) / + (NGTCP2_BBR_LOSS_THRESH_DENOM - NGTCP2_BBR_LOSS_THRESH_NUMER); + + return inflight_prev + lost_prefix; } -static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (cc->state == NGTCP2_BBR_STATE_STARTUP && cc->filled_pipe) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit Startup and enter Drain"); +static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack, + ngtcp2_tstamp ts) { + int min_rtt_expired; + + bbr->probe_rtt_expired = + ts > bbr->probe_rtt_min_stamp + NGTCP2_BBR_PROBE_RTT_INTERVAL; - bbr_enter_drain(cc); + if (ack->rtt != UINT64_MAX && + (ack->rtt < bbr->probe_rtt_min_delay || bbr->probe_rtt_expired)) { + bbr->probe_rtt_min_delay = ack->rtt; + bbr->probe_rtt_min_stamp = ts; } - if (cc->state == NGTCP2_BBR_STATE_DRAIN && - cstat->bytes_in_flight <= bbr_inflight(cc, cstat, 1.0)) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit Drain and enter ProbeBW"); + min_rtt_expired = ts > bbr->min_rtt_stamp + NGTCP2_BBR_MIN_RTT_FILTERLEN; - /* we estimate queue is drained */ - bbr_enter_probe_bw(cc, ts); + if (bbr->probe_rtt_min_delay < bbr->min_rtt || min_rtt_expired) { + bbr->min_rtt = bbr->probe_rtt_min_delay; + bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp; + + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, + "bbr update min_rtt=%" PRIu64, bbr->min_rtt); } } -static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) { - uint8_t rand; +static void bbr_check_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr->state != NGTCP2_BBR_STATE_PROBE_RTT && bbr->probe_rtt_expired && + !bbr->idle_restart) { + bbr_enter_probe_rtt(bbr); + bbr_save_cwnd(bbr, cstat); + + bbr->probe_rtt_done_stamp = UINT64_MAX; + bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING; - cc->state = NGTCP2_BBR_STATE_PROBE_BW; - cc->pacing_gain = 1; - cc->cwnd_gain = 2; + bbr_start_round(bbr); + } + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) { + bbr_handle_probe_rtt(bbr, cstat, ts); + } - assert(cc->rand); + if (bbr->rst->rs.delivered) { + bbr->idle_restart = 0; + } +} - cc->rand(&rand, 1, &cc->rand_ctx); +static void bbr_enter_probe_rtt(ngtcp2_cc_bbr *bbr) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr enter ProbeRTT"); - cc->cycle_index = NGTCP2_BBR_GAIN_CYCLELEN - 1 - (size_t)(rand * 7 / 256); - bbr_advance_cycle_phase(cc, ts); + bbr->state = NGTCP2_BBR_STATE_PROBE_RTT; + bbr->pacing_gain_h = 100; + bbr->cwnd_gain_h = NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H; } -static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - if (cc->state == NGTCP2_BBR_STATE_PROBE_BW && - bbr_is_next_cycle_phase(cc, cstat, ack, ts)) { - bbr_advance_cycle_phase(cc, ts); +static void bbr_handle_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + bbr_mark_connection_app_limited(bbr, cstat); + + if (bbr->probe_rtt_done_stamp == UINT64_MAX && + cstat->bytes_in_flight <= bbr_probe_rtt_cwnd(bbr, cstat)) { + bbr->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION; + bbr->probe_rtt_round_done = 0; + + bbr_start_round(bbr); + + return; + } + + if (bbr->probe_rtt_done_stamp != UINT64_MAX) { + if (bbr->round_start) { + bbr->probe_rtt_round_done = 1; + } + + if (bbr->probe_rtt_round_done) { + bbr_check_probe_rtt_done(bbr, cstat, ts); + } } } -static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) { - cc->cycle_stamp = ts; - cc->cycle_index = (cc->cycle_index + 1) & (NGTCP2_BBR_GAIN_CYCLELEN - 1); - cc->pacing_gain = pacing_gain_cycle[cc->cycle_index]; +static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (bbr->probe_rtt_done_stamp != UINT64_MAX && + ts > bbr->probe_rtt_done_stamp) { + bbr->probe_rtt_min_stamp = ts; + bbr_restore_cwnd(bbr, cstat); + bbr_exit_probe_rtt(bbr, ts); + } } -static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - int is_full_length = (ts - cc->cycle_stamp) > cc->rt_prop; +static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight; - if (cc->pacing_gain > 1) { - return is_full_length && (ack->bytes_lost > 0 || - ack->prior_bytes_in_flight >= - bbr_inflight(cc, cstat, cc->pacing_gain)); + if (app_limited) { + bbr->rst->app_limited = app_limited; + } else { + bbr->rst->app_limited = cstat->max_tx_udp_payload_size; } +} - if (cc->pacing_gain < 1) { - return is_full_length || - ack->prior_bytes_in_flight <= bbr_inflight(cc, cstat, 1); - } +static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) { + bbr_reset_lower_bounds(bbr); - return is_full_length; + if (bbr->filled_pipe) { + bbr_start_probe_bw_down(bbr, ts); + bbr_start_probe_bw_cruise(bbr); + } else { + bbr_enter_startup(bbr); + } } -static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc, - ngtcp2_conn_stat *cstat) { - if (cstat->bytes_in_flight == 0 && cc->rst->app_limited) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr restart from idle"); +static void bbr_handle_restart_from_idle(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + if (cstat->bytes_in_flight == 0 && bbr->rst->app_limited) { + ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA, "bbr restart from idle"); - cc->idle_restart = 1; + bbr->idle_restart = 1; + bbr->extra_acked_interval_start = ts; - if (cc->state == NGTCP2_BBR_STATE_PROBE_BW) { - bbr_set_pacing_rate_with_gain(cc, cstat, 1); + if (bbr_is_in_probe_bw_state(bbr)) { + bbr_set_pacing_rate_with_gain(bbr, cstat, 100); + } else if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) { + bbr_check_probe_rtt_done(bbr, cstat, ts); } } } -static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (cc->state != NGTCP2_BBR_STATE_PROBE_RTT && cc->rtprop_expired && - !cc->idle_restart) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr enter ProbeRTT"); +static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t bw, + uint64_t gain_h) { + uint64_t bdp; - bbr_enter_probe_rtt(cc); - bbr_save_cwnd(cc, cstat); - cc->probe_rtt_done_stamp = UINT64_MAX; + if (bbr->min_rtt == UINT64_MAX) { + return bbr->initial_cwnd; } - if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) { - bbr_handle_probe_rtt(cc, cstat, ts); + bdp = bw * bbr->min_rtt / NGTCP2_SECONDS; + + return (uint64_t)(bdp * gain_h / 100); +} + +static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) { + return max_udp_payload_size * 4; +} + +static uint64_t bbr_quantization_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + uint64_t inflight) { + bbr_update_offload_budget(bbr, cstat); + + inflight = ngtcp2_max(inflight, bbr->offload_budget); + inflight = + 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; } - cc->idle_restart = 0; + return inflight; } -static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc) { - cc->state = NGTCP2_BBR_STATE_PROBE_RTT; - cc->pacing_gain = 1; - cc->cwnd_gain = 1; +static uint64_t bbr_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + uint64_t bw, uint64_t gain_h) { + uint64_t inflight = bbr_bdp_multiple(bbr, bw, gain_h); + + return bbr_quantization_budget(bbr, cstat, inflight); } -static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - uint64_t app_limited = cc->rst->delivered + cstat->bytes_in_flight; +static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t inflight; + + /* Not documented */ + /* bbr_update_aggregation_budget(bbr); */ + + inflight = + bbr_bdp_multiple(bbr, bbr->bw, bbr->cwnd_gain_h) + bbr->extra_acked; + bbr->max_inflight = bbr_quantization_budget(bbr, cstat, inflight); +} - /* Ignore low rate samples during NGTCP2_BBR_STATE_PROBE_RTT. */ - cc->rst->app_limited = app_limited ? app_limited : 1; +static void bbr_update_offload_budget(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + bbr->offload_budget = 3 * cstat->send_quantum; +} - if (cc->probe_rtt_done_stamp == UINT64_MAX && - cstat->bytes_in_flight <= min_pipe_cwnd(cstat->max_udp_payload_size)) { - cc->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION; - cc->probe_rtt_round_done = 0; - cc->next_round_delivered = cc->rst->delivered; +static void bbr_advance_max_bw_filter(ngtcp2_cc_bbr *bbr) { + ++bbr->cycle_count; +} +static void bbr_modulate_cwnd_for_recovery(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + if (ack->bytes_lost > 0) { + if (cstat->cwnd > ack->bytes_lost) { + cstat->cwnd -= ack->bytes_lost; + cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_tx_udp_payload_size); + } else { + cstat->cwnd = 2 * cstat->max_tx_udp_payload_size; + } + } + + if (bbr->packet_conservation) { + cstat->cwnd = + ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered); + } +} + +static void bbr_save_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + if (!bbr->in_loss_recovery && bbr->state != NGTCP2_BBR_STATE_PROBE_RTT) { + bbr->prior_cwnd = cstat->cwnd; return; } - if (cc->probe_rtt_done_stamp != UINT64_MAX) { - if (cc->round_start) { - cc->probe_rtt_round_done = 1; + bbr->prior_cwnd = ngtcp2_max(bbr->prior_cwnd, cstat->cwnd); +} + +static void bbr_restore_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + cstat->cwnd = ngtcp2_max(cstat->cwnd, bbr->prior_cwnd); +} + +static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t probe_rtt_cwnd = + bbr_bdp_multiple(bbr, bbr->bw, NGTCP2_BBR_PROBE_RTT_CWND_GAIN_H); + uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); + + return ngtcp2_max(probe_rtt_cwnd, mpcwnd); +} + +static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t probe_rtt_cwnd; + + if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) { + probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat); + + cstat->cwnd = ngtcp2_min(cstat->cwnd, probe_rtt_cwnd); + } +} + +static void bbr_set_cwnd(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { + uint64_t mpcwnd; + + bbr_update_max_inflight(bbr, cstat); + bbr_modulate_cwnd_for_recovery(bbr, cstat, ack); + + if (!bbr->packet_conservation) { + if (bbr->filled_pipe) { + cstat->cwnd += ack->bytes_delivered; + 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(cstat->cwnd, mpcwnd); + } + + bbr_bound_cwnd_for_probe_rtt(bbr, cstat); + bbr_bound_cwnd_for_model(bbr, cstat); +} + +static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { + uint64_t cap = UINT64_MAX; + uint64_t mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); + + if (bbr_is_in_probe_bw_state(bbr) && + bbr->state != NGTCP2_BBR_STATE_PROBE_BW_CRUISE) { + cap = bbr->inflight_hi; + } else if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT || + bbr->state == NGTCP2_BBR_STATE_PROBE_BW_CRUISE) { + cap = bbr_inflight_with_headroom(bbr, cstat); + } + + cap = ngtcp2_min(cap, bbr->inflight_lo); + cap = ngtcp2_max(cap, mpcwnd); + + cstat->cwnd = ngtcp2_min(cstat->cwnd, cap); +} + +static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { + size_t floor, send_quantum; + (void)bbr; + + if (cstat->pacing_interval > (NGTCP2_SECONDS * 8 * 10 / 12) >> 20) { + floor = cstat->max_tx_udp_payload_size; + } else { + floor = 2 * cstat->max_tx_udp_payload_size; + } + + if (cstat->pacing_interval) { + send_quantum = (size_t)(NGTCP2_MILLISECONDS / cstat->pacing_interval); + send_quantum = ngtcp2_min(send_quantum, 64 * 1024); + } else { + send_quantum = 64 * 1024; + } + + cstat->send_quantum = ngtcp2_max(send_quantum, floor); +} + +static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, + ngtcp2_tstamp sent_time) { + return cstat->congestion_recovery_start_ts != UINT64_MAX && + sent_time <= cstat->congestion_recovery_start_ts; +} + +static void bbr_handle_recovery(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { + if (bbr->in_loss_recovery) { + if (ts - cstat->congestion_recovery_start_ts >= cstat->smoothed_rtt) { + bbr->packet_conservation = 0; } - if (cc->probe_rtt_round_done && ts > cc->probe_rtt_done_stamp) { - cc->rtprop_stamp = ts; - bbr_restore_cwnd(cc, cstat); - bbr_exit_probe_rtt(cc, ts); + if (ack->largest_pkt_sent_ts != UINT64_MAX && + !in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) { + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + bbr_restore_cwnd(bbr, cstat); } + + return; + } + + if (bbr->congestion_recovery_start_ts != UINT64_MAX) { + bbr->in_loss_recovery = 1; + bbr_save_cwnd(bbr, cstat); + cstat->cwnd = + cstat->bytes_in_flight + + ngtcp2_max(ack->bytes_delivered, cstat->max_tx_udp_payload_size); + + cstat->congestion_recovery_start_ts = bbr->congestion_recovery_start_ts; + bbr->congestion_recovery_start_ts = UINT64_MAX; + bbr->packet_conservation = 1; + bbr->congestion_recovery_next_round_delivered = bbr->rst->delivered; + bbr->prior_inflight_hi = bbr->inflight_hi; + bbr->prior_inflight_lo = bbr->inflight_lo; + bbr->prior_bw_lo = bbr->bw_lo; } } -static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) { - if (cc->filled_pipe) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit ProbeRTT and enter ProbeBW"); +static void bbr_cc_on_pkt_lost(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_update_on_loss(bbr, cstat, pkt, ts); +} - bbr_enter_probe_bw(cc, ts); +static void bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + if (bbr->in_loss_recovery || + bbr->congestion_recovery_start_ts != UINT64_MAX || + in_congestion_recovery(cstat, sent_ts)) { return; } - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr exit ProbeRTT and enter Startup"); + bbr->congestion_recovery_start_ts = ts; +} + +static void bbr_cc_on_spurious_congestion(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + (void)ts; + + bbr->congestion_recovery_start_ts = UINT64_MAX; + cstat->congestion_recovery_start_ts = UINT64_MAX; + + if (bbr->in_loss_recovery) { + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + bbr_restore_cwnd(bbr, cstat); + bbr->full_bw_count = 0; + bbr->loss_in_round = 0; + bbr->inflight_lo = ngtcp2_max(bbr->inflight_lo, bbr->prior_inflight_lo); + bbr->inflight_hi = ngtcp2_max(bbr->inflight_hi, bbr->prior_inflight_hi); + bbr->bw_lo = ngtcp2_max(bbr->bw_lo, bbr->prior_bw_lo); + } +} + +static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + (void)ts; + + cstat->congestion_recovery_start_ts = UINT64_MAX; + bbr->congestion_recovery_start_ts = UINT64_MAX; + bbr->in_loss_recovery = 0; + bbr->packet_conservation = 0; + + bbr_save_cwnd(bbr, cstat); + cstat->cwnd = cstat->bytes_in_flight + 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, + const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_handle_recovery(bbr, cstat, ack, ts); + bbr_update_on_ack(bbr, cstat, ack, ts); +} + +static void bbr_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_on_transmit(bbr, cstat, pkt->sent_ts); +} + +static void bbr_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc); + + bbr_on_init(bbr, cstat, ts); +} - bbr_enter_startup(cc); +void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log, + ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, + ngtcp2_tstamp initial_ts, ngtcp2_rand rand, + const ngtcp2_rand_ctx *rand_ctx) { + memset(bbr, 0, sizeof(*bbr)); + + bbr->cc.log = log; + bbr->cc.on_pkt_lost = bbr_cc_on_pkt_lost; + bbr->cc.congestion_event = bbr_cc_congestion_event; + bbr->cc.on_spurious_congestion = bbr_cc_on_spurious_congestion; + bbr->cc.on_persistent_congestion = bbr_cc_on_persistent_congestion; + bbr->cc.on_ack_recv = bbr_cc_on_ack_recv; + bbr->cc.on_pkt_sent = bbr_cc_on_pkt_sent; + bbr->cc.reset = bbr_cc_reset; + + bbr->rst = rst; + bbr->rand = rand; + bbr->rand_ctx = *rand_ctx; + bbr->initial_cwnd = cstat->cwnd; + + bbr_on_init(bbr, cstat, initial_ts); } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h index 7311f051e187bc..0017be35010e66 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h @@ -39,118 +39,108 @@ typedef struct ngtcp2_rst ngtcp2_rst; typedef enum ngtcp2_bbr_state { NGTCP2_BBR_STATE_STARTUP, NGTCP2_BBR_STATE_DRAIN, - NGTCP2_BBR_STATE_PROBE_BW, + NGTCP2_BBR_STATE_PROBE_BW_DOWN, + NGTCP2_BBR_STATE_PROBE_BW_CRUISE, + NGTCP2_BBR_STATE_PROBE_BW_REFILL, + NGTCP2_BBR_STATE_PROBE_BW_UP, NGTCP2_BBR_STATE_PROBE_RTT, } ngtcp2_bbr_state; +typedef enum ngtcp2_bbr_ack_phase { + NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING, + NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STOPPING, + NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK, + NGTCP2_BBR_ACK_PHASE_ACKS_REFILLING, +} ngtcp2_bbr_ack_phase; + /* - * ngtcp2_bbr_cc is BBR congestion controller, described in - * https://tools.ietf.org/html/draft-cardwell-iccrg-bbr-congestion-control-00 + * ngtcp2_cc_bbr is BBR v2 congestion controller, described in + * https://datatracker.ietf.org/doc/html/draft-cardwell-iccrg-bbr-congestion-control-01 */ -typedef struct ngtcp2_bbr_cc { - ngtcp2_cc_base ccb; +typedef struct ngtcp2_cc_bbr { + ngtcp2_cc cc; - /* The max filter used to estimate BBR.BtlBw. */ - ngtcp2_window_filter btl_bw_filter; uint64_t initial_cwnd; ngtcp2_rst *rst; ngtcp2_rand rand; ngtcp2_rand_ctx rand_ctx; - /* BBR variables */ + /* max_bw_filter for tracking the maximum recent delivery rate + samples for estimating max_bw. */ + ngtcp2_window_filter max_bw_filter; - /* The dynamic gain factor used to scale BBR.BtlBw to - produce BBR.pacing_rate. */ - double pacing_gain; - /* The dynamic gain factor used to scale the estimated BDP to produce a - congestion window (cwnd). */ - double cwnd_gain; - uint64_t full_bw; - /* packet.delivered value denoting the end of a packet-timed round trip. */ - uint64_t next_round_delivered; - /* Count of packet-timed round trips. */ - uint64_t round_count; - uint64_t prior_cwnd; - /* target_cwnd is the upper bound on the volume of data BBR - allows in flight. */ - uint64_t target_cwnd; - /* BBR's estimated bottleneck bandwidth available to the - transport flow, estimated from the maximum delivery rate sample in a - sliding window. */ - uint64_t btl_bw; - /* BBR's estimated two-way round-trip propagation delay of - the path, estimated from the windowed minimum recent round-trip delay - sample. */ - ngtcp2_duration rt_prop; - /* The wall clock time at which the current BBR.RTProp - sample was obtained. */ - ngtcp2_tstamp rtprop_stamp; - ngtcp2_tstamp cycle_stamp; + ngtcp2_window_filter extra_acked_filter; + + ngtcp2_duration min_rtt; + ngtcp2_tstamp min_rtt_stamp; ngtcp2_tstamp probe_rtt_done_stamp; - /* congestion_recovery_start_ts is the time when congestion recovery - period started.*/ - ngtcp2_tstamp congestion_recovery_start_ts; - uint64_t congestion_recovery_next_round_delivered; - size_t full_bw_count; - size_t cycle_index; - ngtcp2_bbr_state state; - /* A boolean that records whether BBR estimates that it has ever fully - utilized its available bandwidth ("filled the pipe"). */ - int filled_pipe; - /* A boolean that BBR sets to true once per packet-timed round trip, - on ACKs that advance BBR.round_count. */ - int round_start; - int rtprop_expired; - int idle_restart; - int packet_conservation; int probe_rtt_round_done; - /* in_loss_recovery becomes nonzero when BBR enters loss recovery - period. */ - int in_loss_recovery; -} ngtcp2_bbr_cc; - -int ngtcp2_cc_bbr_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem); - -void ngtcp2_cc_bbr_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -void ngtcp2_bbr_cc_init(ngtcp2_bbr_cc *bbr_cc, ngtcp2_conn_stat *cstat, - ngtcp2_rst *rst, ngtcp2_tstamp initial_ts, - ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx, - ngtcp2_log *log); - -void ngtcp2_bbr_cc_free(ngtcp2_bbr_cc *cc); - -void ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); + uint64_t prior_cwnd; + int idle_restart; + ngtcp2_tstamp extra_acked_interval_start; + uint64_t extra_acked_delivered; -void ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts); + /* Congestion signals */ + int loss_in_round; + uint64_t bw_latest; + uint64_t inflight_latest; -void ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + /* Lower bounds */ + uint64_t bw_lo; + uint64_t inflight_lo; -void ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc *cc, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + /* Round counting */ + uint64_t next_round_delivered; + int round_start; + uint64_t round_count; -void ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); + /* Full pipe */ + int filled_pipe; + uint64_t full_bw; + size_t full_bw_count; -void ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt); + /* Pacing rate */ + uint64_t pacing_gain_h; -void ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + ngtcp2_bbr_state state; + uint64_t cwnd_gain_h; + + int loss_round_start; + uint64_t loss_round_delivered; + uint64_t rounds_since_bw_probe; + uint64_t max_bw; + uint64_t bw; + uint64_t cycle_count; + uint64_t extra_acked; + uint64_t bytes_lost_in_round; + size_t loss_events_in_round; + uint64_t offload_budget; + uint64_t probe_up_cnt; + ngtcp2_tstamp cycle_stamp; + ngtcp2_bbr_ack_phase ack_phase; + ngtcp2_duration bw_probe_wait; + int bw_probe_samples; + size_t bw_probe_up_rounds; + uint64_t bw_probe_up_acks; + uint64_t inflight_hi; + uint64_t bw_hi; + int probe_rtt_expired; + ngtcp2_duration probe_rtt_min_delay; + ngtcp2_tstamp probe_rtt_min_stamp; + int in_loss_recovery; + int packet_conservation; + uint64_t max_inflight; + ngtcp2_tstamp congestion_recovery_start_ts; + uint64_t congestion_recovery_next_round_delivered; -void ngtcp2_cc_bbr_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); + uint64_t prior_inflight_lo; + uint64_t prior_inflight_hi; + uint64_t prior_bw_lo; +} ngtcp2_cc_bbr; -void ngtcp2_cc_bbr_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, - ngtcp2_cc_event_type event, ngtcp2_tstamp ts); +void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log, + ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, + ngtcp2_tstamp initial_ts, ngtcp2_rand rand, + const ngtcp2_rand_ctx *rand_ctx); #endif /* NGTCP2_BBR_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c deleted file mode 100644 index 585ea11e8e29a5..00000000000000 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.c +++ /dev/null @@ -1,1486 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2021 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_bbr2.h" - -#include - -#include "ngtcp2_log.h" -#include "ngtcp2_macro.h" -#include "ngtcp2_mem.h" -#include "ngtcp2_rcvry.h" -#include "ngtcp2_rst.h" - -#define NGTCP2_BBR_MAX_BW_FILTERLEN 2 - -#define NGTCP2_BBR_EXTRA_ACKED_FILTERLEN 10 - -#define NGTCP2_BBR_STARTUP_PACING_GAIN ((double)2.77) - -#define NGTCP2_BBR_STARTUP_CWND_GAIN 2 - -#define NGTCP2_BBR_PROBE_RTT_CWND_GAIN ((double)0.5) - -#define NGTCP2_BBR_BETA_NUMER 7 -#define NGTCP2_BBR_BETA_DENOM 10 - -#define NGTCP2_BBR_LOSS_THRESH_NUMER 2 -#define NGTCP2_BBR_LOSS_THRESH_DENOM 100 - -#define NGTCP2_BBR_HEADROOM_NUMER 15 -#define NGTCP2_BBR_HEADROOM_DENOM 100 - -#define NGTCP2_BBR_PROBE_RTT_INTERVAL (5 * NGTCP2_SECONDS) -#define NGTCP2_BBR_MIN_RTT_FILTERLEN (10 * NGTCP2_SECONDS) - -#define NGTCP2_BBR_PROBE_RTT_DURATION (200 * NGTCP2_MILLISECONDS) - -#define NGTCP2_BBR_PACING_MARGIN_PERCENT 1 - -static void bbr_on_init(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts); - -static void bbr_on_transmit(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_reset_congestion_signals(ngtcp2_bbr2_cc *bbr); - -static void bbr_reset_lower_bounds(ngtcp2_bbr2_cc *bbr); - -static void bbr_init_round_counting(ngtcp2_bbr2_cc *bbr); - -static void bbr_init_full_pipe(ngtcp2_bbr2_cc *bbr); - -static void bbr_init_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - double pacing_gain); - -static void bbr_set_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_enter_startup(ngtcp2_bbr2_cc *bbr); - -static void bbr_check_startup_done(ngtcp2_bbr2_cc *bbr, - const ngtcp2_cc_ack *ack); - -static void bbr_update_on_ack(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); - -static void bbr_update_model_and_state(ngtcp2_bbr2_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static void bbr_update_control_parameters(ngtcp2_bbr2_cc *cc, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_update_on_loss(ngtcp2_bbr2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); - -static void bbr_update_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_advance_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_update_congestion_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_init_lower_bounds(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_loss_lower_bounds(ngtcp2_bbr2_cc *bbr); - -static void bbr_bound_bw_for_model(ngtcp2_bbr2_cc *bbr); - -static void bbr_update_max_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_update_round(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack); - -static void bbr_start_round(ngtcp2_bbr2_cc *bbr); - -static int bbr_is_in_probe_bw_state(ngtcp2_bbr2_cc *bbr); - -static void bbr_update_ack_aggregation(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static void bbr_enter_drain(ngtcp2_bbr2_cc *bbr); - -static void bbr_check_drain(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_enter_probe_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts); - -static void bbr_start_probe_bw_down(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts); - -static void bbr_start_probe_bw_cruise(ngtcp2_bbr2_cc *bbr); - -static void bbr_start_probe_bw_refill(ngtcp2_bbr2_cc *bbr); - -static void bbr_start_probe_bw_up(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_update_probe_bw_cycle_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static int bbr_check_time_to_cruise(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); - -static int bbr_has_elapsed_in_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_duration interval, ngtcp2_tstamp ts); - -static uint64_t bbr_inflight_with_headroom(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_raise_inflight_hi_slope(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_probe_inflight_hi_upward(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_adapt_upper_bounds(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); - -static int bbr_check_time_to_probe_bw(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_pick_probe_wait(ngtcp2_bbr2_cc *bbr); - -static int bbr_is_reno_coexistence_probe_time(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static uint64_t bbr_target_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static int bbr_check_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static int is_inflight_too_high(const ngtcp2_rs *rs); - -static void bbr_handle_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_rs *rs, ngtcp2_tstamp ts); - -static void bbr_handle_lost_packet(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); - -static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_bbr2_cc *bbr, - const ngtcp2_rs *rs, - const ngtcp2_cc_pkt *pkt); - -static void bbr_update_min_rtt(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts); - -static void bbr_check_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_enter_probe_rtt(ngtcp2_bbr2_cc *bbr); - -static void bbr_handle_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static void bbr_check_probe_rtt_done(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); - -static void bbr_mark_connection_app_limited(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_exit_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts); - -static void bbr_handle_restart_from_idle(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static uint64_t bbr_bdp_multiple(ngtcp2_bbr2_cc *bbr, uint64_t bw, double gain); - -static uint64_t bbr_quantization_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - uint64_t inflight); - -static uint64_t bbr_inflight(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - uint64_t bw, double gain); - -static void bbr_update_max_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_update_offload_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static uint64_t min_pipe_cwnd(size_t max_udp_payload_size); - -static void bbr_advance_max_bw_filter(ngtcp2_bbr2_cc *bbr); - -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_save_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static void bbr_restore_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static uint64_t bbr_probe_rtt_cwnd(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_set_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_bound_cwnd_for_model(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat); - -static void bbr_set_send_quantum(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat); - -static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_time); - -static void bbr_handle_recovery(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); - -static void bbr_on_init(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp initial_ts) { - ngtcp2_window_filter_init(&bbr->max_bw_filter, NGTCP2_BBR_MAX_BW_FILTERLEN); - ngtcp2_window_filter_init(&bbr->extra_acked_filter, - NGTCP2_BBR_EXTRA_ACKED_FILTERLEN); - - bbr->min_rtt = UINT64_MAX; - bbr->min_rtt_stamp = initial_ts; - /* remark: Use UINT64_MAX instead of 0 for consistency. */ - bbr->probe_rtt_done_stamp = UINT64_MAX; - bbr->probe_rtt_round_done = 0; - bbr->prior_cwnd = 0; - bbr->idle_restart = 0; - bbr->extra_acked_interval_start = initial_ts; - bbr->extra_acked_delivered = 0; - - bbr_reset_congestion_signals(bbr); - bbr_reset_lower_bounds(bbr); - bbr_init_round_counting(bbr); - bbr_init_full_pipe(bbr); - bbr_init_pacing_rate(bbr, cstat); - bbr_enter_startup(bbr); - - cstat->send_quantum = cstat->max_udp_payload_size * 10; - - /* Missing in documentation */ - bbr->loss_round_start = 0; - bbr->loss_round_delivered = UINT64_MAX; - - bbr->rounds_since_bw_probe = 0; - - bbr->max_bw = 0; - bbr->bw = 0; - - bbr->cycle_count = 0; - - bbr->extra_acked = 0; - - bbr->bytes_lost_in_round = 0; - bbr->loss_events_in_round = 0; - - bbr->offload_budget = 0; - - bbr->probe_up_cnt = UINT64_MAX; - bbr->cycle_stamp = UINT64_MAX; - bbr->ack_phase = 0; - bbr->bw_probe_wait = 0; - bbr->bw_probe_samples = 0; - bbr->bw_probe_up_rounds = 0; - bbr->bw_probe_up_acks = 0; - - bbr->inflight_hi = UINT64_MAX; - bbr->bw_hi = UINT64_MAX; - - bbr->probe_rtt_expired = 0; - bbr->probe_rtt_min_delay = UINT64_MAX; - bbr->probe_rtt_min_stamp = initial_ts; - - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - - bbr->max_inflight = 0; - - bbr->congestion_recovery_start_ts = UINT64_MAX; - bbr->congestion_recovery_next_round_delivered = 0; - - bbr->prior_inflight_lo = 0; - bbr->prior_inflight_hi = 0; - bbr->prior_bw_lo = 0; -} - -static void bbr_reset_congestion_signals(ngtcp2_bbr2_cc *bbr) { - bbr->loss_in_round = 0; - bbr->bw_latest = 0; - bbr->inflight_latest = 0; -} - -static void bbr_reset_lower_bounds(ngtcp2_bbr2_cc *bbr) { - bbr->bw_lo = UINT64_MAX; - bbr->inflight_lo = UINT64_MAX; -} - -static void bbr_init_round_counting(ngtcp2_bbr2_cc *bbr) { - bbr->next_round_delivered = 0; - bbr->round_start = 0; - bbr->round_count = 0; -} - -static void bbr_init_full_pipe(ngtcp2_bbr2_cc *bbr) { - bbr->filled_pipe = 0; - bbr->full_bw = 0; - bbr->full_bw_count = 0; -} - -static void bbr_check_startup_full_bandwidth(ngtcp2_bbr2_cc *bbr) { - if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { - return; - } - - if (bbr->max_bw * 100 >= bbr->full_bw * 125) { - bbr->full_bw = bbr->max_bw; - bbr->full_bw_count = 0; - } - - ++bbr->full_bw_count; - - if (bbr->full_bw_count >= 3) { - bbr->filled_pipe = 1; - - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 filled pipe, full_bw=%" PRIu64, bbr->full_bw); - } -} - -static void bbr_check_startup_high_loss(ngtcp2_bbr2_cc *bbr, - const ngtcp2_cc_ack *ack) { - if (bbr->filled_pipe || !bbr->round_start || bbr->rst->rs.is_app_limited) { - return; - } - - if (bbr->loss_events_in_round <= 3) { - return; - } - - /* loss_thresh = 2% */ - if (bbr->bytes_lost_in_round * 100 <= ack->prior_bytes_in_flight * 2) { - return; - } - - bbr->filled_pipe = 1; -} - -static void bbr_init_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - double nominal_bandwidth = (double)bbr->initial_cwnd; - - cstat->pacing_rate = NGTCP2_BBR_STARTUP_PACING_GAIN * nominal_bandwidth / - (double)NGTCP2_MILLISECONDS; -} - -static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - double pacing_gain) { - double rate = pacing_gain * (double)bbr->bw * - (100 - NGTCP2_BBR_PACING_MARGIN_PERCENT) / 100 / NGTCP2_SECONDS; - - if (bbr->filled_pipe || rate > cstat->pacing_rate) { - cstat->pacing_rate = rate; - } -} - -static void bbr_set_pacing_rate(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - bbr_set_pacing_rate_with_gain(bbr, cstat, bbr->pacing_gain); -} - -static void bbr_enter_startup(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 enter Startup"); - - bbr->state = NGTCP2_BBR2_STATE_STARTUP; - bbr->pacing_gain = NGTCP2_BBR_STARTUP_PACING_GAIN; - bbr->cwnd_gain = NGTCP2_BBR_STARTUP_CWND_GAIN; -} - -static void bbr_check_startup_done(ngtcp2_bbr2_cc *bbr, - const ngtcp2_cc_ack *ack) { - bbr_check_startup_full_bandwidth(bbr); - bbr_check_startup_high_loss(bbr, ack); - - if (bbr->state == NGTCP2_BBR2_STATE_STARTUP && bbr->filled_pipe) { - bbr_enter_drain(bbr); - } -} - -static void bbr_on_transmit(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - bbr_handle_restart_from_idle(bbr, cstat, ts); -} - -static void bbr_update_on_ack(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - bbr_update_model_and_state(bbr, cstat, ack, ts); - bbr_update_control_parameters(bbr, cstat, ack); -} - -static void bbr_update_model_and_state(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - bbr_update_latest_delivery_signals(bbr, cstat); - bbr_update_congestion_signals(bbr, cstat, ack); - bbr_update_ack_aggregation(bbr, cstat, ack, ts); - bbr_check_startup_done(bbr, ack); - bbr_check_drain(bbr, cstat, ts); - bbr_update_probe_bw_cycle_phase(bbr, cstat, ack, ts); - bbr_update_min_rtt(bbr, ack, ts); - bbr_check_probe_rtt(bbr, cstat, ts); - bbr_advance_latest_delivery_signals(bbr, cstat); - bbr_bound_bw_for_model(bbr); -} - -static void bbr_update_control_parameters(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_set_pacing_rate(bbr, cstat); - bbr_set_send_quantum(bbr, cstat); - bbr_set_cwnd(bbr, cstat, ack); -} - -static void bbr_update_on_loss(ngtcp2_bbr2_cc *cc, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - bbr_handle_lost_packet(cc, cstat, pkt, ts); -} - -static void bbr_update_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - bbr->loss_round_start = 0; - bbr->bw_latest = ngtcp2_max(bbr->bw_latest, cstat->delivery_rate_sec); - bbr->inflight_latest = - 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; - bbr->loss_round_start = 1; - } -} - -static void bbr_advance_latest_delivery_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - if (bbr->loss_round_start) { - bbr->bw_latest = cstat->delivery_rate_sec; - bbr->inflight_latest = bbr->rst->rs.delivered; - } -} - -static void bbr_update_congestion_signals(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_max_bw(bbr, cstat, ack); - - if (ack->bytes_lost) { - bbr->bytes_lost_in_round += ack->bytes_lost; - ++bbr->loss_events_in_round; - - if (!bbr->loss_in_round) { - bbr->loss_in_round = 1; - bbr->loss_round_delivered = bbr->rst->delivered; - } - } - - if (!bbr->loss_round_start) { - return; - } - - bbr_adapt_lower_bounds_from_congestion(bbr, cstat); - - bbr->loss_in_round = 0; -} - -static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - if (!bbr->filled_pipe || bbr_is_in_probe_bw_state(bbr)) { - return; - } - - if (bbr->loss_in_round) { - bbr_init_lower_bounds(bbr, cstat); - bbr_loss_lower_bounds(bbr); - } -} - -static void bbr_init_lower_bounds(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - if (bbr->bw_lo == UINT64_MAX) { - bbr->bw_lo = bbr->max_bw; - } - - if (bbr->inflight_lo == UINT64_MAX) { - bbr->inflight_lo = cstat->cwnd; - } -} - -static void bbr_loss_lower_bounds(ngtcp2_bbr2_cc *bbr) { - bbr->bw_lo = ngtcp2_max(bbr->bw_latest, bbr->bw_lo * NGTCP2_BBR_BETA_NUMER / - NGTCP2_BBR_BETA_DENOM); - bbr->inflight_lo = ngtcp2_max(bbr->inflight_latest, - bbr->inflight_lo * NGTCP2_BBR_BETA_NUMER / - NGTCP2_BBR_BETA_DENOM); -} - -static void bbr_bound_bw_for_model(ngtcp2_bbr2_cc *bbr) { - bbr->bw = ngtcp2_min(bbr->max_bw, bbr->bw_lo); - bbr->bw = ngtcp2_min(bbr->bw, bbr->bw_hi); -} - -static void bbr_update_max_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - bbr_update_round(bbr, ack); - bbr_handle_recovery(bbr, cstat, ack); - - if (cstat->delivery_rate_sec >= bbr->max_bw || !bbr->rst->rs.is_app_limited) { - ngtcp2_window_filter_update(&bbr->max_bw_filter, cstat->delivery_rate_sec, - bbr->cycle_count); - - bbr->max_bw = ngtcp2_window_filter_get_best(&bbr->max_bw_filter); - } -} - -static void bbr_update_round(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack) { - if (ack->pkt_delivered >= bbr->next_round_delivered) { - bbr_start_round(bbr); - - ++bbr->round_count; - ++bbr->rounds_since_bw_probe; - bbr->round_start = 1; - - bbr->bytes_lost_in_round = 0; - bbr->loss_events_in_round = 0; - - bbr->rst->is_cwnd_limited = 0; - - return; - } - - bbr->round_start = 0; -} - -static void bbr_start_round(ngtcp2_bbr2_cc *bbr) { - bbr->next_round_delivered = bbr->rst->delivered; -} - -static int bbr_is_in_probe_bw_state(ngtcp2_bbr2_cc *bbr) { - switch (bbr->state) { - case NGTCP2_BBR2_STATE_PROBE_BW_DOWN: - case NGTCP2_BBR2_STATE_PROBE_BW_CRUISE: - case NGTCP2_BBR2_STATE_PROBE_BW_REFILL: - case NGTCP2_BBR2_STATE_PROBE_BW_UP: - return 1; - default: - return 0; - } -} - -static void bbr_update_ack_aggregation(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - ngtcp2_duration interval = ts - bbr->extra_acked_interval_start; - uint64_t expected_delivered = bbr->bw * interval / NGTCP2_SECONDS; - uint64_t extra; - - if (bbr->extra_acked_delivered <= expected_delivered) { - bbr->extra_acked_delivered = 0; - bbr->extra_acked_interval_start = ts; - expected_delivered = 0; - } - - bbr->extra_acked_delivered += ack->bytes_delivered; - extra = bbr->extra_acked_delivered - expected_delivered; - extra = ngtcp2_min(extra, cstat->cwnd); - - ngtcp2_window_filter_update(&bbr->extra_acked_filter, extra, - bbr->round_count); - - bbr->extra_acked = ngtcp2_window_filter_get_best(&bbr->extra_acked_filter); -} - -static void bbr_enter_drain(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 enter Drain"); - - bbr->state = NGTCP2_BBR2_STATE_DRAIN; - bbr->pacing_gain = 1. / NGTCP2_BBR_STARTUP_CWND_GAIN; - bbr->cwnd_gain = NGTCP2_BBR_STARTUP_CWND_GAIN; -} - -static void bbr_check_drain(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr->state == NGTCP2_BBR2_STATE_DRAIN && - cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->bw, 1.0)) { - bbr_enter_probe_bw(bbr, ts); - } -} - -static void bbr_enter_probe_bw(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts) { - bbr_start_probe_bw_down(bbr, ts); -} - -static void bbr_start_probe_bw_down(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 start ProbeBW_DOWN"); - - bbr_reset_congestion_signals(bbr); - - bbr->probe_up_cnt = UINT64_MAX; - - bbr_pick_probe_wait(bbr); - - bbr->cycle_stamp = ts; - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING; - - bbr_start_round(bbr); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_DOWN; - bbr->pacing_gain = 0.9; - bbr->cwnd_gain = 2; -} - -static void bbr_start_probe_bw_cruise(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 start ProbeBW_CRUISE"); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_CRUISE; - bbr->pacing_gain = 1.0; - bbr->cwnd_gain = 2; -} - -static void bbr_start_probe_bw_refill(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 start ProbeBW_REFILL"); - - bbr_reset_lower_bounds(bbr); - - bbr->bw_probe_up_rounds = 0; - bbr->bw_probe_up_acks = 0; - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_REFILLING; - - bbr_start_round(bbr); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_REFILL; - bbr->pacing_gain = 1.0; - bbr->cwnd_gain = 2; -} - -static void bbr_start_probe_bw_up(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 start ProbeBW_UP"); - - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STARTING; - - bbr_start_round(bbr); - - bbr->cycle_stamp = ts; - bbr->state = NGTCP2_BBR2_STATE_PROBE_BW_UP; - bbr->pacing_gain = 1.25; - bbr->cwnd_gain = 2; - - bbr_raise_inflight_hi_slope(bbr, cstat); -} - -static void bbr_update_probe_bw_cycle_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - if (!bbr->filled_pipe) { - return; - } - - bbr_adapt_upper_bounds(bbr, cstat, ack, ts); - - if (!bbr_is_in_probe_bw_state(bbr)) { - return; - } - - switch (bbr->state) { - case NGTCP2_BBR2_STATE_PROBE_BW_DOWN: - if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { - return; - } - - if (bbr_check_time_to_cruise(bbr, cstat, ts)) { - bbr_start_probe_bw_cruise(bbr); - } - - break; - case NGTCP2_BBR2_STATE_PROBE_BW_CRUISE: - if (bbr_check_time_to_probe_bw(bbr, cstat, ts)) { - return; - } - - break; - case NGTCP2_BBR2_STATE_PROBE_BW_REFILL: - if (bbr->round_start) { - bbr->bw_probe_samples = 1; - bbr_start_probe_bw_up(bbr, cstat, ts); - } - - break; - case NGTCP2_BBR2_STATE_PROBE_BW_UP: - if (bbr_has_elapsed_in_phase(bbr, bbr->min_rtt, ts) && - cstat->bytes_in_flight > bbr_inflight(bbr, cstat, bbr->max_bw, 1.25)) { - bbr_start_probe_bw_down(bbr, ts); - } - - break; - default: - break; - } -} - -static int bbr_check_time_to_cruise(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - (void)ts; - - if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) { - return 0; - } - - if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, bbr->max_bw, 1.0)) { - return 1; - } - - return 0; -} - -static int bbr_has_elapsed_in_phase(ngtcp2_bbr2_cc *bbr, - ngtcp2_duration interval, - ngtcp2_tstamp ts) { - return ts > bbr->cycle_stamp + interval; -} - -static uint64_t bbr_inflight_with_headroom(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t headroom; - uint64_t mpcwnd; - if (bbr->inflight_hi == UINT64_MAX) { - return UINT64_MAX; - } - - headroom = ngtcp2_max(cstat->max_udp_payload_size, - bbr->inflight_hi * NGTCP2_BBR_HEADROOM_NUMER / - NGTCP2_BBR_HEADROOM_DENOM); - mpcwnd = min_pipe_cwnd(cstat->max_udp_payload_size); - - if (bbr->inflight_hi > headroom) { - return ngtcp2_max(bbr->inflight_hi - headroom, mpcwnd); - } - - return mpcwnd; -} - -static void bbr_raise_inflight_hi_slope(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t growth_this_round = cstat->max_udp_payload_size - << bbr->bw_probe_up_rounds; - - 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) * - cstat->max_udp_payload_size; -} - -static void bbr_probe_inflight_hi_upward(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - uint64_t delta; - - if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_hi) { - return; - } - - bbr->bw_probe_up_acks += ack->bytes_delivered; - - if (bbr->bw_probe_up_acks >= bbr->probe_up_cnt) { - delta = bbr->bw_probe_up_acks / bbr->probe_up_cnt; - bbr->bw_probe_up_acks -= delta * bbr->probe_up_cnt; - bbr->inflight_hi += delta * cstat->max_udp_payload_size; - } - - if (bbr->round_start) { - bbr_raise_inflight_hi_slope(bbr, cstat); - } -} - -static void bbr_adapt_upper_bounds(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - if (bbr->ack_phase == NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STARTING && - bbr->round_start) { - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_FEEDBACK; - } - - if (bbr->ack_phase == NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING && - bbr->round_start) { - if (bbr_is_in_probe_bw_state(bbr) && !bbr->rst->rs.is_app_limited) { - bbr_advance_max_bw_filter(bbr); - } - } - - if (!bbr_check_inflight_too_high(bbr, cstat, ts)) { - /* bbr->bw_hi never be updated */ - if (bbr->inflight_hi == UINT64_MAX /* || bbr->bw_hi == UINT64_MAX */) { - return; - } - - if (bbr->rst->rs.tx_in_flight > bbr->inflight_hi) { - bbr->inflight_hi = bbr->rst->rs.tx_in_flight; - } - - if (cstat->delivery_rate_sec > bbr->bw_hi) { - bbr->bw_hi = cstat->delivery_rate_sec; - } - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_UP) { - bbr_probe_inflight_hi_upward(bbr, cstat, ack); - } - } -} - -static int bbr_check_time_to_probe_bw(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr_has_elapsed_in_phase(bbr, bbr->bw_probe_wait, ts) || - bbr_is_reno_coexistence_probe_time(bbr, cstat)) { - bbr_start_probe_bw_refill(bbr); - - return 1; - } - - return 0; -} - -static void bbr_pick_probe_wait(ngtcp2_bbr2_cc *bbr) { - uint8_t rand; - - bbr->rand(&rand, 1, &bbr->rand_ctx); - - bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256); - - bbr->rand(&rand, 1, &bbr->rand_ctx); - - bbr->bw_probe_wait = 2 * NGTCP2_SECONDS + - (ngtcp2_tstamp)((double)rand / 255. * NGTCP2_SECONDS); -} - -static int bbr_is_reno_coexistence_probe_time(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t reno_rounds = - bbr_target_inflight(bbr, cstat) / cstat->max_udp_payload_size; - - return bbr->rounds_since_bw_probe >= ngtcp2_min(reno_rounds, 63); -} - -static uint64_t bbr_target_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t bdp = bbr_inflight(bbr, cstat, bbr->bw, 1.0); - - return ngtcp2_min(bdp, cstat->cwnd); -} - -static int bbr_check_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (is_inflight_too_high(&bbr->rst->rs)) { - if (bbr->bw_probe_samples) { - bbr_handle_inflight_too_high(bbr, cstat, &bbr->rst->rs, ts); - } - - return 1; - } - - return 0; -} - -static int is_inflight_too_high(const ngtcp2_rs *rs) { - return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM > - rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER; -} - -static void bbr_handle_inflight_too_high(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_rs *rs, - ngtcp2_tstamp ts) { - bbr->bw_probe_samples = 0; - - if (!rs->is_app_limited) { - bbr->prior_inflight_hi = bbr->inflight_hi; - - bbr->inflight_hi = ngtcp2_max( - rs->tx_in_flight, bbr_target_inflight(bbr, cstat) * - NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); - } - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_UP) { - bbr_start_probe_bw_down(bbr, ts); - } -} - -static void bbr_handle_lost_packet(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_rs rs = {0}; - - if (!bbr->bw_probe_samples) { - return; - } - - rs.tx_in_flight = pkt->tx_in_flight; - rs.lost = bbr->rst->lost - pkt->lost; - rs.is_app_limited = pkt->is_app_limited; - - if (is_inflight_too_high(&rs)) { - rs.tx_in_flight = bbr_inflight_hi_from_lost_packet(bbr, &rs, pkt); - - bbr_handle_inflight_too_high(bbr, cstat, &rs, ts); - } -} - -static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_bbr2_cc *bbr, - const ngtcp2_rs *rs, - const ngtcp2_cc_pkt *pkt) { - uint64_t inflight_prev, lost_prefix; - (void)bbr; - - assert(rs->tx_in_flight >= pkt->pktlen); - - inflight_prev = rs->tx_in_flight - pkt->pktlen; - - assert(rs->lost >= pkt->pktlen); - - /* bbr->rst->lost is not incremented for pkt yet */ - - if (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER < - rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM) { - return inflight_prev; - } - - lost_prefix = (inflight_prev * NGTCP2_BBR_LOSS_THRESH_NUMER - - rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM) / - (NGTCP2_BBR_LOSS_THRESH_DENOM - NGTCP2_BBR_LOSS_THRESH_NUMER); - - return inflight_prev + lost_prefix; -} - -static void bbr_update_min_rtt(ngtcp2_bbr2_cc *bbr, const ngtcp2_cc_ack *ack, - ngtcp2_tstamp ts) { - int min_rtt_expired; - - bbr->probe_rtt_expired = - ts > bbr->probe_rtt_min_stamp + NGTCP2_BBR_PROBE_RTT_INTERVAL; - - if (ack->rtt != UINT64_MAX && - (ack->rtt < bbr->probe_rtt_min_delay || bbr->probe_rtt_expired)) { - bbr->probe_rtt_min_delay = ack->rtt; - bbr->probe_rtt_min_stamp = ts; - } - - min_rtt_expired = ts > bbr->min_rtt_stamp + NGTCP2_BBR_MIN_RTT_FILTERLEN; - - if (bbr->probe_rtt_min_delay < bbr->min_rtt || min_rtt_expired) { - bbr->min_rtt = bbr->probe_rtt_min_delay; - bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp; - - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 update min_rtt=%" PRIu64, bbr->min_rtt); - } -} - -static void bbr_check_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr->state != NGTCP2_BBR2_STATE_PROBE_RTT && bbr->probe_rtt_expired && - !bbr->idle_restart) { - bbr_enter_probe_rtt(bbr); - bbr_save_cwnd(bbr, cstat); - - bbr->probe_rtt_done_stamp = UINT64_MAX; - bbr->ack_phase = NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING; - - bbr_start_round(bbr); - } - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT) { - bbr_handle_probe_rtt(bbr, cstat, ts); - } - - if (bbr->rst->rs.delivered) { - bbr->idle_restart = 0; - } -} - -static void bbr_enter_probe_rtt(ngtcp2_bbr2_cc *bbr) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr2 enter ProbeRTT"); - - bbr->state = NGTCP2_BBR2_STATE_PROBE_RTT; - bbr->pacing_gain = 1; - bbr->cwnd_gain = NGTCP2_BBR_PROBE_RTT_CWND_GAIN; -} - -static void bbr_handle_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - bbr_mark_connection_app_limited(bbr, cstat); - - if (bbr->probe_rtt_done_stamp == UINT64_MAX && - cstat->bytes_in_flight <= bbr_probe_rtt_cwnd(bbr, cstat)) { - bbr->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION; - bbr->probe_rtt_round_done = 0; - - bbr_start_round(bbr); - - return; - } - - if (bbr->probe_rtt_done_stamp != UINT64_MAX) { - if (bbr->round_start) { - bbr->probe_rtt_round_done = 1; - } - - if (bbr->probe_rtt_round_done) { - bbr_check_probe_rtt_done(bbr, cstat, ts); - } - } -} - -static void bbr_check_probe_rtt_done(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (bbr->probe_rtt_done_stamp != UINT64_MAX && - ts > bbr->probe_rtt_done_stamp) { - bbr->probe_rtt_min_stamp = ts; - bbr_restore_cwnd(bbr, cstat); - bbr_exit_probe_rtt(bbr, ts); - } -} - -static void bbr_mark_connection_app_limited(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight; - - if (app_limited) { - bbr->rst->app_limited = app_limited; - } else { - bbr->rst->app_limited = cstat->max_udp_payload_size; - } -} - -static void bbr_exit_probe_rtt(ngtcp2_bbr2_cc *bbr, ngtcp2_tstamp ts) { - bbr_reset_lower_bounds(bbr); - - if (bbr->filled_pipe) { - bbr_start_probe_bw_down(bbr, ts); - bbr_start_probe_bw_cruise(bbr); - } else { - bbr_enter_startup(bbr); - } -} - -static void bbr_handle_restart_from_idle(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (cstat->bytes_in_flight == 0 && bbr->rst->app_limited) { - ngtcp2_log_info(bbr->ccb.log, NGTCP2_LOG_EVENT_RCV, - "bbr2 restart from idle"); - - bbr->idle_restart = 1; - bbr->extra_acked_interval_start = ts; - - if (bbr_is_in_probe_bw_state(bbr)) { - bbr_set_pacing_rate_with_gain(bbr, cstat, 1); - } else if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT) { - bbr_check_probe_rtt_done(bbr, cstat, ts); - } - } -} - -static uint64_t bbr_bdp_multiple(ngtcp2_bbr2_cc *bbr, uint64_t bw, - double gain) { - uint64_t bdp; - - if (bbr->min_rtt == UINT64_MAX) { - return bbr->initial_cwnd; - } - - bdp = bw * bbr->min_rtt / NGTCP2_SECONDS; - - return (uint64_t)(gain * (double)bdp); -} - -static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) { - return max_udp_payload_size * 4; -} - -static uint64_t bbr_quantization_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - uint64_t inflight) { - bbr_update_offload_budget(bbr, cstat); - - inflight = ngtcp2_max(inflight, bbr->offload_budget); - inflight = ngtcp2_max(inflight, min_pipe_cwnd(cstat->max_udp_payload_size)); - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_UP) { - inflight += 2 * cstat->max_udp_payload_size; - } - - return inflight; -} - -static uint64_t bbr_inflight(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - uint64_t bw, double gain) { - uint64_t inflight = bbr_bdp_multiple(bbr, bw, gain); - - return bbr_quantization_budget(bbr, cstat, inflight); -} - -static void bbr_update_max_inflight(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t inflight; - - /* Not documented */ - /* bbr_update_aggregation_budget(bbr); */ - - inflight = bbr_bdp_multiple(bbr, bbr->bw, bbr->cwnd_gain) + bbr->extra_acked; - bbr->max_inflight = bbr_quantization_budget(bbr, cstat, inflight); -} - -static void bbr_update_offload_budget(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - bbr->offload_budget = 3 * cstat->send_quantum; -} - -static void bbr_advance_max_bw_filter(ngtcp2_bbr2_cc *bbr) { - ++bbr->cycle_count; -} - -static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (ack->bytes_lost > 0) { - if (cstat->cwnd > ack->bytes_lost) { - cstat->cwnd -= ack->bytes_lost; - cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_udp_payload_size); - } else { - cstat->cwnd = cstat->max_udp_payload_size; - } - } - - if (bbr->packet_conservation) { - cstat->cwnd = - ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered); - } -} - -static void bbr_save_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - if (!bbr->in_loss_recovery && bbr->state != NGTCP2_BBR2_STATE_PROBE_RTT) { - bbr->prior_cwnd = cstat->cwnd; - return; - } - - bbr->prior_cwnd = ngtcp2_max(bbr->prior_cwnd, cstat->cwnd); -} - -static void bbr_restore_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - cstat->cwnd = ngtcp2_max(cstat->cwnd, bbr->prior_cwnd); -} - -static uint64_t bbr_probe_rtt_cwnd(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t probe_rtt_cwnd = - bbr_bdp_multiple(bbr, bbr->bw, NGTCP2_BBR_PROBE_RTT_CWND_GAIN); - uint64_t mpcwnd = min_pipe_cwnd(cstat->max_udp_payload_size); - - return ngtcp2_max(probe_rtt_cwnd, mpcwnd); -} - -static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t probe_rtt_cwnd; - - if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT) { - probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat); - - cstat->cwnd = ngtcp2_min(cstat->cwnd, probe_rtt_cwnd); - } -} - -static void bbr_set_cwnd(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - uint64_t mpcwnd; - - bbr_update_max_inflight(bbr, cstat); - bbr_modulate_cwnd_for_recovery(bbr, cstat, ack); - - if (!bbr->packet_conservation) { - if (bbr->filled_pipe) { - cstat->cwnd += ack->bytes_delivered; - 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_udp_payload_size); - cstat->cwnd = ngtcp2_max(cstat->cwnd, mpcwnd); - } - - bbr_bound_cwnd_for_probe_rtt(bbr, cstat); - bbr_bound_cwnd_for_model(bbr, cstat); -} - -static void bbr_bound_cwnd_for_model(ngtcp2_bbr2_cc *bbr, - ngtcp2_conn_stat *cstat) { - uint64_t cap = UINT64_MAX; - uint64_t mpcwnd = min_pipe_cwnd(cstat->max_udp_payload_size); - - if (bbr_is_in_probe_bw_state(bbr) && - bbr->state != NGTCP2_BBR2_STATE_PROBE_BW_CRUISE) { - cap = bbr->inflight_hi; - } else if (bbr->state == NGTCP2_BBR2_STATE_PROBE_RTT || - bbr->state == NGTCP2_BBR2_STATE_PROBE_BW_CRUISE) { - cap = bbr_inflight_with_headroom(bbr, cstat); - } - - cap = ngtcp2_min(cap, bbr->inflight_lo); - cap = ngtcp2_max(cap, mpcwnd); - - cstat->cwnd = ngtcp2_min(cstat->cwnd, cap); -} - -static void bbr_set_send_quantum(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat) { - size_t send_quantum = - (size_t)(cstat->pacing_rate * (double)(bbr->min_rtt == UINT64_MAX - ? NGTCP2_MILLISECONDS - : bbr->min_rtt)); - (void)bbr; - - cstat->send_quantum = ngtcp2_min(send_quantum, 64 * 1024); - cstat->send_quantum = - ngtcp2_max(cstat->send_quantum, cstat->max_udp_payload_size * 10); -} - -static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_time) { - return cstat->congestion_recovery_start_ts != UINT64_MAX && - sent_time <= cstat->congestion_recovery_start_ts; -} - -static void bbr_handle_recovery(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { - if (bbr->in_loss_recovery) { - if (ack->pkt_delivered >= bbr->congestion_recovery_next_round_delivered) { - bbr->packet_conservation = 0; - } - - if (!in_congestion_recovery(cstat, ack->largest_acked_sent_ts)) { - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - bbr_restore_cwnd(bbr, cstat); - } - - return; - } - - if (bbr->congestion_recovery_start_ts != UINT64_MAX) { - bbr->in_loss_recovery = 1; - bbr_save_cwnd(bbr, cstat); - cstat->cwnd = cstat->bytes_in_flight + - ngtcp2_max(ack->bytes_delivered, cstat->max_udp_payload_size); - - cstat->congestion_recovery_start_ts = bbr->congestion_recovery_start_ts; - bbr->congestion_recovery_start_ts = UINT64_MAX; - bbr->packet_conservation = 1; - bbr->congestion_recovery_next_round_delivered = bbr->rst->delivered; - bbr->prior_inflight_lo = bbr->inflight_lo; - bbr->prior_bw_lo = bbr->bw_lo; - } -} - -static void bbr2_cc_init(ngtcp2_bbr2_cc *bbr, ngtcp2_conn_stat *cstat, - ngtcp2_rst *rst, ngtcp2_tstamp initial_ts, - ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx, - ngtcp2_log *log) { - bbr->ccb.log = log; - bbr->rst = rst; - bbr->rand = rand; - bbr->rand_ctx = *rand_ctx; - bbr->initial_cwnd = cstat->cwnd; - - bbr_on_init(bbr, cstat, initial_ts); -} - -static void bbr2_cc_free(ngtcp2_bbr2_cc *bbr) { (void)bbr; } - -static void bbr2_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)pkt; - (void)ts; -} - -static void bbr2_cc_on_pkt_lost(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_update_on_loss(bbr, cstat, pkt, ts); -} - -static void bbr2_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - if (!bbr->filled_pipe || bbr->in_loss_recovery || - bbr->congestion_recovery_start_ts != UINT64_MAX || - in_congestion_recovery(cstat, sent_ts)) { - return; - } - - bbr->congestion_recovery_start_ts = ts; -} - -static void bbr2_cc_on_spurious_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - (void)ts; - - bbr->congestion_recovery_start_ts = UINT64_MAX; - cstat->congestion_recovery_start_ts = UINT64_MAX; - - if (bbr->in_loss_recovery) { - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - bbr_restore_cwnd(bbr, cstat); - bbr->full_bw_count = 0; - bbr->loss_in_round = 0; - bbr->inflight_lo = ngtcp2_max(bbr->inflight_lo, bbr->prior_inflight_lo); - bbr->inflight_hi = ngtcp2_max(bbr->inflight_hi, bbr->prior_inflight_hi); - bbr->bw_lo = ngtcp2_max(bbr->bw_lo, bbr->prior_bw_lo); - } -} - -static void bbr2_cc_on_persistent_congestion(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - (void)ts; - - cstat->congestion_recovery_start_ts = UINT64_MAX; - bbr->congestion_recovery_start_ts = UINT64_MAX; - bbr->in_loss_recovery = 0; - bbr->packet_conservation = 0; - - bbr_save_cwnd(bbr, cstat); - cstat->cwnd = cstat->bytes_in_flight + cstat->max_udp_payload_size; - cstat->cwnd = - ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_udp_payload_size)); -} - -static void bbr2_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_update_on_ack(bbr, cstat, ack, ts); -} - -static void bbr2_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_pkt *pkt) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_on_transmit(bbr, cstat, pkt->sent_ts); -} - -static void bbr2_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)ts; -} - -static void bbr2_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr2_cc, ccb); - - bbr_on_init(bbr, cstat, ts); -} - -static void bbr2_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, - ngtcp2_cc_event_type event, ngtcp2_tstamp ts) { - (void)ccx; - (void)cstat; - (void)event; - (void)ts; -} - -int ngtcp2_cc_bbr2_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem) { - ngtcp2_bbr2_cc *bbr; - - bbr = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_bbr2_cc)); - if (bbr == NULL) { - return NGTCP2_ERR_NOMEM; - } - - bbr2_cc_init(bbr, cstat, rst, initial_ts, rand, rand_ctx, log); - - cc->ccb = &bbr->ccb; - cc->on_pkt_acked = bbr2_cc_on_pkt_acked; - cc->on_pkt_lost = bbr2_cc_on_pkt_lost; - cc->congestion_event = bbr2_cc_congestion_event; - cc->on_spurious_congestion = bbr2_cc_on_spurious_congestion; - cc->on_persistent_congestion = bbr2_cc_on_persistent_congestion; - cc->on_ack_recv = bbr2_cc_on_ack_recv; - cc->on_pkt_sent = bbr2_cc_on_pkt_sent; - cc->new_rtt_sample = bbr2_cc_new_rtt_sample; - cc->reset = bbr2_cc_reset; - cc->event = bbr2_cc_event; - - return 0; -} - -void ngtcp2_cc_bbr2_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_bbr2_cc *bbr = ngtcp2_struct_of(cc->ccb, ngtcp2_bbr2_cc, ccb); - - bbr2_cc_free(bbr); - ngtcp2_mem_free(mem, bbr); -} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h deleted file mode 100644 index 50dc05a5f26121..00000000000000 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr2.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2021 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_BBR2_H -#define NGTCP2_BBR2_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include "ngtcp2_cc.h" -#include "ngtcp2_window_filter.h" - -typedef struct ngtcp2_rst ngtcp2_rst; - -typedef enum ngtcp2_bbr2_state { - NGTCP2_BBR2_STATE_STARTUP, - NGTCP2_BBR2_STATE_DRAIN, - NGTCP2_BBR2_STATE_PROBE_BW_DOWN, - NGTCP2_BBR2_STATE_PROBE_BW_CRUISE, - NGTCP2_BBR2_STATE_PROBE_BW_REFILL, - NGTCP2_BBR2_STATE_PROBE_BW_UP, - NGTCP2_BBR2_STATE_PROBE_RTT, -} ngtcp2_bbr2_state; - -typedef enum ngtcp2_bbr2_ack_phase { - NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STARTING, - NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING, - NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_FEEDBACK, - NGTCP2_BBR2_ACK_PHASE_ACKS_REFILLING, -} ngtcp2_bbr2_ack_phase; - -/* - * ngtcp2_bbr2_cc is BBR v2 congestion controller, described in - * https://datatracker.ietf.org/doc/html/draft-cardwell-iccrg-bbr-congestion-control-01 - */ -typedef struct ngtcp2_bbr2_cc { - ngtcp2_cc_base ccb; - - uint64_t initial_cwnd; - ngtcp2_rst *rst; - ngtcp2_rand rand; - ngtcp2_rand_ctx rand_ctx; - - /* max_bw_filter for tracking the maximum recent delivery rate - samples for estimating max_bw. */ - ngtcp2_window_filter max_bw_filter; - - ngtcp2_window_filter extra_acked_filter; - - ngtcp2_duration min_rtt; - ngtcp2_tstamp min_rtt_stamp; - ngtcp2_tstamp probe_rtt_done_stamp; - int probe_rtt_round_done; - uint64_t prior_cwnd; - int idle_restart; - ngtcp2_tstamp extra_acked_interval_start; - uint64_t extra_acked_delivered; - - /* Congestion signals */ - int loss_in_round; - uint64_t bw_latest; - uint64_t inflight_latest; - - /* Lower bounds */ - uint64_t bw_lo; - uint64_t inflight_lo; - - /* Round counting */ - uint64_t next_round_delivered; - int round_start; - uint64_t round_count; - - /* Full pipe */ - int filled_pipe; - uint64_t full_bw; - size_t full_bw_count; - - /* Pacing rate */ - double pacing_gain; - - ngtcp2_bbr2_state state; - double cwnd_gain; - - int loss_round_start; - uint64_t loss_round_delivered; - uint64_t rounds_since_bw_probe; - uint64_t max_bw; - uint64_t bw; - uint64_t cycle_count; - uint64_t extra_acked; - uint64_t bytes_lost_in_round; - size_t loss_events_in_round; - uint64_t offload_budget; - uint64_t probe_up_cnt; - ngtcp2_tstamp cycle_stamp; - ngtcp2_bbr2_ack_phase ack_phase; - ngtcp2_duration bw_probe_wait; - int bw_probe_samples; - size_t bw_probe_up_rounds; - uint64_t bw_probe_up_acks; - uint64_t inflight_hi; - uint64_t bw_hi; - int probe_rtt_expired; - ngtcp2_duration probe_rtt_min_delay; - ngtcp2_tstamp probe_rtt_min_stamp; - int in_loss_recovery; - int packet_conservation; - uint64_t max_inflight; - ngtcp2_tstamp congestion_recovery_start_ts; - uint64_t congestion_recovery_next_round_delivered; - - uint64_t prior_inflight_lo; - uint64_t prior_inflight_hi; - uint64_t prior_bw_lo; -} ngtcp2_bbr2_cc; - -int ngtcp2_cc_bbr2_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_conn_stat *cstat, ngtcp2_rst *rst, - ngtcp2_tstamp initial_ts, ngtcp2_rand rand, - const ngtcp2_rand_ctx *rand_ctx, - const ngtcp2_mem *mem); - -void ngtcp2_cc_bbr2_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -#endif /* NGTCP2_BBR2_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c index 1ee7d96b04776e..6369887c28671b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c @@ -25,6 +25,7 @@ #include "ngtcp2_cc.h" #include +#include #if defined(_MSC_VER) # include @@ -34,6 +35,11 @@ #include "ngtcp2_macro.h" #include "ngtcp2_mem.h" #include "ngtcp2_rcvry.h" +#include "ngtcp2_conn_stat.h" + +/* NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN is the window length of + delivery rate filter driven by ACK clocking. */ +#define NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN 10 uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) { uint64_t n = 2 * max_udp_payload_size; @@ -56,45 +62,26 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num, return pkt; } -static void reno_cc_reset(ngtcp2_reno_cc *cc) { - cc->max_delivery_rate_sec = 0; - cc->target_cwnd = 0; - cc->pending_add = 0; -} - -void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log) { - cc->ccb.log = log; - reno_cc_reset(cc); +static void reno_cc_reset(ngtcp2_cc_reno *reno) { + ngtcp2_window_filter_init(&reno->delivery_rate_sec_filter, + NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN); + reno->ack_count = 0; + reno->target_cwnd = 0; + reno->pending_add = 0; } -void ngtcp2_reno_cc_free(ngtcp2_reno_cc *cc) { (void)cc; } - -int ngtcp2_cc_reno_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem) { - ngtcp2_reno_cc *reno_cc; - - reno_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_reno_cc)); - if (reno_cc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_reno_cc_init(reno_cc, log); - - cc->ccb = &reno_cc->ccb; - cc->on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked; - cc->congestion_event = ngtcp2_cc_reno_cc_congestion_event; - cc->on_persistent_congestion = ngtcp2_cc_reno_cc_on_persistent_congestion; - cc->on_ack_recv = ngtcp2_cc_reno_cc_on_ack_recv; - cc->reset = ngtcp2_cc_reno_cc_reset; - - return 0; -} +void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) { + memset(reno, 0, sizeof(*reno)); -void ngtcp2_cc_reno_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_reno_cc *reno_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_reno_cc, ccb); + reno->cc.log = log; + reno->cc.on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked; + reno->cc.congestion_event = ngtcp2_cc_reno_cc_congestion_event; + reno->cc.on_persistent_congestion = + ngtcp2_cc_reno_cc_on_persistent_congestion; + reno->cc.on_ack_recv = ngtcp2_cc_reno_cc_on_ack_recv; + reno->cc.reset = ngtcp2_cc_reno_cc_reset; - ngtcp2_reno_cc_free(reno_cc); - ngtcp2_mem_free(mem, reno_cc); + reno_cc_reset(reno); } static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, @@ -103,10 +90,10 @@ static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, sent_time <= cstat->congestion_recovery_start_ts; } -void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); uint64_t m; (void)ts; @@ -114,28 +101,28 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, return; } - if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) { + if (reno->target_cwnd && reno->target_cwnd < cstat->cwnd) { return; } if (cstat->cwnd < cstat->ssthresh) { cstat->cwnd += pkt->pktlen; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA, "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64, pkt->pkt_num, cstat->cwnd); return; } - m = cstat->max_udp_payload_size * pkt->pktlen + cc->pending_add; - cc->pending_add = m % cstat->cwnd; + m = cstat->max_tx_udp_payload_size * pkt->pktlen + reno->pending_add; + reno->pending_add = m % cstat->cwnd; cstat->cwnd += m / cstat->cwnd; } -void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); uint64_t min_cwnd; if (in_congestion_recovery(cstat, sent_ts)) { @@ -144,123 +131,109 @@ void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, cstat->congestion_recovery_start_ts = ts; cstat->cwnd >>= NGTCP2_LOSS_REDUCTION_FACTOR_BITS; - min_cwnd = 2 * cstat->max_udp_payload_size; + min_cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->cwnd = ngtcp2_max(cstat->cwnd, min_cwnd); cstat->ssthresh = cstat->cwnd; - cc->pending_add = 0; + reno->pending_add = 0; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA, "reduce cwnd because of packet loss cwnd=%" PRIu64, cstat->cwnd); } -void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *ccx, +void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - (void)ccx; + (void)cc; (void)ts; - cstat->cwnd = 2 * cstat->max_udp_payload_size; + cstat->cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->congestion_recovery_start_ts = UINT64_MAX; } -void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); uint64_t target_cwnd, initcwnd; + uint64_t max_delivery_rate_sec; (void)ack; (void)ts; - /* TODO Use sliding window for min rtt measurement */ - /* TODO Use sliding window */ - cc->max_delivery_rate_sec = - ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec); + ++reno->ack_count; - if (cstat->min_rtt != UINT64_MAX && cc->max_delivery_rate_sec) { - target_cwnd = cc->max_delivery_rate_sec * cstat->min_rtt / NGTCP2_SECONDS; - initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_udp_payload_size); - cc->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; + ngtcp2_window_filter_update(&reno->delivery_rate_sec_filter, + cstat->delivery_rate_sec, reno->ack_count); - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + max_delivery_rate_sec = + ngtcp2_window_filter_get_best(&reno->delivery_rate_sec_filter); + + if (cstat->min_rtt != UINT64_MAX && max_delivery_rate_sec) { + target_cwnd = max_delivery_rate_sec * cstat->smoothed_rtt / NGTCP2_SECONDS; + initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size); + reno->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; + + ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA, "target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64 - " min_rtt=%" PRIu64, - cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt); + " smoothed_rtt=%" PRIu64, + reno->target_cwnd, max_delivery_rate_sec, + cstat->smoothed_rtt); } } -void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc); (void)cstat; (void)ts; - reno_cc_reset(cc); -} - -static void cubic_cc_reset(ngtcp2_cubic_cc *cc) { - cc->max_delivery_rate_sec = 0; - cc->target_cwnd = 0; - cc->w_last_max = 0; - cc->w_tcp = 0; - cc->origin_point = 0; - cc->epoch_start = UINT64_MAX; - cc->k = 0; - - cc->prior.cwnd = 0; - cc->prior.ssthresh = 0; - cc->prior.w_last_max = 0; - cc->prior.w_tcp = 0; - cc->prior.origin_point = 0; - cc->prior.epoch_start = UINT64_MAX; - cc->prior.k = 0; - - cc->rtt_sample_count = 0; - cc->current_round_min_rtt = UINT64_MAX; - cc->last_round_min_rtt = UINT64_MAX; - cc->window_end = -1; -} - -void ngtcp2_cubic_cc_init(ngtcp2_cubic_cc *cc, ngtcp2_log *log) { - cc->ccb.log = log; - cubic_cc_reset(cc); + reno_cc_reset(reno); } -void ngtcp2_cubic_cc_free(ngtcp2_cubic_cc *cc) { (void)cc; } - -int ngtcp2_cc_cubic_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem) { - ngtcp2_cubic_cc *cubic_cc; - - cubic_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_cubic_cc)); - if (cubic_cc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_cubic_cc_init(cubic_cc, log); - - cc->ccb = &cubic_cc->ccb; - cc->on_pkt_acked = ngtcp2_cc_cubic_cc_on_pkt_acked; - cc->congestion_event = ngtcp2_cc_cubic_cc_congestion_event; - cc->on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion; - cc->on_persistent_congestion = ngtcp2_cc_cubic_cc_on_persistent_congestion; - cc->on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv; - cc->on_pkt_sent = ngtcp2_cc_cubic_cc_on_pkt_sent; - cc->new_rtt_sample = ngtcp2_cc_cubic_cc_new_rtt_sample; - cc->reset = ngtcp2_cc_cubic_cc_reset; - cc->event = ngtcp2_cc_cubic_cc_event; - - return 0; +static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) { + ngtcp2_window_filter_init(&cubic->delivery_rate_sec_filter, + NGTCP2_CC_DELIVERY_RATE_SEC_FILTERLEN); + cubic->ack_count = 0; + cubic->target_cwnd = 0; + cubic->w_last_max = 0; + cubic->w_tcp = 0; + cubic->origin_point = 0; + cubic->epoch_start = UINT64_MAX; + cubic->k = 0; + + cubic->prior.cwnd = 0; + cubic->prior.ssthresh = 0; + cubic->prior.w_last_max = 0; + cubic->prior.w_tcp = 0; + cubic->prior.origin_point = 0; + cubic->prior.epoch_start = UINT64_MAX; + cubic->prior.k = 0; + + cubic->rtt_sample_count = 0; + cubic->current_round_min_rtt = UINT64_MAX; + cubic->last_round_min_rtt = UINT64_MAX; + cubic->window_end = -1; } -void ngtcp2_cc_cubic_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) { - ngtcp2_cubic_cc *cubic_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_cubic_cc, ccb); - - ngtcp2_cubic_cc_free(cubic_cc); - ngtcp2_mem_free(mem, cubic_cc); +void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log) { + memset(cubic, 0, sizeof(*cubic)); + + cubic->cc.log = log; + cubic->cc.on_pkt_acked = ngtcp2_cc_cubic_cc_on_pkt_acked; + cubic->cc.congestion_event = ngtcp2_cc_cubic_cc_congestion_event; + cubic->cc.on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion; + cubic->cc.on_persistent_congestion = + ngtcp2_cc_cubic_cc_on_persistent_congestion; + cubic->cc.on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv; + cubic->cc.on_pkt_sent = ngtcp2_cc_cubic_cc_on_pkt_sent; + cubic->cc.new_rtt_sample = ngtcp2_cc_cubic_cc_new_rtt_sample; + cubic->cc.reset = ngtcp2_cc_cubic_cc_reset; + cubic->cc.event = ngtcp2_cc_cubic_cc_event; + + cubic_cc_reset(cubic); } -static uint64_t ngtcp2_cbrt(uint64_t n) { +uint64_t ngtcp2_cbrt(uint64_t n) { int d; uint64_t a; @@ -269,26 +242,23 @@ static uint64_t ngtcp2_cbrt(uint64_t n) { } #if defined(_MSC_VER) -# if defined(_M_X64) - d = (int)__lzcnt64(n); -# elif defined(_M_ARM64) { unsigned long index; - d = sizeof(uint64_t) * CHAR_BIT; +# if defined(_WIN64) if (_BitScanReverse64(&index, n)) { - d = d - 1 - index; + d = 61 - index; } +# else /* !defined(_WIN64) */ + if (_BitScanReverse(&index, (unsigned int)(n >> 32))) { + d = 31 - index; + } else { + d = 32 + 31 - _BitScanReverse(&index, (unsigned int)n); + } +# endif /* !defined(_WIN64) */ } -# else - if ((n >> 32) != 0) { - d = __lzcnt((unsigned int)(n >> 32)); - } else { - d = 32 + __lzcnt((unsigned int)n); - } -# endif -#else +#else /* !defined(_MSC_VER) */ d = __builtin_clzll(n); -#endif +#endif /* !defined(_MSC_VER) */ a = 1ULL << ((64 - d) / 3 + 1); for (; a * a * a > n;) { @@ -303,42 +273,41 @@ static uint64_t ngtcp2_cbrt(uint64_t n) { #define NGTCP2_HS_MIN_ETA (4 * NGTCP2_MILLISECONDS) #define NGTCP2_HS_MAX_ETA (16 * NGTCP2_MILLISECONDS) -void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); - ngtcp2_duration t, min_rtt, eta; - uint64_t target; + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); + ngtcp2_duration t, eta; + uint64_t target, cwnd_thres; uint64_t tx, kx, time_delta, delta; uint64_t add, tcp_add; uint64_t m; - if (pkt->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && cc->window_end != -1 && - cc->window_end <= pkt->pkt_num) { - cc->window_end = -1; + if (pkt->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && cubic->window_end != -1 && + cubic->window_end <= pkt->pkt_num) { + cubic->window_end = -1; } if (in_congestion_recovery(cstat, pkt->sent_ts)) { return; } - if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) { - return; - } - if (cstat->cwnd < cstat->ssthresh) { /* slow-start */ - cstat->cwnd += pkt->pktlen; + if (cubic->target_cwnd == 0 || cubic->target_cwnd > cstat->cwnd) { + cstat->cwnd += pkt->pktlen; + } - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64, pkt->pkt_num, cstat->cwnd); - if (cc->last_round_min_rtt != UINT64_MAX && - cc->current_round_min_rtt != UINT64_MAX && - cstat->cwnd >= NGTCP2_HS_MIN_SSTHRESH * cstat->max_udp_payload_size && - cc->rtt_sample_count >= NGTCP2_HS_N_RTT_SAMPLE) { - eta = cc->last_round_min_rtt / 8; + if (cubic->last_round_min_rtt != UINT64_MAX && + cubic->current_round_min_rtt != UINT64_MAX && + cstat->cwnd >= + NGTCP2_HS_MIN_SSTHRESH * cstat->max_tx_udp_payload_size && + cubic->rtt_sample_count >= NGTCP2_HS_N_RTT_SAMPLE) { + eta = cubic->last_round_min_rtt / 8; if (eta < NGTCP2_HS_MIN_ETA) { eta = NGTCP2_HS_MIN_ETA; @@ -346,11 +315,11 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, eta = NGTCP2_HS_MAX_ETA; } - if (cc->current_round_min_rtt >= cc->last_round_min_rtt + eta) { - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + if (cubic->current_round_min_rtt >= cubic->last_round_min_rtt + eta) { + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "HyStart++ exit slow start"); - cc->w_last_max = cstat->cwnd; + cubic->w_last_max = cstat->cwnd; cstat->ssthresh = cstat->cwnd; } } @@ -360,34 +329,32 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, /* congestion avoidance */ - if (cc->epoch_start == UINT64_MAX) { - cc->epoch_start = ts; - if (cstat->cwnd < cc->w_last_max) { - cc->k = ngtcp2_cbrt((cc->w_last_max - cstat->cwnd) * 10 / 4 / - cstat->max_udp_payload_size); - cc->origin_point = cc->w_last_max; + if (cubic->epoch_start == UINT64_MAX) { + cubic->epoch_start = ts; + if (cstat->cwnd < cubic->w_last_max) { + cubic->k = ngtcp2_cbrt((cubic->w_last_max - cstat->cwnd) * 10 / 4 / + cstat->max_tx_udp_payload_size); + cubic->origin_point = cubic->w_last_max; } else { - cc->k = 0; - cc->origin_point = cstat->cwnd; + cubic->k = 0; + cubic->origin_point = cstat->cwnd; } - cc->w_tcp = cstat->cwnd; + cubic->w_tcp = cstat->cwnd; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "cubic-ca epoch_start=%" PRIu64 " k=%" PRIu64 " origin_point=%" PRIu64, - cc->epoch_start, cc->k, cc->origin_point); + cubic->epoch_start, cubic->k, cubic->origin_point); - cc->pending_add = 0; - cc->pending_w_add = 0; + cubic->pending_add = 0; + cubic->pending_w_add = 0; } - min_rtt = cstat->min_rtt == UINT64_MAX ? cstat->initial_rtt : cstat->min_rtt; + t = ts - cubic->epoch_start; - t = ts + min_rtt - cc->epoch_start; - - tx = (t << 4) / NGTCP2_SECONDS; - kx = (cc->k << 4); + tx = (t << 10) / NGTCP2_SECONDS; + kx = (cubic->k << 10); if (tx > kx) { time_delta = tx - kx; @@ -395,210 +362,229 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, time_delta = kx - tx; } - delta = cstat->max_udp_payload_size * - ((((time_delta * time_delta) >> 4) * time_delta) >> 8) * 4 / 10; + delta = cstat->max_tx_udp_payload_size * + ((((time_delta * time_delta) >> 10) * time_delta) >> 10) * 4 / 10; + delta >>= 10; if (tx > kx) { - target = cc->origin_point + delta; + target = cubic->origin_point + delta; + } else { + target = cubic->origin_point - delta; + } + + cwnd_thres = + (target * (((t + cstat->smoothed_rtt) << 10) / NGTCP2_SECONDS)) >> 10; + if (cwnd_thres < cstat->cwnd) { + target = cstat->cwnd; + } else if (2 * cwnd_thres > 3 * cstat->cwnd) { + target = cstat->cwnd * 3 / 2; } else { - target = cc->origin_point - delta; + target = cwnd_thres; } if (target > cstat->cwnd) { - m = cc->pending_add + cstat->max_udp_payload_size * (target - cstat->cwnd); + m = cubic->pending_add + + cstat->max_tx_udp_payload_size * (target - cstat->cwnd); add = m / cstat->cwnd; - cc->pending_add = m % cstat->cwnd; + cubic->pending_add = m % cstat->cwnd; } else { - m = cc->pending_add + cstat->max_udp_payload_size; + m = cubic->pending_add + cstat->max_tx_udp_payload_size; add = m / (100 * cstat->cwnd); - cc->pending_add = m % (100 * cstat->cwnd); + cubic->pending_add = m % (100 * cstat->cwnd); } - m = cc->pending_w_add + cstat->max_udp_payload_size * pkt->pktlen; + m = cubic->pending_w_add + cstat->max_tx_udp_payload_size * pkt->pktlen; - cc->w_tcp += m / cstat->cwnd; - cc->pending_w_add = m % cstat->cwnd; + cubic->w_tcp += m / cstat->cwnd; + cubic->pending_w_add = m % cstat->cwnd; - if (cc->w_tcp > cstat->cwnd) { - tcp_add = - cstat->max_udp_payload_size * (cc->w_tcp - cstat->cwnd) / cstat->cwnd; + if (cubic->w_tcp > cstat->cwnd) { + tcp_add = cstat->max_tx_udp_payload_size * (cubic->w_tcp - cstat->cwnd) / + cstat->cwnd; if (tcp_add > add) { add = tcp_add; } } - cstat->cwnd += add; + if (cubic->target_cwnd == 0 || cubic->target_cwnd > cstat->cwnd) { + cstat->cwnd += add; + } - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "pkn=%" PRId64 " acked, cubic-ca cwnd=%" PRIu64 " t=%" PRIu64 " k=%" PRIi64 " time_delta=%" PRIu64 " delta=%" PRIu64 " target=%" PRIu64 " w_tcp=%" PRIu64, - pkt->pkt_num, cstat->cwnd, t, cc->k, time_delta >> 4, delta, - target, cc->w_tcp); + pkt->pkt_num, cstat->cwnd, t, cubic->k, time_delta >> 4, + delta, target, cubic->w_tcp); } -void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *ccx, - ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); uint64_t min_cwnd; if (in_congestion_recovery(cstat, sent_ts)) { return; } - if (cc->prior.cwnd < cstat->cwnd) { - cc->prior.cwnd = cstat->cwnd; - cc->prior.ssthresh = cstat->ssthresh; - cc->prior.w_last_max = cc->w_last_max; - cc->prior.w_tcp = cc->w_tcp; - cc->prior.origin_point = cc->origin_point; - cc->prior.epoch_start = cc->epoch_start; - cc->prior.k = cc->k; + if (cubic->prior.cwnd < cstat->cwnd) { + cubic->prior.cwnd = cstat->cwnd; + cubic->prior.ssthresh = cstat->ssthresh; + cubic->prior.w_last_max = cubic->w_last_max; + cubic->prior.w_tcp = cubic->w_tcp; + cubic->prior.origin_point = cubic->origin_point; + cubic->prior.epoch_start = cubic->epoch_start; + cubic->prior.k = cubic->k; } cstat->congestion_recovery_start_ts = ts; - cc->epoch_start = UINT64_MAX; - if (cstat->cwnd < cc->w_last_max) { - cc->w_last_max = cstat->cwnd * 17 / 10 / 2; + cubic->epoch_start = UINT64_MAX; + if (cstat->cwnd < cubic->w_last_max) { + cubic->w_last_max = cstat->cwnd * 17 / 10 / 2; } else { - cc->w_last_max = cstat->cwnd; + cubic->w_last_max = cstat->cwnd; } - min_cwnd = 2 * cstat->max_udp_payload_size; + min_cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->ssthresh = cstat->cwnd * 7 / 10; cstat->ssthresh = ngtcp2_max(cstat->ssthresh, min_cwnd); cstat->cwnd = cstat->ssthresh; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "reduce cwnd because of packet loss cwnd=%" PRIu64, cstat->cwnd); } -void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *ccx, +void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)ts; - if (cstat->cwnd >= cc->prior.cwnd) { + if (cstat->cwnd >= cubic->prior.cwnd) { return; } cstat->congestion_recovery_start_ts = UINT64_MAX; - cstat->cwnd = cc->prior.cwnd; - cstat->ssthresh = cc->prior.ssthresh; - cc->w_last_max = cc->prior.w_last_max; - cc->w_tcp = cc->prior.w_tcp; - cc->origin_point = cc->prior.origin_point; - cc->epoch_start = cc->prior.epoch_start; - cc->k = cc->prior.k; - - cc->prior.cwnd = 0; - cc->prior.ssthresh = 0; - cc->prior.w_last_max = 0; - cc->prior.w_tcp = 0; - cc->prior.origin_point = 0; - cc->prior.epoch_start = UINT64_MAX; - cc->prior.k = 0; - - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + cstat->cwnd = cubic->prior.cwnd; + cstat->ssthresh = cubic->prior.ssthresh; + cubic->w_last_max = cubic->prior.w_last_max; + cubic->w_tcp = cubic->prior.w_tcp; + cubic->origin_point = cubic->prior.origin_point; + cubic->epoch_start = cubic->prior.epoch_start; + cubic->k = cubic->prior.k; + + cubic->prior.cwnd = 0; + cubic->prior.ssthresh = 0; + cubic->prior.w_last_max = 0; + cubic->prior.w_tcp = 0; + cubic->prior.origin_point = 0; + cubic->prior.epoch_start = UINT64_MAX; + cubic->prior.k = 0; + + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "spurious congestion is detected and congestion state is " "restored cwnd=%" PRIu64, cstat->cwnd); } -void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *ccx, +void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - (void)ccx; + (void)cc; (void)ts; - cstat->cwnd = 2 * cstat->max_udp_payload_size; + cstat->cwnd = 2 * cstat->max_tx_udp_payload_size; cstat->congestion_recovery_start_ts = UINT64_MAX; } -void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); uint64_t target_cwnd, initcwnd; + uint64_t max_delivery_rate_sec; (void)ack; (void)ts; - /* TODO Use sliding window for min rtt measurement */ - /* TODO Use sliding window */ - cc->max_delivery_rate_sec = - ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec); + ++cubic->ack_count; + + ngtcp2_window_filter_update(&cubic->delivery_rate_sec_filter, + cstat->delivery_rate_sec, cubic->ack_count); + + max_delivery_rate_sec = + ngtcp2_window_filter_get_best(&cubic->delivery_rate_sec_filter); - if (cstat->min_rtt != UINT64_MAX && cc->max_delivery_rate_sec) { - target_cwnd = cc->max_delivery_rate_sec * cstat->min_rtt / NGTCP2_SECONDS; - initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_udp_payload_size); - cc->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; + if (cstat->min_rtt != UINT64_MAX && max_delivery_rate_sec) { + target_cwnd = max_delivery_rate_sec * cstat->smoothed_rtt / NGTCP2_SECONDS; + initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size); + cubic->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100; - ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA, "target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64 - " min_rtt=%" PRIu64, - cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt); + " smoothed_rtt=%" PRIu64, + cubic->target_cwnd, max_delivery_rate_sec, + cstat->smoothed_rtt); } } -void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)cstat; - if (pkt->pktns_id != NGTCP2_PKTNS_ID_APPLICATION || cc->window_end != -1) { + if (pkt->pktns_id != NGTCP2_PKTNS_ID_APPLICATION || cubic->window_end != -1) { return; } - cc->window_end = pkt->pkt_num; - cc->last_round_min_rtt = cc->current_round_min_rtt; - cc->current_round_min_rtt = UINT64_MAX; - cc->rtt_sample_count = 0; + cubic->window_end = pkt->pkt_num; + cubic->last_round_min_rtt = cubic->current_round_min_rtt; + cubic->current_round_min_rtt = UINT64_MAX; + cubic->rtt_sample_count = 0; } -void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)ts; - if (cc->window_end == -1) { + if (cubic->window_end == -1) { return; } - cc->current_round_min_rtt = - ngtcp2_min(cc->current_round_min_rtt, cstat->latest_rtt); - ++cc->rtt_sample_count; + cubic->current_round_min_rtt = + ngtcp2_min(cubic->current_round_min_rtt, cstat->latest_rtt); + ++cubic->rtt_sample_count; } -void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); (void)cstat; (void)ts; - cubic_cc_reset(cc); + cubic_cc_reset(cubic); } -void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, +void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_cc_event_type event, ngtcp2_tstamp ts) { - ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc); ngtcp2_tstamp last_ts; - if (event != NGTCP2_CC_EVENT_TYPE_TX_START || cc->epoch_start == UINT64_MAX) { + if (event != NGTCP2_CC_EVENT_TYPE_TX_START || + cubic->epoch_start == UINT64_MAX) { return; } last_ts = cstat->last_tx_pkt_ts[NGTCP2_PKTNS_ID_APPLICATION]; - if (last_ts == UINT64_MAX || last_ts <= cc->epoch_start) { + if (last_ts == UINT64_MAX || last_ts <= cubic->epoch_start) { return; } assert(ts >= last_ts); - cc->epoch_start += ts - last_ts; + cubic->epoch_start += ts - last_ts; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h index 6d9e0c2459ece4..524bcdb7e4bf86 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h @@ -31,24 +31,14 @@ #include +#include "ngtcp2_pktns_id.h" +#include "ngtcp2_window_filter.h" + #define NGTCP2_LOSS_REDUCTION_FACTOR_BITS 1 #define NGTCP2_PERSISTENT_CONGESTION_THRESHOLD 3 typedef struct ngtcp2_log ngtcp2_log; - -/** - * @struct - * - * :type:`ngtcp2_cc_base` is the base structure of custom congestion - * control algorithm. It must be the first field of custom congestion - * controller. - */ -typedef struct ngtcp2_cc_base { - /** - * :member:`log` is ngtcp2 library internal logger. - */ - ngtcp2_log *log; -} ngtcp2_cc_base; +typedef struct ngtcp2_conn_stat ngtcp2_conn_stat; /** * @struct @@ -117,10 +107,10 @@ typedef struct ngtcp2_cc_ack { */ uint64_t pkt_delivered; /** - * :member:`largest_acked_sent_ts` is the time when the largest - * acknowledged packet was sent. + * :member:`largest_pkt_sent_ts` is the time when the largest + * acknowledged packet was sent. It is UINT64_MAX if it is unknown. */ - ngtcp2_tstamp largest_acked_sent_ts; + ngtcp2_tstamp largest_pkt_sent_ts; /** * :member:`rtt` is the RTT sample. It is UINT64_MAX if no RTT * sample is available. @@ -242,15 +232,14 @@ typedef void (*ngtcp2_cc_event)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, /** * @struct * - * :type:`ngtcp2_cc` is congestion control algorithm interface to - * allow custom implementation. + * :type:`ngtcp2_cc` is congestion control algorithm interface shared + * by implementations. All callback functions are optional. */ typedef struct ngtcp2_cc { /** - * :member:`ccb` is a pointer to :type:`ngtcp2_cc_base` which - * usually contains a state. + * :member:`log` is ngtcp2 library internal logger. */ - ngtcp2_cc_base *ccb; + ngtcp2_log *log; /** * :member:`on_pkt_acked` is a callback function which is called * when a packet is acknowledged. @@ -313,22 +302,16 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num, ngtcp2_tstamp sent_ts, uint64_t lost, uint64_t tx_in_flight, int is_app_limited); -/* ngtcp2_reno_cc is the RENO congestion controller. */ -typedef struct ngtcp2_reno_cc { - ngtcp2_cc_base ccb; - uint64_t max_delivery_rate_sec; +/* ngtcp2_cc_reno is the RENO congestion controller. */ +typedef struct ngtcp2_cc_reno { + ngtcp2_cc cc; + ngtcp2_window_filter delivery_rate_sec_filter; + uint64_t ack_count; uint64_t target_cwnd; uint64_t pending_add; -} ngtcp2_reno_cc; - -int ngtcp2_cc_reno_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem); - -void ngtcp2_cc_reno_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log); +} ngtcp2_cc_reno; -void ngtcp2_reno_cc_free(ngtcp2_reno_cc *cc); +void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log); void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); @@ -347,10 +330,11 @@ void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); -/* ngtcp2_cubic_cc is CUBIC congestion controller. */ -typedef struct ngtcp2_cubic_cc { - ngtcp2_cc_base ccb; - uint64_t max_delivery_rate_sec; +/* ngtcp2_cc_cubic is CUBIC congestion controller. */ +typedef struct ngtcp2_cc_cubic { + ngtcp2_cc cc; + ngtcp2_window_filter delivery_rate_sec_filter; + uint64_t ack_count; uint64_t target_cwnd; uint64_t w_last_max; uint64_t w_tcp; @@ -376,16 +360,9 @@ typedef struct ngtcp2_cubic_cc { int64_t window_end; uint64_t pending_add; uint64_t pending_w_add; -} ngtcp2_cubic_cc; +} ngtcp2_cc_cubic; -int ngtcp2_cc_cubic_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, - const ngtcp2_mem *mem); - -void ngtcp2_cc_cubic_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); - -void ngtcp2_cubic_cc_init(ngtcp2_cubic_cc *cc, ngtcp2_log *log); - -void ngtcp2_cubic_cc_free(ngtcp2_cubic_cc *cc); +void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cc, ngtcp2_log *log); void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, @@ -418,4 +395,6 @@ void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_cc_event_type event, ngtcp2_tstamp ts); +uint64_t ngtcp2_cbrt(uint64_t n); + #endif /* NGTCP2_CC_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c index a3135680ca160f..f40ab5626109e9 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c @@ -35,6 +35,11 @@ #include "ngtcp2_addr.h" #include "ngtcp2_path.h" #include "ngtcp2_rcvry.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_net.h" +#include "ngtcp2_conversion.h" +#include "ngtcp2_tstamp.h" +#include "ngtcp2_frame_chain.h" /* NGTCP2_FLOW_WINDOW_RTT_FACTOR is the factor of RTT when flow control window auto-tuning is triggered. */ @@ -46,6 +51,8 @@ packet payload that should be coalesced to a long packet. */ #define NGTCP2_MIN_COALESCED_PAYLOADLEN 128 +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. @@ -60,12 +67,20 @@ static int conn_local_stream(ngtcp2_conn *conn, int64_t stream_id) { */ static int bidi_stream(int64_t stream_id) { return (stream_id & 0x2) == 0; } +static void conn_update_timestamp(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + assert(conn->log.last_ts <= ts); + assert(conn->qlog.last_ts <= ts); + + conn->log.last_ts = ts; + conn->qlog.last_ts = ts; +} + /* - * conn_is_handshake_completed returns nonzero if QUIC handshake has - * completed. + * conn_is_tls_handshake_completed returns nonzero if TLS handshake + * has completed and 1 RTT keys are available. */ -static int conn_is_handshake_completed(ngtcp2_conn *conn) { - return (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) && +static int conn_is_tls_handshake_completed(ngtcp2_conn *conn) { + return (conn->flags & NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED) && conn->pktns.crypto.rx.ckm && conn->pktns.crypto.tx.ckm; } @@ -118,14 +133,14 @@ static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, } static int conn_call_recv_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, uint64_t offset, const uint8_t *data, size_t datalen) { int rv; assert(conn->callbacks.recv_crypto_data); - rv = conn->callbacks.recv_crypto_data(conn, crypto_level, offset, data, + rv = conn->callbacks.recv_crypto_data(conn, encryption_level, offset, data, datalen, conn->user_data); switch (rv) { case 0: @@ -267,6 +282,7 @@ static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv, ngtcp2_path_validation_result res) { int rv; uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE; + const ngtcp2_path *old_path = NULL; if (!conn->callbacks.path_validation) { return 0; @@ -276,8 +292,18 @@ static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv, flags |= NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR; } - rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path, res, - conn->user_data); + if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) { + old_path = &pv->fallback_dcid.ps.path; + } + + if (conn->server && old_path && + (ngtcp2_addr_compare(&pv->dcid.ps.path.remote, &old_path->remote) & + (NGTCP2_ADDR_COMPARE_FLAG_ADDR | NGTCP2_ADDR_COMPARE_FLAG_FAMILY))) { + flags |= NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN; + } + + rv = conn->callbacks.path_validation(conn, flags, &pv->dcid.ps.path, old_path, + res, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -294,10 +320,10 @@ static int conn_call_select_preferred_addr(ngtcp2_conn *conn, } assert(conn->remote.transport_params); - assert(conn->remote.transport_params->preferred_address_present); + assert(conn->remote.transport_params->preferred_addr_present); rv = conn->callbacks.select_preferred_addr( - conn, dest, &conn->remote.transport_params->preferred_address, + conn, dest, &conn->remote.transport_params->preferred_addr, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; @@ -369,7 +395,7 @@ static int conn_call_dcid_status(ngtcp2_conn *conn, } rv = conn->callbacks.dcid_status( - conn, (int)type, dcid->seq, &dcid->cid, + conn, type, dcid->seq, &dcid->cid, (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token : NULL, conn->user_data); if (rv != 0) { @@ -505,15 +531,15 @@ conn_call_recv_stateless_reset(ngtcp2_conn *conn, return 0; } -static int conn_call_recv_new_token(ngtcp2_conn *conn, - const ngtcp2_vec *token) { +static int conn_call_recv_new_token(ngtcp2_conn *conn, const uint8_t *token, + size_t tokenlen) { int rv; if (!conn->callbacks.recv_new_token) { return 0; } - rv = conn->callbacks.recv_new_token(conn, token, conn->user_data); + rv = conn->callbacks.recv_new_token(conn, token, tokenlen, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -557,8 +583,8 @@ static int conn_call_recv_datagram(ngtcp2_conn *conn, datalen = 0; } - if (!conn_is_handshake_completed(conn)) { - flags |= NGTCP2_DATAGRAM_FLAG_EARLY; + if (!conn_is_tls_handshake_completed(conn)) { + flags |= NGTCP2_DATAGRAM_FLAG_0RTT; } rv = conn->callbacks.recv_datagram(conn, flags, data, datalen, @@ -605,7 +631,8 @@ static int conn_call_version_negotiation(ngtcp2_conn *conn, uint32_t version, return 0; } -static int conn_call_recv_rx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { +static int conn_call_recv_rx_key(ngtcp2_conn *conn, + ngtcp2_encryption_level level) { int rv; if (!conn->callbacks.recv_rx_key) { @@ -620,7 +647,8 @@ static int conn_call_recv_rx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { return 0; } -static int conn_call_recv_tx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { +static int conn_call_recv_tx_key(ngtcp2_conn *conn, + ngtcp2_encryption_level level) { int rv; if (!conn->callbacks.recv_tx_key) { @@ -635,14 +663,10 @@ static int conn_call_recv_tx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level) { return 0; } -static int crypto_offset_less(const ngtcp2_ksl_key *lhs, - const ngtcp2_ksl_key *rhs) { - return *(int64_t *)lhs < *(int64_t *)rhs; -} - static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, - ngtcp2_rst *rst, ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, + ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num, + ngtcp2_log *log, ngtcp2_qlog *qlog, + ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { int rv; @@ -650,7 +674,8 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, ngtcp2_gaptr_init(&pktns->rx.pngap, mem); - pktns->tx.last_pkt_num = -1; + pktns->tx.last_pkt_num = initial_pkt_num - 1; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; pktns->rx.max_pkt_num = -1; pktns->rx.max_ack_eliciting_pkt_num = -1; @@ -660,14 +685,12 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, } ngtcp2_strm_init(&pktns->crypto.strm, 0, NGTCP2_STRM_FLAG_NONE, 0, 0, NULL, - NULL, mem); + frc_objalloc, mem); - ngtcp2_ksl_init(&pktns->crypto.tx.frq, crypto_offset_less, sizeof(uint64_t), + ngtcp2_rtb_init(&pktns->rtb, pktns_id, &pktns->crypto.strm, rst, cc, + initial_pkt_num, log, qlog, rtb_entry_objalloc, frc_objalloc, mem); - ngtcp2_rtb_init(&pktns->rtb, pktns_id, &pktns->crypto.strm, rst, cc, log, - qlog, rtb_entry_objalloc, frc_objalloc, mem); - return 0; fail_acktr_init: @@ -677,8 +700,9 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, } static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id, - ngtcp2_rst *rst, ngtcp2_cc *cc, ngtcp2_log *log, - ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, + ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num, + ngtcp2_log *log, ngtcp2_qlog *qlog, + ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { int rv; @@ -687,8 +711,8 @@ static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id, return NGTCP2_ERR_NOMEM; } - rv = pktns_init(*ppktns, pktns_id, rst, cc, log, qlog, rtb_entry_objalloc, - frc_objalloc, mem); + rv = pktns_init(*ppktns, pktns_id, rst, cc, initial_pkt_num, log, qlog, + rtb_entry_objalloc, frc_objalloc, mem); if (rv != 0) { ngtcp2_mem_free(mem, *ppktns); } @@ -729,9 +753,6 @@ static void delete_buf_chain(ngtcp2_buf_chain *bufchain, } static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { - ngtcp2_frame_chain *frc; - ngtcp2_ksl_it it; - delete_buf_chain(pktns->crypto.tx.data, mem); delete_buffed_pkts(pktns->rx.buffed_pkts, mem); @@ -742,13 +763,6 @@ static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, mem); ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, mem); - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); - ngtcp2_ksl_it_next(&it)) { - frc = ngtcp2_ksl_it_get(&it); - ngtcp2_frame_chain_objalloc_del(frc, pktns->rtb.frc_objalloc, mem); - } - - ngtcp2_ksl_free(&pktns->crypto.tx.frq); ngtcp2_rtb_free(&pktns->rtb); ngtcp2_strm_free(&pktns->crypto.strm); ngtcp2_acktr_free(&pktns->acktr); @@ -765,26 +779,6 @@ static void pktns_del(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) { ngtcp2_mem_free(mem, pktns); } -static void cc_del(ngtcp2_cc *cc, ngtcp2_cc_algo cc_algo, - const ngtcp2_mem *mem) { - switch (cc_algo) { - case NGTCP2_CC_ALGO_RENO: - ngtcp2_cc_reno_cc_free(cc, mem); - break; - case NGTCP2_CC_ALGO_CUBIC: - ngtcp2_cc_cubic_cc_free(cc, mem); - break; - case NGTCP2_CC_ALGO_BBR: - ngtcp2_cc_bbr_cc_free(cc, mem); - break; - case NGTCP2_CC_ALGO_BBR2: - ngtcp2_cc_bbr2_cc_free(cc, mem); - break; - default: - break; - } -} - static int cid_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { return ngtcp2_cid_less(lhs, rhs); } @@ -810,13 +804,13 @@ static void conn_reset_conn_stat_cc(ngtcp2_conn *conn, cstat->pto_count = 0; cstat->loss_detection_timer = UINT64_MAX; cstat->cwnd = - ngtcp2_cc_compute_initcwnd(conn->local.settings.max_udp_payload_size); + ngtcp2_cc_compute_initcwnd(conn->local.settings.max_tx_udp_payload_size); cstat->ssthresh = UINT64_MAX; cstat->congestion_recovery_start_ts = UINT64_MAX; cstat->bytes_in_flight = 0; cstat->delivery_rate_sec = 0; - cstat->pacing_rate = 0.0; - cstat->send_quantum = SIZE_MAX; + cstat->pacing_interval = 0; + cstat->send_quantum = 64 * 1024; } /* @@ -896,6 +890,25 @@ ngtcp2_duration ngtcp2_conn_compute_pto(ngtcp2_conn *conn, 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, + ngtcp2_duration pto) { + ngtcp2_duration initial_pto = conn_compute_initial_pto(conn, &conn->pktns); + + 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 void conn_handle_tx_ecn(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint16_t *prtb_entry_flags, ngtcp2_pktns *pktns, const ngtcp2_pkt_hd *hd, ngtcp2_tstamp ts) { @@ -959,7 +972,7 @@ static void conn_handle_tx_ecn(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, case NGTCP2_ECN_STATE_FAILED: break; default: - assert(0); + ngtcp2_unreachable(); } } @@ -989,14 +1002,14 @@ static void conn_reset_ecn_validation_state(ngtcp2_conn *conn) { pktns->tx.ecn.validation_pkt_lost = 0; } -/* server_default_other_versions is the default other_versions field - sent by server. */ -static uint8_t server_default_other_versions[] = {0, 0, 0, 1}; +/* server_default_available_versions is the default available_versions + field sent by server. */ +static uint8_t server_default_available_versions[] = {0, 0, 0, 1}; /* - * other_versions_new allocates new buffer, and writes |versions| of - * length |versionslen| in network byte order, suitable for sending in - * other_versions field of version_information QUIC transport + * available_versions_new allocates new buffer, and writes |versions| + * of length |versionslen| in network byte order, suitable for sending + * in available_versions field of version_information QUIC transport * parameter. The pointer to the allocated buffer is assigned to * |*pbuf|. * @@ -1006,8 +1019,8 @@ static uint8_t server_default_other_versions[] = {0, 0, 0, 1}; * NGTCP2_ERR_NOMEM * Out of memory. */ -static int other_versions_new(uint8_t **pbuf, const uint32_t *versions, - size_t versionslen, const ngtcp2_mem *mem) { +static int available_versions_new(uint8_t **pbuf, const uint32_t *versions, + size_t versionslen, const ngtcp2_mem *mem) { size_t i; uint8_t *buf = ngtcp2_mem_malloc(mem, sizeof(uint32_t) * versionslen); @@ -1032,16 +1045,13 @@ conn_set_local_transport_params(ngtcp2_conn *conn, *p = *params; - /* grease_quic_bit is always enabled. */ - p->grease_quic_bit = 1; - if (conn->server) { p->version_info.chosen_version = chosen_version; } else { p->version_info.chosen_version = conn->client_chosen_version; } - p->version_info.other_versions = conn->vneg.other_versions; - p->version_info.other_versionslen = conn->vneg.other_versionslen; + p->version_info.available_versions = conn->vneg.available_versions; + p->version_info.available_versionslen = conn->vneg.available_versionslen; p->version_info_present = 1; } @@ -1059,19 +1069,33 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, uint8_t fixed_bit_byte; size_t i; uint32_t *preferred_versions; + ngtcp2_transport_params paramsbuf; (void)callbacks_version; (void)settings_version; - (void)transport_params_version; + + params = ngtcp2_transport_params_convert_to_latest( + ¶msbuf, transport_params_version, params); assert(settings->max_window <= NGTCP2_MAX_VARINT); assert(settings->max_stream_window <= NGTCP2_MAX_VARINT); - assert(settings->max_udp_payload_size); - assert(settings->max_udp_payload_size <= NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE); + assert(settings->max_tx_udp_payload_size); + assert(settings->max_tx_udp_payload_size <= NGTCP2_HARD_MAX_UDP_PAYLOAD_SIZE); + assert(settings->initial_pkt_num <= INT32_MAX); + assert(params->active_connection_id_limit >= + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT); assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE); assert(params->initial_max_data <= NGTCP2_MAX_VARINT); assert(params->initial_max_stream_data_bidi_local <= NGTCP2_MAX_VARINT); assert(params->initial_max_stream_data_bidi_remote <= NGTCP2_MAX_VARINT); assert(params->initial_max_stream_data_uni <= NGTCP2_MAX_VARINT); + assert((server && params->original_dcid_present) || + (!server && !params->original_dcid_present)); + assert(!params->initial_scid_present); + assert(server || !params->stateless_reset_token_present); + assert(server || !params->preferred_addr_present); + assert(server || !params->retry_scid_present); + assert(params->max_idle_timeout != UINT64_MAX); + assert(params->max_ack_delay < (1 << 14) * NGTCP2_MILLISECONDS); assert(server || callbacks->client_initial); assert(!server || callbacks->recv_client_initial); assert(callbacks->recv_crypto_data); @@ -1097,6 +1121,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, goto fail_conn; } + (*pconn)->server = server; + ngtcp2_objalloc_frame_chain_init(&(*pconn)->frc_objalloc, 64, mem); ngtcp2_objalloc_rtb_entry_init(&(*pconn)->rtb_entry_objalloc, 64, mem); ngtcp2_objalloc_strm_init(&(*pconn)->strm_objalloc, 64, mem); @@ -1125,7 +1151,7 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ngtcp2_log_init(&(*pconn)->log, scid, settings->log_printf, settings->initial_ts, user_data); - ngtcp2_qlog_init(&(*pconn)->qlog, settings->qlog.write, settings->initial_ts, + ngtcp2_qlog_init(&(*pconn)->qlog, settings->qlog_write, settings->initial_ts, user_data); if ((*pconn)->qlog.write) { buf = ngtcp2_mem_malloc(mem, NGTCP2_QLOG_BUFLEN); @@ -1138,17 +1164,16 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->local.settings = *settings; - if (settings->token.len) { - buf = ngtcp2_mem_malloc(mem, settings->token.len); + if (settings->tokenlen) { + buf = ngtcp2_mem_malloc(mem, settings->tokenlen); if (buf == NULL) { rv = NGTCP2_ERR_NOMEM; goto fail_token; } - memcpy(buf, settings->token.base, settings->token.len); - (*pconn)->local.settings.token.base = buf; + memcpy(buf, settings->token, settings->tokenlen); + (*pconn)->local.settings.token = buf; } else { - (*pconn)->local.settings.token.base = NULL; - (*pconn)->local.settings.token.len = 0; + (*pconn)->local.settings.token = NULL; } if (!(*pconn)->local.settings.original_version) { @@ -1157,8 +1182,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, conn_reset_conn_stat(*pconn, &(*pconn)->cstat); (*pconn)->cstat.initial_rtt = settings->initial_rtt; - (*pconn)->cstat.max_udp_payload_size = - (*pconn)->local.settings.max_udp_payload_size; + (*pconn)->cstat.max_tx_udp_payload_size = + (*pconn)->local.settings.max_tx_udp_payload_size; ngtcp2_rst_init(&(*pconn)->rst); @@ -1166,54 +1191,43 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, switch (settings->cc_algo) { case NGTCP2_CC_ALGO_RENO: - rv = ngtcp2_cc_reno_cc_init(&(*pconn)->cc, &(*pconn)->log, mem); - if (rv != 0) { - goto fail_cc_init; - } + ngtcp2_cc_reno_init(&(*pconn)->reno, &(*pconn)->log); + break; case NGTCP2_CC_ALGO_CUBIC: - rv = ngtcp2_cc_cubic_cc_init(&(*pconn)->cc, &(*pconn)->log, mem); - if (rv != 0) { - goto fail_cc_init; - } + ngtcp2_cc_cubic_init(&(*pconn)->cubic, &(*pconn)->log); + break; case NGTCP2_CC_ALGO_BBR: - rv = ngtcp2_cc_bbr_cc_init(&(*pconn)->cc, &(*pconn)->log, &(*pconn)->cstat, - &(*pconn)->rst, settings->initial_ts, - callbacks->rand, &settings->rand_ctx, mem); - if (rv != 0) { - goto fail_cc_init; - } - break; - case NGTCP2_CC_ALGO_BBR2: - rv = ngtcp2_cc_bbr2_cc_init(&(*pconn)->cc, &(*pconn)->log, &(*pconn)->cstat, - &(*pconn)->rst, settings->initial_ts, - callbacks->rand, &settings->rand_ctx, mem); - if (rv != 0) { - goto fail_cc_init; - } + ngtcp2_cc_bbr_init(&(*pconn)->bbr, &(*pconn)->log, &(*pconn)->cstat, + &(*pconn)->rst, settings->initial_ts, callbacks->rand, + &settings->rand_ctx); + break; default: - assert(0); + ngtcp2_unreachable(); } rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_PKTNS_ID_INITIAL, &(*pconn)->rst, - &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - &(*pconn)->rtb_entry_objalloc, &(*pconn)->frc_objalloc, mem); + &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log, + &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, + &(*pconn)->frc_objalloc, mem); if (rv != 0) { goto fail_in_pktns_init; } rv = pktns_new(&(*pconn)->hs_pktns, NGTCP2_PKTNS_ID_HANDSHAKE, &(*pconn)->rst, - &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - &(*pconn)->rtb_entry_objalloc, &(*pconn)->frc_objalloc, mem); + &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log, + &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, + &(*pconn)->frc_objalloc, mem); if (rv != 0) { goto fail_hs_pktns_init; } rv = pktns_init(&(*pconn)->pktns, NGTCP2_PKTNS_ID_APPLICATION, &(*pconn)->rst, - &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - &(*pconn)->rtb_entry_objalloc, &(*pconn)->frc_objalloc, mem); + &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log, + &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, + &(*pconn)->frc_objalloc, mem); if (rv != 0) { goto fail_pktns_init; } @@ -1271,56 +1285,63 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->vneg.preferred_versionslen = settings->preferred_versionslen; } - if (settings->other_versionslen) { + (*pconn)->local.settings.preferred_versions = NULL; + (*pconn)->local.settings.preferred_versionslen = 0; + + if (settings->available_versionslen) { if (!server && !ngtcp2_is_reserved_version(client_chosen_version)) { - for (i = 0; i < settings->other_versionslen; ++i) { - if (settings->other_versions[i] == client_chosen_version) { + for (i = 0; i < settings->available_versionslen; ++i) { + if (settings->available_versions[i] == client_chosen_version) { break; } } - assert(i < settings->other_versionslen); + assert(i < settings->available_versionslen); } - for (i = 0; i < settings->other_versionslen; ++i) { - assert(ngtcp2_is_reserved_version(settings->other_versions[i]) || - ngtcp2_is_supported_version(settings->other_versions[i])); + for (i = 0; i < settings->available_versionslen; ++i) { + assert(ngtcp2_is_reserved_version(settings->available_versions[i]) || + ngtcp2_is_supported_version(settings->available_versions[i])); } - rv = other_versions_new(&buf, settings->other_versions, - settings->other_versionslen, mem); + rv = available_versions_new(&buf, settings->available_versions, + settings->available_versionslen, mem); if (rv != 0) { - goto fail_other_versions; + goto fail_available_versions; } - (*pconn)->vneg.other_versions = buf; - (*pconn)->vneg.other_versionslen = - sizeof(uint32_t) * settings->other_versionslen; + (*pconn)->vneg.available_versions = buf; + (*pconn)->vneg.available_versionslen = + sizeof(uint32_t) * settings->available_versionslen; } else if (server) { if (settings->preferred_versionslen) { - rv = other_versions_new(&buf, settings->preferred_versions, - settings->preferred_versionslen, mem); + rv = available_versions_new(&buf, settings->preferred_versions, + settings->preferred_versionslen, mem); if (rv != 0) { - goto fail_other_versions; + goto fail_available_versions; } - (*pconn)->vneg.other_versions = buf; - (*pconn)->vneg.other_versionslen = + (*pconn)->vneg.available_versions = buf; + (*pconn)->vneg.available_versionslen = sizeof(uint32_t) * settings->preferred_versionslen; } else { - (*pconn)->vneg.other_versions = server_default_other_versions; - (*pconn)->vneg.other_versionslen = sizeof(server_default_other_versions); + (*pconn)->vneg.available_versions = server_default_available_versions; + (*pconn)->vneg.available_versionslen = + sizeof(server_default_available_versions); } } else if (!server && !ngtcp2_is_reserved_version(client_chosen_version)) { - rv = other_versions_new(&buf, &client_chosen_version, 1, mem); + rv = available_versions_new(&buf, &client_chosen_version, 1, mem); if (rv != 0) { - goto fail_other_versions; + goto fail_available_versions; } - (*pconn)->vneg.other_versions = buf; - (*pconn)->vneg.other_versionslen = sizeof(uint32_t); + (*pconn)->vneg.available_versions = buf; + (*pconn)->vneg.available_versionslen = sizeof(uint32_t); } + (*pconn)->local.settings.available_versions = NULL; + (*pconn)->local.settings.available_versionslen = 0; + (*pconn)->client_chosen_version = client_chosen_version; conn_set_local_transport_params(*pconn, params); @@ -1331,8 +1352,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, } (*pconn)->keep_alive.last_ts = UINT64_MAX; + (*pconn)->keep_alive.timeout = UINT64_MAX; - (*pconn)->server = server; (*pconn)->oscid = *scid; (*pconn)->callbacks = *callbacks; (*pconn)->mem = mem; @@ -1341,16 +1362,22 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->crypto.key_update.confirmed_ts = UINT64_MAX; (*pconn)->tx.last_max_data_ts = UINT64_MAX; (*pconn)->tx.pacing.next_ts = UINT64_MAX; + (*pconn)->tx.last_blocked_offset = UINT64_MAX; (*pconn)->early.discard_started_ts = UINT64_MAX; conn_reset_ecn_validation_state(*pconn); - ngtcp2_qlog_start(&(*pconn)->qlog, server ? &settings->qlog.odcid : dcid, - server); + ngtcp2_qlog_start( + &(*pconn)->qlog, + server ? ((*pconn)->local.transport_params.retry_scid_present + ? &(*pconn)->local.transport_params.retry_scid + : &(*pconn)->local.transport_params.original_dcid) + : dcid, + server); return 0; -fail_other_versions: +fail_available_versions: ngtcp2_mem_free(mem, (*pconn)->vneg.preferred_versions); fail_preferred_versions: fail_seqgap_push: @@ -1363,9 +1390,7 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, fail_hs_pktns_init: pktns_del((*pconn)->in_pktns, mem); fail_in_pktns_init: - cc_del(&(*pconn)->cc, settings->cc_algo, mem); -fail_cc_init: - ngtcp2_mem_free(mem, (*pconn)->local.settings.token.base); + ngtcp2_mem_free(mem, (uint8_t *)(*pconn)->local.settings.token); fail_token: ngtcp2_mem_free(mem, (*pconn)->qlog.buf.begin); fail_qlog_buf: @@ -1432,7 +1457,7 @@ int ngtcp2_conn_server_new_versioned( (*pconn)->local.bidi.next_stream_id = 1; (*pconn)->local.uni.next_stream_id = 3; - if ((*pconn)->local.settings.token.len) { + if ((*pconn)->local.settings.tokenlen) { /* Usage of token lifts amplification limit */ (*pconn)->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; } @@ -1558,13 +1583,13 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { conn_vneg_crypto_free(conn); ngtcp2_mem_free(conn->mem, conn->vneg.preferred_versions); - if (conn->vneg.other_versions != server_default_other_versions) { - ngtcp2_mem_free(conn->mem, conn->vneg.other_versions); + if (conn->vneg.available_versions != server_default_available_versions) { + ngtcp2_mem_free(conn->mem, conn->vneg.available_versions); } ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_buf.base); ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_hp_buf.base); - ngtcp2_mem_free(conn->mem, conn->local.settings.token.base); + ngtcp2_mem_free(conn->mem, (uint8_t *)conn->local.settings.token); ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem); ngtcp2_crypto_km_del(conn->crypto.key_update.new_rx_ckm, conn->mem); @@ -1575,14 +1600,12 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { pktns_del(conn->hs_pktns, conn->mem); pktns_del(conn->in_pktns, conn->mem); - cc_del(&conn->cc, conn->cc_algo, conn->mem); - ngtcp2_mem_free(conn->mem, conn->qlog.buf.begin); ngtcp2_pmtud_del(conn->pmtud); ngtcp2_pv_del(conn->pv); - ngtcp2_mem_free(conn->mem, conn->rx.ccerr.reason); + ngtcp2_mem_free(conn->mem, (uint8_t *)conn->rx.ccerr.reason); ngtcp2_idtr_free(&conn->remote.uni.idtr); ngtcp2_idtr_free(&conn->remote.bidi.idtr); @@ -1604,8 +1627,8 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { } /* - * conn_ensure_ack_blks makes sure that conn->tx.ack->ack.blks can - * contain at least |n| additional ngtcp2_ack_blk. + * conn_ensure_ack_ranges makes sure that conn->tx.ack->ack.ranges can + * contain at least |n| additional ngtcp2_ack_range. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -1613,9 +1636,9 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { * NGTCP2_ERR_NOMEM * Out of memory. */ -static int conn_ensure_ack_blks(ngtcp2_conn *conn, size_t n) { +static int conn_ensure_ack_ranges(ngtcp2_conn *conn, size_t n) { ngtcp2_frame *fr; - size_t max = conn->tx.max_ack_blks; + size_t max = conn->tx.max_ack_ranges; if (n <= max) { return 0; @@ -1626,13 +1649,13 @@ static int conn_ensure_ack_blks(ngtcp2_conn *conn, size_t n) { assert(max >= n); fr = ngtcp2_mem_realloc(conn->mem, conn->tx.ack, - sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_blk) * max); + sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_range) * max); if (fr == NULL) { return NGTCP2_ERR_NOMEM; } conn->tx.ack = fr; - conn->tx.max_ack_blks = max; + conn->tx.max_ack_ranges = max; return 0; } @@ -1646,40 +1669,20 @@ static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) { conn->cstat.smoothed_rtt / 8); } -/* - * conn_create_ack_frame creates ACK frame, and assigns its pointer to - * |*pfr| if there are any received packets to acknowledge. If there - * are no packets to acknowledge, this function returns 0, and |*pfr| - * is untouched. The caller is advised to set |*pfr| to NULL before - * calling this function, and check it after this function returns. - * If |nodelay| is nonzero, delayed ACK timer is ignored. - * - * The memory for ACK frame is dynamically allocated by this function. - * A caller is responsible to free it. - * - * Call ngtcp2_acktr_commit_ack after a created ACK frame is - * successfully serialized into a packet. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, +int ngtcp2_conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, ngtcp2_pktns *pktns, uint8_t type, ngtcp2_tstamp ts, ngtcp2_duration ack_delay, uint64_t ack_delay_exponent) { /* TODO Measure an actual size of ACK blocks to find the best default value. */ - const size_t initial_max_ack_blks = 8; + const size_t initial_max_ack_ranges = 8; int64_t last_pkt_num; ngtcp2_acktr *acktr = &pktns->acktr; - ngtcp2_ack_blk *blk; + ngtcp2_ack_range *range; ngtcp2_ksl_it it; ngtcp2_acktr_entry *rpkt; ngtcp2_ack *ack; - size_t blk_idx; + size_t range_idx; ngtcp2_tstamp largest_ack_ts; int rv; @@ -1700,11 +1703,11 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, if (conn->tx.ack == NULL) { conn->tx.ack = ngtcp2_mem_malloc( conn->mem, - sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_blk) * initial_max_ack_blks); + sizeof(ngtcp2_ack) + sizeof(ngtcp2_ack_range) * initial_max_ack_ranges); if (conn->tx.ack == NULL) { return NGTCP2_ERR_NOMEM; } - conn->tx.max_ack_blks = initial_max_ack_blks; + conn->tx.max_ack_ranges = initial_max_ack_ranges; } ack = &conn->tx.ack->ack; @@ -1717,7 +1720,7 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, } else { ack->type = NGTCP2_FRAME_ACK; } - ack->num_blks = 0; + ack->rangecnt = 0; rpkt = ngtcp2_ksl_it_get(&it); @@ -1725,7 +1728,14 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); largest_ack_ts = rpkt->tstamp; ack->largest_ack = rpkt->pkt_num; - ack->first_ack_blklen = rpkt->len - 1; + ack->first_ack_range = rpkt->len - 1; + + ngtcp2_ksl_it_next(&it); + } else if (rpkt->pkt_num + 1 == pktns->rx.max_pkt_num) { + last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); + largest_ack_ts = pktns->rx.max_pkt_ts; + ack->largest_ack = pktns->rx.max_pkt_num; + ack->first_ack_range = rpkt->len; ngtcp2_ksl_it_next(&it); } else { @@ -1734,7 +1744,7 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, last_pkt_num = pktns->rx.max_pkt_num; largest_ack_ts = pktns->rx.max_pkt_ts; ack->largest_ack = pktns->rx.max_pkt_num; - ack->first_ack_blklen = 0; + ack->first_ack_range = 0; } if (type == NGTCP2_PKT_1RTT) { @@ -1747,21 +1757,21 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, } for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { - if (ack->num_blks == NGTCP2_MAX_ACK_BLKS) { + if (ack->rangecnt == NGTCP2_MAX_ACK_RANGES) { break; } rpkt = ngtcp2_ksl_it_get(&it); - blk_idx = ack->num_blks++; - rv = conn_ensure_ack_blks(conn, ack->num_blks); + range_idx = ack->rangecnt++; + rv = conn_ensure_ack_ranges(conn, ack->rangecnt); if (rv != 0) { return rv; } ack = &conn->tx.ack->ack; - blk = &ack->blks[blk_idx]; - blk->gap = (uint64_t)(last_pkt_num - rpkt->pkt_num - 2); - blk->blklen = rpkt->len - 1; + range = &ack->ranges[range_idx]; + range->gap = (uint64_t)(last_pkt_num - rpkt->pkt_num - 2); + range->len = rpkt->len - 1; last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1); } @@ -1888,7 +1898,7 @@ static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) { */ static uint64_t conn_get_cwnd(ngtcp2_conn *conn) { return conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) - ? ngtcp2_cc_compute_initcwnd(conn->cstat.max_udp_payload_size) + ? ngtcp2_cc_compute_initcwnd(conn->cstat.max_tx_udp_payload_size) : conn->cstat.cwnd; } @@ -1896,12 +1906,12 @@ static uint64_t conn_get_cwnd(ngtcp2_conn *conn) { * conn_cwnd_is_zero returns nonzero if the number of bytes the local * endpoint can sent at this time is zero. */ -static uint64_t conn_cwnd_is_zero(ngtcp2_conn *conn) { +static int conn_cwnd_is_zero(ngtcp2_conn *conn) { uint64_t bytes_in_flight = conn->cstat.bytes_in_flight; uint64_t cwnd = conn_get_cwnd(conn); if (bytes_in_flight >= cwnd) { - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "cwnd limited bytes_in_flight=%lu cwnd=%lu", bytes_in_flight, cwnd); } @@ -1943,349 +1953,6 @@ static uint64_t conn_retry_early_payloadlen(ngtcp2_conn *conn) { return 0; } -static void conn_cryptofrq_clear(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { - ngtcp2_frame_chain *frc; - ngtcp2_ksl_it it; - - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); - ngtcp2_ksl_it_next(&it)) { - frc = ngtcp2_ksl_it_get(&it); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - } - ngtcp2_ksl_clear(&pktns->crypto.tx.frq); -} - -/* - * conn_cryptofrq_unacked_offset returns the CRYPTO frame offset by - * taking into account acknowledged offset. If there is no data to - * send, this function returns (uint64_t)-1. - */ -static uint64_t conn_cryptofrq_unacked_offset(ngtcp2_conn *conn, - ngtcp2_pktns *pktns) { - ngtcp2_frame_chain *frc; - ngtcp2_crypto *fr; - ngtcp2_range gap; - ngtcp2_rtb *rtb = &pktns->rtb; - ngtcp2_ksl_it it; - uint64_t datalen; - - (void)conn; - - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it); - ngtcp2_ksl_it_next(&it)) { - frc = ngtcp2_ksl_it_get(&it); - fr = &frc->fr.crypto; - - gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->offset); - - datalen = ngtcp2_vec_len(fr->data, fr->datacnt); - - if (gap.begin <= fr->offset) { - return fr->offset; - } - if (gap.begin < fr->offset + datalen) { - return gap.begin; - } - } - - return (uint64_t)-1; -} - -static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_frame_chain **pfrc) { - ngtcp2_frame_chain *frc, *nfrc; - ngtcp2_crypto *fr, *nfr; - uint64_t offset, end_offset; - size_t idx, end_idx; - uint64_t base_offset, end_base_offset; - ngtcp2_range gap; - ngtcp2_rtb *rtb = &pktns->rtb; - ngtcp2_vec *v; - int rv; - ngtcp2_ksl_it it; - - *pfrc = NULL; - - for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it);) { - frc = ngtcp2_ksl_it_get(&it); - fr = &frc->fr.crypto; - - ngtcp2_ksl_remove_hint(&pktns->crypto.tx.frq, &it, &it, &fr->offset); - - idx = 0; - offset = fr->offset; - base_offset = 0; - - gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, offset); - if (gap.begin < offset) { - gap.begin = offset; - } - - for (; idx < fr->datacnt && offset < gap.begin; ++idx) { - v = &fr->data[idx]; - if (offset + v->len > gap.begin) { - base_offset = gap.begin - offset; - break; - } - - offset += v->len; - } - - if (idx == fr->datacnt) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - continue; - } - - assert(gap.begin == offset + base_offset); - - end_idx = idx; - end_offset = offset; - end_base_offset = 0; - - for (; end_idx < fr->datacnt; ++end_idx) { - v = &fr->data[end_idx]; - if (end_offset + v->len > gap.end) { - end_base_offset = gap.end - end_offset; - break; - } - - end_offset += v->len; - } - - if (fr->offset == offset && base_offset == 0 && fr->datacnt == end_idx) { - *pfrc = frc; - return 0; - } - - if (fr->datacnt == end_idx) { - memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx)); - - assert(fr->data[0].len > base_offset); - - fr->offset = offset + base_offset; - fr->datacnt = end_idx - idx; - fr->data[0].base += base_offset; - fr->data[0].len -= (size_t)base_offset; - - *pfrc = frc; - return 0; - } - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, fr->datacnt - end_idx, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - nfr->type = NGTCP2_FRAME_CRYPTO; - memcpy(nfr->data, fr->data + end_idx, - sizeof(nfr->data[0]) * (fr->datacnt - end_idx)); - - assert(nfr->data[0].len > end_base_offset); - - nfr->offset = end_offset + end_base_offset; - nfr->datacnt = fr->datacnt - end_idx; - nfr->data[0].base += end_base_offset; - nfr->data[0].len -= (size_t)end_base_offset; - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - if (end_base_offset) { - ++end_idx; - } - - memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx)); - - assert(fr->data[0].len > base_offset); - - fr->offset = offset + base_offset; - fr->datacnt = end_idx - idx; - if (end_base_offset) { - assert(fr->data[fr->datacnt - 1].len > end_base_offset); - fr->data[fr->datacnt - 1].len = (size_t)end_base_offset; - } - fr->data[0].base += base_offset; - fr->data[0].len -= (size_t)base_offset; - - *pfrc = frc; - return 0; - } - - return 0; -} -static int conn_cryptofrq_pop(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, - ngtcp2_pktns *pktns, size_t left) { - ngtcp2_crypto *fr, *nfr; - ngtcp2_frame_chain *frc, *nfrc; - int rv; - size_t nmerged; - uint64_t datalen; - ngtcp2_vec a[NGTCP2_MAX_CRYPTO_DATACNT]; - ngtcp2_vec b[NGTCP2_MAX_CRYPTO_DATACNT]; - size_t acnt, bcnt; - ngtcp2_ksl_it it; - - rv = conn_cryptofrq_unacked_pop(conn, pktns, &frc); - if (rv != 0) { - return rv; - } - if (frc == NULL) { - *pfrc = NULL; - return 0; - } - - fr = &frc->fr.crypto; - datalen = ngtcp2_vec_len(fr->data, fr->datacnt); - - if (datalen > left) { - ngtcp2_vec_copy(a, fr->data, fr->datacnt); - acnt = fr->datacnt; - - bcnt = 0; - ngtcp2_vec_split(a, &acnt, b, &bcnt, left, NGTCP2_MAX_CRYPTO_DATACNT); - - assert(acnt > 0); - assert(bcnt > 0); - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, bcnt, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - nfr->type = NGTCP2_FRAME_CRYPTO; - nfr->offset = fr->offset + left; - nfr->datacnt = bcnt; - ngtcp2_vec_copy(nfr->data, b, bcnt); - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, acnt, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - *nfr = *fr; - nfr->datacnt = acnt; - ngtcp2_vec_copy(nfr->data, a, acnt); - - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - - *pfrc = nfrc; - - return 0; - } - - left -= (size_t)datalen; - - ngtcp2_vec_copy(a, fr->data, fr->datacnt); - acnt = fr->datacnt; - - for (; left && ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { - it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); - nfrc = ngtcp2_ksl_it_get(&it); - nfr = &nfrc->fr.crypto; - - if (nfr->offset != fr->offset + datalen) { - assert(fr->offset + datalen < nfr->offset); - break; - } - - rv = conn_cryptofrq_unacked_pop(conn, pktns, &nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - if (nfrc == NULL) { - break; - } - - nfr = &nfrc->fr.crypto; - - nmerged = ngtcp2_vec_merge(a, &acnt, nfr->data, &nfr->datacnt, left, - NGTCP2_MAX_CRYPTO_DATACNT); - if (nmerged == 0) { - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - break; - } - - datalen += nmerged; - left -= nmerged; - - if (nfr->datacnt == 0) { - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - continue; - } - - nfr->offset += nmerged; - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - break; - } - - if (acnt == fr->datacnt) { - assert(acnt > 0); - fr->data[acnt - 1] = a[acnt - 1]; - - *pfrc = frc; - return 0; - } - - assert(acnt > fr->datacnt); - - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, acnt, &conn->frc_objalloc, conn->mem); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - - nfr = &nfrc->fr.crypto; - *nfr = *fr; - nfr->datacnt = acnt; - ngtcp2_vec_copy(nfr->data, a, acnt); - - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - - *pfrc = nfrc; - - return 0; -} - /* * conn_verify_dcid verifies that destination connection ID in |hd| is * valid for the connection. If it is successfully verified and the @@ -2341,7 +2008,7 @@ static int conn_verify_dcid(ngtcp2_conn *conn, int *pnew_cid_used, * conn_should_pad_pkt returns nonzero if the packet should be padded. * |type| is the type of packet. |left| is the space left in packet * buffer. |write_datalen| is the number of bytes which will be sent - * in the next, coalesced 0-RTT or 1RTT packet. + * 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, @@ -2356,7 +2023,7 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, if (conn->hs_pktns->crypto.tx.ckm && (conn->hs_pktns->rtb.probe_pkt_left || - ngtcp2_ksl_len(&conn->hs_pktns->crypto.tx.frq) || + !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm) || !ngtcp2_acktr_empty(&conn->hs_pktns->acktr))) { /* If we have something to send in Handshake packet, then add PADDING in Handshake packet. */ @@ -2367,20 +2034,19 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, } else { if (conn->hs_pktns->crypto.tx.ckm && (conn->hs_pktns->rtb.probe_pkt_left || - ngtcp2_ksl_len(&conn->hs_pktns->crypto.tx.frq) || + !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm) || !ngtcp2_acktr_empty(&conn->hs_pktns->acktr))) { /* If we have something to send in Handshake packet, then add PADDING in Handshake packet. */ min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN; - } else if ((!conn->early.ckm && !conn->pktns.crypto.tx.ckm) || - write_datalen == 0) { - return 1; - } else { - /* If we have something to send in 0RTT or 1RTT packet, then - add PADDING in that packet. Take maximum in case that + } else if (conn->early.ckm && write_datalen > 0) { + /* If we have something to send in 0RTT packet, then add + PADDING in that packet. Take maximum in case that write_datalen includes DATAGRAM which cannot be split. */ min_payloadlen = ngtcp2_max(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); + } else { + return 1; } } } else { @@ -2390,11 +2056,11 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, return 0; } - if (!conn->pktns.crypto.tx.ckm || write_datalen == 0) { + if (!conn->pktns.crypto.tx.ckm) { return 1; } - min_payloadlen = ngtcp2_max(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); + min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN; } /* TODO the next packet type should be taken into account */ @@ -2419,7 +2085,8 @@ 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) { - return conn->keep_alive.last_ts != UINT64_MAX && conn->keep_alive.timeout; + return conn->keep_alive.last_ts != UINT64_MAX && + conn->keep_alive.timeout != UINT64_MAX; } /* @@ -2427,8 +2094,8 @@ static int conn_keep_alive_enabled(ngtcp2_conn *conn) { * expired. */ static int conn_keep_alive_expired(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - return conn_keep_alive_enabled(conn) && - conn->keep_alive.last_ts + conn->keep_alive.timeout <= ts; + return ngtcp2_tstamp_elapsed(conn->keep_alive.last_ts, + conn->keep_alive.timeout, ts); } /* @@ -2436,7 +2103,9 @@ static int conn_keep_alive_expired(ngtcp2_conn *conn, ngtcp2_tstamp ts) { */ static ngtcp2_tstamp conn_keep_alive_expiry(ngtcp2_conn *conn) { if ((conn->flags & NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED) || - !conn_keep_alive_enabled(conn)) { + !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) || + !conn_keep_alive_enabled(conn) || + conn->keep_alive.last_ts >= UINT64_MAX - conn->keep_alive.timeout) { return UINT64_MAX; } @@ -2467,6 +2136,10 @@ static void conn_update_keep_alive_last_ts(ngtcp2_conn *conn, void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn, ngtcp2_duration timeout) { + if (timeout == 0) { + timeout = UINT64_MAX; + } + conn->keep_alive.timeout = timeout; } @@ -2527,7 +2200,7 @@ static uint8_t conn_pkt_flags_short(ngtcp2_conn *conn) { * NGTCP2_PKT_HANDSHAKE_PKT. * * |write_datalen| is the minimum length of application data ready to - * send in subsequent 0RTT or 1RTT packet. + * send in subsequent 0RTT packet. * * This function returns the number of bytes written in |dest| if it * succeeds, or one of the following negative error codes: @@ -2590,8 +2263,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, cc.hp_ctx = pktns->crypto.tx.hp_ctx; break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } cc.aead = pktns->crypto.ctx.aead; @@ -2605,8 +2277,9 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, version, 0); if (!conn->server && type == NGTCP2_PKT_INITIAL && - conn->local.settings.token.len) { + conn->local.settings.tokenlen) { hd.token = conn->local.settings.token; + hd.tokenlen = conn->local.settings.tokenlen; } ngtcp2_ppe_init(&ppe, dest, destlen, &cc); @@ -2621,9 +2294,9 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, return 0; } - rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, - /* ack_delay = */ 0, - NGTCP2_DEFAULT_ACK_DELAY_EXPONENT); + rv = ngtcp2_conn_create_ack_frame(conn, &ackfr, pktns, type, ts, + /* ack_delay = */ 0, + NGTCP2_DEFAULT_ACK_DELAY_EXPONENT); if (rv != 0) { ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, conn->mem); return rv; @@ -2645,12 +2318,12 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, if (!conn->server || type != NGTCP2_PKT_INITIAL || destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE) { build_pkt: - for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { + for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) { left = ngtcp2_ppe_left(&ppe); - crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns); - if (crypto_offset == (size_t)-1) { - conn_cryptofrq_clear(conn, pktns); + crypto_offset = ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm); + if (crypto_offset == (uint64_t)-1) { + ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm); break; } @@ -2659,7 +2332,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, break; } - rv = conn_cryptofrq_pop(conn, &nfrc, pktns, left); + rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, @@ -2673,7 +2346,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -2729,9 +2402,8 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, if (!pkt_empty) { if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { - /* The intention of smaller limit is get more chance to measure - RTT samples in early phase. */ - if (pktns->tx.num_non_ack_pkt >= 1) { + if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts, + conn->cstat.smoothed_rtt, ts)) { lfr.type = NGTCP2_FRAME_PING; rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, &lfr); @@ -2739,18 +2411,18 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, assert(rv == NGTCP2_ERR_NOBUF); } else { rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING; - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } - } else { - ++pktns->tx.num_non_ack_pkt; + } else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) { + pktns->tx.non_ack_pkt_start_ts = ts; } } else { - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } } } - if (pkt_empty) { + if (pkt_empty && !require_padding) { return 0; } @@ -2762,6 +2434,8 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, require_padding)) { lfr.type = NGTCP2_FRAME_PADDING; lfr.padding.len = ngtcp2_ppe_padding(&ppe); + } else if (pkt_empty) { + return 0; } else { lfr.type = NGTCP2_FRAME_PADDING; lfr.padding.len = ngtcp2_ppe_padding_hp_sample(&ppe); @@ -2872,8 +2546,7 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, ack_delay_exponent = conn->local.transport_params.ack_delay_exponent; break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } if (!pktns->crypto.tx.ckm) { @@ -2881,8 +2554,8 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } ackfr = NULL; - rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, ack_delay, - ack_delay_exponent); + rv = ngtcp2_conn_create_ack_frame(conn, &ackfr, pktns, type, ts, ack_delay, + ack_delay_exponent); if (rv != 0) { return rv; } @@ -2992,11 +2665,11 @@ static ngtcp2_ssize conn_write_handshake_ack_pkts(ngtcp2_conn *conn, ngtcp2_ssize res = 0, nwrite = 0; /* In the most cases, client sends ACK in conn_write_handshake_pkt. - This function is only called when it is CWND limited. It is not - required for client to send ACK for server Initial. This is - because once it gets server Initial, it gets Handshake tx key and - discards Initial key. The only good reason to send ACK is give - server RTT measurement early. */ + This function is only called when it is CWND limited or pacing + limited. It is not required for client to send ACK for server + Initial. This is because once it gets server Initial, it gets + Handshake tx key and discards Initial key. The only good reason + to send ACK is give server RTT measurement early. */ if (conn->server && conn->in_pktns) { nwrite = conn_write_ack_pkt(conn, pi, dest, destlen, NGTCP2_PKT_INITIAL, ts); @@ -3145,13 +2818,14 @@ static ngtcp2_ssize conn_write_handshake_pkts(ngtcp2_conn *conn, } if (nwrite == 0) { - if (conn->server && (conn->in_pktns->rtb.probe_pkt_left || - ngtcp2_ksl_len(&conn->in_pktns->crypto.tx.frq))) { + if (conn->server && + (conn->in_pktns->rtb.probe_pkt_left || + !ngtcp2_strm_streamfrq_empty(&conn->in_pktns->crypto.strm))) { if (cstat->loss_detection_timer != UINT64_MAX && conn_server_tx_left(conn, &conn->dcid.current) < NGTCP2_MAX_UDP_PAYLOAD_SIZE) { ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer canceled due to amplification limit"); cstat->loss_detection_timer = UINT64_MAX; } @@ -3252,11 +2926,19 @@ static int conn_should_send_max_data(ngtcp2_conn *conn) { static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { uint64_t n; size_t len = ngtcp2_ksl_len(&conn->scid.set); + size_t lim; if (len >= NGTCP2_MAX_SCID_POOL_SIZE) { return 0; } + assert(NGTCP2_MAX_SCID_POOL_SIZE >= conn->scid.num_in_flight); + + lim = NGTCP2_MAX_SCID_POOL_SIZE - conn->scid.num_in_flight; + if (lim == 0) { + return 0; + } + assert(conn->remote.transport_params); assert(conn->remote.transport_params->active_connection_id_limit); @@ -3266,7 +2948,9 @@ static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { n = conn->remote.transport_params->active_connection_id_limit + conn->scid.num_retired; - return (size_t)ngtcp2_min(NGTCP2_MAX_SCID_POOL_SIZE, n) - len; + n = ngtcp2_min(NGTCP2_MAX_SCID_POOL_SIZE, n) - len; + + return (size_t)ngtcp2_min(lim, n); } /* @@ -3338,6 +3022,10 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { sizeof(token)); nfrc->next = pktns->tx.frq; pktns->tx.frq = nfrc; + + assert(NGTCP2_MAX_SCID_POOL_SIZE > conn->scid.num_in_flight); + + ++conn->scid.num_in_flight; } return 0; @@ -3368,7 +3056,7 @@ static int conn_remove_retired_connection_id(ngtcp2_conn *conn, for (; !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 || scid->retired_ts + timeout >= ts) { + if (!ngtcp2_tstamp_elapsed(scid->retired_ts, timeout, ts)) { break; } @@ -3435,6 +3123,36 @@ 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) { + return strm->tx.offset == strm->tx.max_offset && + strm->tx.last_blocked_offset != strm->tx.max_offset; +} + +/* + * conn_should_send_data_blocked returns nonzero if DATA_BLOCKED frame + * should be sent. + */ +static int conn_should_send_data_blocked(ngtcp2_conn *conn) { + return conn->tx.offset == conn->tx.max_offset && + conn->tx.last_blocked_offset != conn->tx.max_offset; +} + +/* + * conn_reset_ppe_pending clears NGTCP2_CONN_FLAG_PPE_PENDING flag and + * nullifies conn->pkt. + */ +static void conn_reset_ppe_pending(ngtcp2_conn *conn) { + conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_PPE_PENDING; + + memset(&conn->pkt, 0, sizeof(conn->pkt)); +} + /* * conn_write_pkt writes a protected packet in the buffer pointed by * |dest| whose length if |destlen|. |type| specifies the type of @@ -3550,8 +3268,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, /* transport parameter is only valid after handshake completion which means we don't know how many connection ID that remote - peer can accept before handshake completion. */ - if (conn->oscid.datalen && conn_is_handshake_completed(conn)) { + peer can accept before handshake completion. Because server + can use remote transport parameters sending stream data in + 0.5 RTT, it is also allowed to use remote transport + parameters here. */ + if (conn->oscid.datalen && + (conn->server || conn_is_tls_handshake_completed(conn))) { rv = conn_enqueue_new_connection_id(conn); if (rv != 0) { return rv; @@ -3574,7 +3296,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, break; default: /* Unreachable */ - assert(0); + ngtcp2_unreachable(); } cc->encrypt = conn->callbacks.encrypt; @@ -3617,6 +3339,32 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, nfrc->fr.max_data.max_data; } + if (stream_blocked && conn_should_send_max_data(conn)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED; + nfrc->fr.data_blocked.offset = conn->tx.max_offset; + nfrc->next = pktns->tx.frq; + pktns->tx.frq = nfrc; + + conn->tx.last_blocked_offset = conn->tx.max_offset; + } + + if (stream_blocked && !ngtcp2_strm_is_tx_queued(vmsg->stream.strm) && + strm_should_send_stream_data_blocked(vmsg->stream.strm)) { + assert(vmsg); + assert(vmsg->type == NGTCP2_VMSG_TYPE_STREAM); + + vmsg->stream.strm->cycle = conn_tx_strmq_first_cycle(conn); + rv = ngtcp2_conn_tx_strmq_push(conn, vmsg->stream.strm); + if (rv != 0) { + return rv; + } + } + ngtcp2_pkt_hd_init(hd, hd_flags, type, &conn->dcid.current.cid, scid, pktns->tx.last_pkt_num + 1, pktns_select_pkt_numlen(pktns), version, 0); @@ -3651,16 +3399,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, pkt_empty = 0; rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING; - require_padding = - !conn->server || destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE; + require_padding = require_padding || !conn->server || + destlen >= NGTCP2_MAX_UDP_PAYLOAD_SIZE; /* We don't retransmit PATH_RESPONSE. */ } } } - rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, - conn_compute_ack_delay(conn), - conn->local.transport_params.ack_delay_exponent); + rv = ngtcp2_conn_create_ack_frame( + conn, &ackfr, pktns, type, ts, conn_compute_ack_delay(conn), + conn->local.transport_params.ack_delay_exponent); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); return rv; @@ -3696,29 +3444,17 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, case NGTCP2_FRAME_STOP_SENDING: strm = ngtcp2_conn_find_stream(conn, (*pfrc)->fr.stop_sending.stream_id); - if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD)) { + if (strm == NULL || + ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset)) { frc = *pfrc; *pfrc = (*pfrc)->next; ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); continue; } - - if (!(strm->flags & NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED)) { - strm->flags |= NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED; - - rv = conn_call_stream_stop_sending( - conn, (*pfrc)->fr.stop_sending.stream_id, - (*pfrc)->fr.stop_sending.app_error_code, strm->stream_user_data); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; - } - } - break; case NGTCP2_FRAME_STREAM: - assert(0); - break; + ngtcp2_unreachable(); case NGTCP2_FRAME_MAX_STREAMS_BIDI: if ((*pfrc)->fr.max_streams.max_streams < conn->remote.bidi.max_streams) { @@ -3740,7 +3476,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, case NGTCP2_FRAME_MAX_STREAM_DATA: strm = ngtcp2_conn_find_stream(conn, (*pfrc)->fr.max_stream_data.stream_id); - if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) || + if (strm == NULL || + (strm->flags & + (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) || (*pfrc)->fr.max_stream_data.max_stream_data < strm->rx.max_offset) { frc = *pfrc; *pfrc = (*pfrc)->next; @@ -3756,9 +3494,27 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, continue; } break; - case NGTCP2_FRAME_CRYPTO: - assert(0); + case NGTCP2_FRAME_STREAM_DATA_BLOCKED: + strm = ngtcp2_conn_find_stream( + conn, (*pfrc)->fr.stream_data_blocked.stream_id); + if (strm == NULL || (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) || + (*pfrc)->fr.stream_data_blocked.offset != strm->tx.max_offset) { + frc = *pfrc; + *pfrc = (*pfrc)->next; + ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); + continue; + } + break; + case NGTCP2_FRAME_DATA_BLOCKED: + if ((*pfrc)->fr.data_blocked.offset != conn->tx.max_offset) { + frc = *pfrc; + *pfrc = (*pfrc)->next; + ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); + continue; + } break; + case NGTCP2_FRAME_CRYPTO: + ngtcp2_unreachable(); } rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); @@ -3774,13 +3530,14 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, pfrc = &(*pfrc)->next; } - if (rv != NGTCP2_ERR_NOBUF) { - for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { + if (*pfrc == NULL) { + for (; !ngtcp2_strm_streamfrq_empty(&pktns->crypto.strm);) { left = ngtcp2_ppe_left(ppe); - crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns); - if (crypto_offset == (size_t)-1) { - conn_cryptofrq_clear(conn, pktns); + crypto_offset = + ngtcp2_strm_streamfrq_unacked_offset(&pktns->crypto.strm); + if (crypto_offset == (uint64_t)-1) { + ngtcp2_strm_streamfrq_clear(&pktns->crypto.strm); break; } @@ -3790,7 +3547,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, break; } - rv = conn_cryptofrq_pop(conn, &nfrc, pktns, left); + rv = ngtcp2_strm_streamfrq_pop(&pktns->crypto.strm, &nfrc, left); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); return rv; @@ -3802,7 +3559,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -3815,79 +3572,114 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } } - /* Write MAX_STREAM_ID after RESET_STREAM so that we can extend stream - ID space in one packet. */ - if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL && - conn->remote.bidi.unsent_max_streams > conn->remote.bidi.max_streams) { - rv = conn_call_extend_max_remote_streams_bidi( - conn, conn->remote.bidi.unsent_max_streams); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; - } + if (*pfrc == NULL) { + for (; !ngtcp2_pq_empty(&conn->tx.strmq);) { + strm = ngtcp2_conn_tx_strmq_top(conn); - rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; - } - nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI; - nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams; - *pfrc = nfrc; + if (strm->flags & NGTCP2_STRM_FLAG_SEND_RESET_STREAM) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } - conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams; + nfrc->fr.type = NGTCP2_FRAME_RESET_STREAM; + nfrc->fr.reset_stream.stream_id = strm->stream_id; + nfrc->fr.reset_stream.app_error_code = + strm->tx.reset_stream_app_error_code; + nfrc->fr.reset_stream.final_size = strm->tx.offset; + *pfrc = nfrc; - rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - } else { - pkt_empty = 0; - rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | - NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | - NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; - pfrc = &(*pfrc)->next; - } - } + strm->flags &= ~NGTCP2_STRM_FLAG_SEND_RESET_STREAM; - if (rv != NGTCP2_ERR_NOBUF && *pfrc == NULL) { - if (conn->remote.uni.unsent_max_streams > conn->remote.uni.max_streams) { - rv = conn_call_extend_max_remote_streams_uni( - conn, conn->remote.uni.unsent_max_streams); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; + rv = + conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + break; + } + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; } - rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - return rv; + if (strm->flags & NGTCP2_STRM_FLAG_SEND_STOP_SENDING) { + if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) { + strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING; + } else { + rv = conn_call_stream_stop_sending( + conn, strm->stream_id, strm->tx.stop_sending_app_error_code, + strm->stream_user_data); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + + return rv; + } + + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_STOP_SENDING; + nfrc->fr.stop_sending.stream_id = strm->stream_id; + nfrc->fr.stop_sending.app_error_code = + strm->tx.stop_sending_app_error_code; + *pfrc = nfrc; + + strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, + &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + break; + } + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; + } } - nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI; - nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams; - *pfrc = nfrc; - conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams; + if (!(strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) && + strm_should_send_stream_data_blocked(strm)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED; + nfrc->fr.stream_data_blocked.stream_id = strm->stream_id; + nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset; + *pfrc = nfrc; + + strm->tx.last_blocked_offset = strm->tx.max_offset; + + rv = + conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + break; + } - rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, - &(*pfrc)->fr); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - } else { pkt_empty = 0; rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; } - } - } - - if (rv != NGTCP2_ERR_NOBUF) { - for (; !ngtcp2_pq_empty(&conn->tx.strmq);) { - strm = ngtcp2_conn_tx_strmq_top(conn); - if (!(strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + if (!(strm->flags & + (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING)) && conn_should_send_max_stream_data(conn, strm)) { rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); if (rv != 0) { @@ -3922,7 +3714,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, nfrc->fr.max_stream_data.stream_id = strm->stream_id; nfrc->fr.max_stream_data.max_stream_data = strm->rx.unsent_max_offset + delta; - ngtcp2_list_insert(nfrc, pfrc); + *pfrc = nfrc; + + strm->rx.max_offset = strm->rx.unsent_max_offset = + nfrc->fr.max_stream_data.max_stream_data; rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); @@ -3936,8 +3731,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; pfrc = &(*pfrc)->next; - strm->rx.max_offset = strm->rx.unsent_max_offset = - nfrc->fr.max_stream_data.max_stream_data; } if (ngtcp2_strm_streamfrq_empty(strm)) { @@ -3949,8 +3742,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (stream_offset == (uint64_t)-1) { ngtcp2_strm_streamfrq_clear(strm); ngtcp2_conn_tx_strmq_pop(conn); - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; continue; } @@ -3976,7 +3767,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -3989,8 +3780,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (ngtcp2_strm_streamfrq_empty(strm)) { ngtcp2_conn_tx_strmq_pop(conn); - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; continue; } @@ -4004,10 +3793,75 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } } - if (rv != NGTCP2_ERR_NOBUF && !send_stream && !send_datagram && + /* Write MAX_STREAMS after RESET_STREAM so that we can extend + stream ID space in one packet. */ + if (*pfrc == NULL && + conn->remote.bidi.unsent_max_streams > conn->remote.bidi.max_streams) { + rv = conn_call_extend_max_remote_streams_bidi( + conn, conn->remote.bidi.unsent_max_streams); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI; + nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams; + *pfrc = nfrc; + + conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + } else { + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; + } + } + + if (*pfrc == NULL && + conn->remote.uni.unsent_max_streams > conn->remote.uni.max_streams) { + rv = conn_call_extend_max_remote_streams_uni( + conn, conn->remote.uni.unsent_max_streams); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI; + nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams; + *pfrc = nfrc; + + conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &(*pfrc)->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + } else { + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + pfrc = &(*pfrc)->next; + } + } + + if (pktns->tx.frq == NULL && !send_stream && !send_datagram && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) && - pktns->rtb.num_retransmittable && pktns->tx.frq == NULL && - pktns->rtb.probe_pkt_left) { + pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) { num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, 1); if (num_reclaimed < 0) { return rv; @@ -4016,15 +3870,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, goto build_pkt; } - /* We had pktns->rtb.num_retransmittable > 0 but the contents of - those packets have been acknowledged (i.e., retransmission in - another packet). In this case, we don't have to send any - probe packet. */ + /* We had pktns->rtb.num_retransmittable > 0 but we were unable + to reclaim any frame. In this case, we do not have to send + any probe packet. */ if (pktns->rtb.num_pto_eliciting == 0) { pktns->rtb.probe_pkt_left = 0; ngtcp2_conn_set_loss_detection_timer(conn, ts); - /* TODO If packet is empty, we should return now if cwnd is - zero. */ + + if (pkt_empty && conn_cwnd_is_zero(conn) && !require_padding) { + return 0; + } } } } else { @@ -4036,7 +3891,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, left = ngtcp2_ppe_left(ppe); - if (rv != NGTCP2_ERR_NOBUF && send_stream && *pfrc == NULL && + if (*pfrc == NULL && send_stream && (ndatalen = ngtcp2_pkt_stream_max_datalen( vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen, left)) != (size_t)-1 && @@ -4068,7 +3923,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); if (rv != 0) { - assert(0); + ngtcp2_unreachable(); } *pfrc = nfrc; @@ -4093,7 +3948,83 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, send_stream = 0; } - if (rv != NGTCP2_ERR_NOBUF && send_datagram && + if (vmsg && vmsg->type == NGTCP2_VMSG_TYPE_STREAM && + ((stream_blocked && *pfrc == NULL) || + (send_stream && + !(vmsg->stream.strm->flags & NGTCP2_STRM_FLAG_SHUT_WR)))) { + if (conn_should_send_data_blocked(conn)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED; + nfrc->fr.data_blocked.offset = conn->tx.offset; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + /* We cannot add nfrc to pktns->tx.frq here. */ + ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); + } else { + *pfrc = nfrc; + pfrc = &(*pfrc)->next; + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + + conn->tx.last_blocked_offset = conn->tx.max_offset; + } + } + + strm = vmsg->stream.strm; + + if (strm_should_send_stream_data_blocked(strm)) { + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED; + nfrc->fr.stream_data_blocked.stream_id = strm->stream_id; + nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset; + + rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + + /* We cannot add nfrc to pktns->tx.frq here. */ + 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); + rv = ngtcp2_conn_tx_strmq_push(conn, strm); + if (rv != 0) { + return rv; + } + } + } else { + *pfrc = nfrc; + pfrc = &(*pfrc)->next; + + pkt_empty = 0; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE; + + strm->tx.last_blocked_offset = strm->tx.max_offset; + } + } + } + + if (*pfrc == NULL && send_datagram && left >= ngtcp2_pkt_datagram_framelen((size_t)datalen)) { if (conn->callbacks.ack_datagram || conn->callbacks.lost_datagram) { rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); @@ -4129,8 +4060,9 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } pkt_empty = 0; - rtb_entry_flags |= - NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | NGTCP2_RTB_ENTRY_FLAG_DATAGRAM; + rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING | + NGTCP2_RTB_ENTRY_FLAG_DATAGRAM; if (vmsg->datagram.paccepted) { *vmsg->datagram.paccepted = 1; @@ -4140,14 +4072,27 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } if (pkt_empty) { - assert(rv == 0 || NGTCP2_ERR_NOBUF == rv); - if (rv == 0 && stream_blocked && ngtcp2_conn_get_max_data_left(conn)) { + if (*pfrc == NULL && rv == 0 && stream_blocked && + (write_more || !require_padding) && + ngtcp2_conn_get_max_data_left(conn)) { + if (write_more) { + conn->pkt.pfrc = pfrc; + conn->pkt.pkt_empty = pkt_empty; + conn->pkt.rtb_entry_flags = rtb_entry_flags; + conn->pkt.hd_logged = hd_logged; + conn->flags |= NGTCP2_CONN_FLAG_PPE_PENDING; + } + return NGTCP2_ERR_STREAM_DATA_BLOCKED; } - keep_alive_expired = conn_keep_alive_expired(conn, ts); + keep_alive_expired = + type == NGTCP2_PKT_1RTT && conn_keep_alive_expired(conn, ts); + + if (conn->pktns.rtb.probe_pkt_left == 0 && !keep_alive_expired && + !require_padding) { + conn_reset_ppe_pending(conn); - if (conn->pktns.rtb.probe_pkt_left == 0 && !keep_alive_expired) { return 0; } } else if (write_more) { @@ -4165,7 +4110,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (ngtcp2_ppe_left(ppe)) { return NGTCP2_ERR_WRITE_MORE; } - } else if (ngtcp2_conn_get_max_data_left(conn) && stream_blocked) { + break; + } + + if (*pfrc == NULL && ngtcp2_conn_get_max_data_left(conn) && + stream_blocked) { return NGTCP2_ERR_STREAM_DATA_BLOCKED; } break; @@ -4178,12 +4127,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, calls ngtcp2_conn_writev_datagram again. */ break; default: - assert(0); + ngtcp2_unreachable(); } } if (!(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { - if (pktns->tx.num_non_ack_pkt >= NGTCP2_MAX_NON_ACK_TX_PKT || + if (ngtcp2_tstamp_elapsed(pktns->tx.non_ack_pkt_start_ts, + cstat->smoothed_rtt, ts) || keep_alive_expired || conn->pktns.rtb.probe_pkt_left) { lfr.type = NGTCP2_FRAME_PING; @@ -4197,13 +4147,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (conn->pktns.rtb.probe_pkt_left) { rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_PROBE; } - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } - } else { - ++pktns->tx.num_non_ack_pkt; + } else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) { + pktns->tx.non_ack_pkt_start_ts = ts; } } else { - pktns->tx.num_non_ack_pkt = 0; + pktns->tx.non_ack_pkt_start_ts = UINT64_MAX; } /* TODO Push STREAM frame back to ngtcp2_strm if there is an error @@ -4212,8 +4162,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, /* Making full sized packet will help GSO a bit */ ngtcp2_ppe_left(ppe) < 10) { lfr.padding.len = ngtcp2_ppe_padding(ppe); - } else { + } else if (type == NGTCP2_PKT_1RTT) { lfr.padding.len = ngtcp2_ppe_padding_size(ppe, min_pktlen); + } else { + lfr.padding.len = ngtcp2_ppe_padding_hp_sample(ppe); } if (lfr.padding.len) { @@ -4285,7 +4237,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, conn_handle_tx_ecn(conn, pi, NULL, pktns, hd, ts); } - conn->flags &= (uint32_t)~NGTCP2_CONN_FLAG_PPE_PENDING; + conn_reset_ppe_pending(conn); if (pktns->rtb.probe_pkt_left && (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { @@ -4360,8 +4312,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( break; default: /* We don't support 0-RTT packet in this function. */ - assert(0); - abort(); + ngtcp2_unreachable(); } cc.aead = pktns->crypto.ctx.aead; @@ -4448,7 +4399,8 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( if (((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) || padded) && (!path || ngtcp2_path_eq(&conn->dcid.current.ps.path, path))) { - if (pi && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE)) { + if (pi && (conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE || + !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE))) { conn_handle_tx_ecn(conn, pi, &rtb_entry_flags, pktns, &hd, ts); } @@ -4479,8 +4431,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( nwrite); } } - } else if (pi && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) && - conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) { + } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) { conn_handle_tx_ecn(conn, pi, NULL, pktns, &hd, ts); } @@ -4488,7 +4439,17 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( conn_update_keep_alive_last_ts(conn, ts); } - conn->tx.pacing.pktlen += (size_t)nwrite; + if (!padded) { + switch (fr->type) { + case NGTCP2_FRAME_ACK: + case NGTCP2_FRAME_ACK_ECN: + break; + default: + conn->tx.pacing.pktlen += (size_t)nwrite; + } + } else { + conn->tx.pacing.pktlen += (size_t)nwrite; + } ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); @@ -4529,11 +4490,11 @@ static int conn_handshake_remnants_left(ngtcp2_conn *conn) { ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_pktns *hs_pktns = conn->hs_pktns; - return !conn_is_handshake_completed(conn) || + return !conn_is_tls_handshake_completed(conn) || (in_pktns && (in_pktns->rtb.num_pto_eliciting || - ngtcp2_ksl_len(&in_pktns->crypto.tx.frq))) || + !ngtcp2_strm_streamfrq_empty(&in_pktns->crypto.strm))) || (hs_pktns && (hs_pktns->rtb.num_pto_eliciting || - ngtcp2_ksl_len(&hs_pktns->crypto.tx.frq))); + !ngtcp2_strm_streamfrq_empty(&hs_pktns->crypto.strm))); } /* @@ -4684,14 +4645,14 @@ static int conn_start_pmtud(ngtcp2_conn *conn) { assert(!conn->local.settings.no_pmtud); assert(!conn->pmtud); - assert(conn_is_handshake_completed(conn)); + assert(conn_is_tls_handshake_completed(conn)); assert(conn->remote.transport_params); assert(conn->remote.transport_params->max_udp_payload_size >= NGTCP2_MAX_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_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, hard_max_udp_payload_size, @@ -4850,9 +4811,9 @@ static size_t conn_shape_udp_payload(ngtcp2_conn *conn, const ngtcp2_dcid *dcid, } payloadlen = - ngtcp2_min(payloadlen, conn->local.settings.max_udp_payload_size); + ngtcp2_min(payloadlen, conn->local.settings.max_tx_udp_payload_size); - if (conn->local.settings.no_udp_payload_size_shaping) { + if (conn->local.settings.no_tx_udp_payload_size_shaping) { return payloadlen; } @@ -4885,10 +4846,6 @@ static int conn_on_path_validation_failed(ngtcp2_conn *conn, ngtcp2_pv *pv, } } - if (pv->flags & NGTCP2_PV_FLAG_MTU_PROBE) { - return NGTCP2_ERR_NO_VIABLE_PATH; - } - if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) { ngtcp2_dcid_copy(&conn->dcid.current, &pv->fallback_dcid); conn_reset_congestion_state(conn, ts); @@ -4918,7 +4875,7 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, ngtcp2_tstamp expiry; ngtcp2_pv *pv = conn->pv; ngtcp2_frame lfr; - ngtcp2_duration timeout; + ngtcp2_duration timeout, initial_pto; uint8_t flags; uint64_t tx_left; int rv; @@ -4953,8 +4910,9 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, lfr.type = NGTCP2_FRAME_PATH_CHALLENGE; + initial_pto = conn_compute_initial_pto(conn, &conn->pktns); timeout = conn_compute_pto(conn, &conn->pktns); - timeout = ngtcp2_max(timeout, 3 * conn->cstat.initial_rtt); + timeout = ngtcp2_max(timeout, initial_pto); expiry = ts + timeout * (1ULL << pv->round); destlen = ngtcp2_min(destlen, NGTCP2_MAX_UDP_PAYLOAD_SIZE); @@ -5216,75 +5174,6 @@ uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn) { return strm->cycle; } -int ngtcp2_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_frame_chain **pfrc) { - ngtcp2_frame_chain **first = pfrc; - ngtcp2_frame_chain *frc; - ngtcp2_stream *sfr; - ngtcp2_strm *strm; - int rv; - int streamfrq_empty; - - if (*pfrc == NULL) { - return 0; - } - - for (; *pfrc;) { - switch ((*pfrc)->fr.type) { - case NGTCP2_FRAME_STREAM: - frc = *pfrc; - - *pfrc = frc->next; - frc->next = NULL; - sfr = &frc->fr.stream; - - strm = ngtcp2_conn_find_stream(conn, sfr->stream_id); - if (!strm) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - break; - } - streamfrq_empty = ngtcp2_strm_streamfrq_empty(strm); - rv = ngtcp2_strm_streamfrq_push(strm, frc); - if (rv != 0) { - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - if (!ngtcp2_strm_is_tx_queued(strm)) { - strm->cycle = conn_tx_strmq_first_cycle(conn); - rv = ngtcp2_conn_tx_strmq_push(conn, strm); - if (rv != 0) { - return rv; - } - } - if (streamfrq_empty) { - ++conn->tx.strmq_nretrans; - } - break; - case NGTCP2_FRAME_CRYPTO: - frc = *pfrc; - - *pfrc = frc->next; - frc->next = NULL; - - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - &frc->fr.crypto.offset, frc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); - return rv; - } - break; - default: - pfrc = &(*pfrc)->next; - } - } - - *pfrc = pktns->tx.frq; - pktns->tx.frq = *first; - - return 0; -} - /* * conn_on_retry is called when Retry packet is received. The * function decodes the data in the buffer pointed by |pkt| whose @@ -5312,7 +5201,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, ngtcp2_rtb *rtb = &conn->pktns.rtb; ngtcp2_rtb *in_rtb; uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1]; - ngtcp2_vec *token; + uint8_t *token; if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) { return 0; @@ -5340,7 +5229,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, (const char *)ngtcp2_encode_hex(cidbuf, retry.odcid.data, retry.odcid.datalen)); - if (retry.token.len == 0) { + if (retry.tokenlen == 0) { return NGTCP2_ERR_PROTO; } @@ -5376,19 +5265,19 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, return rv; } - token = &conn->local.settings.token; - - ngtcp2_mem_free(conn->mem, token->base); - token->base = NULL; - token->len = 0; + ngtcp2_mem_free(conn->mem, (uint8_t *)conn->local.settings.token); + conn->local.settings.token = NULL; + conn->local.settings.tokenlen = 0; - token->base = ngtcp2_mem_malloc(conn->mem, retry.token.len); - if (token->base == NULL) { + token = ngtcp2_mem_malloc(conn->mem, retry.tokenlen); + if (token == NULL) { return NGTCP2_ERR_NOMEM; } - token->len = retry.token.len; - ngtcp2_cpymem(token->base, retry.token.base, retry.token.len); + ngtcp2_cpymem(token, retry.token, retry.tokenlen); + + conn->local.settings.token = token; + conn->local.settings.tokenlen = retry.tokenlen; reset_conn_stat_recovery(&conn->cstat); conn_reset_congestion_state(conn, ts); @@ -5423,7 +5312,6 @@ int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) { int rv; - ngtcp2_frame_chain *frc = NULL; ngtcp2_ssize num_acked; ngtcp2_conn_stat *cstat = &conn->cstat; @@ -5431,7 +5319,7 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, return NGTCP2_ERR_PROTO; } - rv = ngtcp2_pkt_validate_ack(fr); + rv = ngtcp2_pkt_validate_ack(fr, conn->local.settings.initial_pkt_num); if (rv != 0) { return rv; } @@ -5443,7 +5331,6 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, if (num_acked < 0) { /* TODO assert this */ assert(ngtcp2_err_is_fatal((int)num_acked)); - ngtcp2_frame_chain_list_objalloc_del(frc, &conn->frc_objalloc, conn->mem); return (int)num_acked; } @@ -5778,10 +5665,10 @@ decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, const ngtcp2_crypto_cipher *hp, * NGTCP2_ERR_CRYPTO * TLS backend reported error */ -static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, - ngtcp2_strm *strm, - uint64_t rx_offset) { +static int +conn_emit_pending_crypto_data(ngtcp2_conn *conn, + ngtcp2_encryption_level encryption_level, + ngtcp2_strm *strm, uint64_t rx_offset) { size_t datalen; const uint8_t *data; int rv; @@ -5801,7 +5688,8 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, offset = rx_offset; rx_offset += datalen; - rv = conn_call_recv_crypto_data(conn, crypto_level, offset, data, datalen); + rv = conn_call_recv_crypto_data(conn, encryption_level, offset, data, + datalen); if (rv != 0) { return rv; } @@ -5816,13 +5704,13 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn, */ static int conn_recv_connection_close(ngtcp2_conn *conn, ngtcp2_connection_close *fr) { - ngtcp2_connection_close_error *ccerr = &conn->rx.ccerr; + ngtcp2_ccerr *ccerr = &conn->rx.ccerr; conn->state = NGTCP2_CS_DRAINING; if (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE) { - ccerr->type = NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT; + ccerr->type = NGTCP2_CCERR_TYPE_TRANSPORT; } else { - ccerr->type = NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION; + ccerr->type = NGTCP2_CCERR_TYPE_APPLICATION; } ccerr->error_code = fr->error_code; ccerr->frame_type = fr->frame_type; @@ -5834,16 +5722,14 @@ static int conn_recv_connection_close(ngtcp2_conn *conn, } if (ccerr->reason == NULL) { - ccerr->reason = ngtcp2_mem_malloc( - conn->mem, NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN); + ccerr->reason = ngtcp2_mem_malloc(conn->mem, NGTCP2_CCERR_MAX_REASONLEN); if (ccerr->reason == NULL) { return NGTCP2_ERR_NOMEM; } } - ccerr->reasonlen = - ngtcp2_min(fr->reasonlen, NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN); - ngtcp2_cpymem(ccerr->reason, fr->reason, ccerr->reasonlen); + ccerr->reasonlen = ngtcp2_min(fr->reasonlen, NGTCP2_CCERR_MAX_REASONLEN); + ngtcp2_cpymem((uint8_t *)ccerr->reason, fr->reason, ccerr->reasonlen); return 0; } @@ -5872,7 +5758,9 @@ static void conn_recv_path_challenge(ngtcp2_conn *conn, const ngtcp2_path *path, static void conn_reset_congestion_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) { conn_reset_conn_stat_cc(conn, &conn->cstat); - conn->cc.reset(&conn->cc, &conn->cstat, ts); + if (conn->cc.reset) { + conn->cc.reset(&conn->cc, &conn->cstat, ts); + } if (conn->hs_pktns) { ngtcp2_rtb_reset_cc_state(&conn->hs_pktns->rtb, @@ -5887,7 +5775,6 @@ static void conn_reset_congestion_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) { static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr, ngtcp2_tstamp ts) { int rv; - ngtcp2_duration pto, timeout; ngtcp2_pv *pv = conn->pv, *npv; uint8_t ent_flags; @@ -5904,53 +5791,52 @@ static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr, if (!(pv->flags & NGTCP2_PV_FLAG_DONT_CARE)) { if (!(pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE)) { - if (pv->dcid.seq != conn->dcid.current.seq) { - assert(conn->dcid.current.cid.datalen); + assert(!conn->server); + assert(pv->dcid.seq != conn->dcid.current.seq); + assert(conn->dcid.current.cid.datalen); - rv = conn_retire_dcid(conn, &conn->dcid.current, ts); - if (rv != 0) { - return rv; - } - ngtcp2_dcid_copy(&conn->dcid.current, &pv->dcid); + rv = conn_retire_dcid(conn, &conn->dcid.current, ts); + if (rv != 0) { + return rv; } + ngtcp2_dcid_copy(&conn->dcid.current, &pv->dcid); + conn_reset_congestion_state(conn, ts); conn_reset_ecn_validation_state(conn); } - if (ngtcp2_path_eq(&pv->dcid.ps.path, &conn->dcid.current.ps.path)) { - conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; - } + assert(ngtcp2_path_eq(&pv->dcid.ps.path, &conn->dcid.current.ps.path)); - rv = conn_call_path_validation(conn, pv, - NGTCP2_PATH_VALIDATION_RESULT_SUCCESS); - if (rv != 0) { - return rv; - } + conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; if (!conn->local.settings.no_pmtud) { ngtcp2_conn_stop_pmtud(conn); - if (!(pv->flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) { + if (!(ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) { rv = conn_start_pmtud(conn); if (rv != 0) { return rv; } } } + + if (!(ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED)) { + rv = conn_call_path_validation(conn, pv, + NGTCP2_PATH_VALIDATION_RESULT_SUCCESS); + if (rv != 0) { + return rv; + } + } } if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) { - pto = conn_compute_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, pv->fallback_pto); - if (ent_flags & NGTCP2_PV_ENTRY_FLAG_UNDERSIZED) { assert(conn->server); /* Validate path again */ - rv = ngtcp2_pv_new(&npv, &pv->dcid, timeout, - NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE | - NGTCP2_PV_FLAG_MTU_PROBE, - &conn->log, conn->mem); + rv = ngtcp2_pv_new(&npv, &pv->dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, &conn->log, + conn->mem); if (rv != 0) { return rv; } @@ -5959,7 +5845,8 @@ static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr, ngtcp2_dcid_copy(&npv->fallback_dcid, &pv->fallback_dcid); npv->fallback_pto = pv->fallback_pto; } else { - rv = ngtcp2_pv_new(&npv, &pv->fallback_dcid, timeout, + rv = ngtcp2_pv_new(&npv, &pv->fallback_dcid, + conn_compute_pv_timeout_pto(conn, pv->fallback_pto), NGTCP2_PV_FLAG_DONT_CARE, &conn->log, conn->mem); if (rv != 0) { return rv; @@ -5999,8 +5886,7 @@ static size_t pkt_num_bits(size_t pkt_numlen) { case 4: return 32; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } @@ -6019,17 +5905,7 @@ static int pktns_pkt_num_is_duplicate(ngtcp2_pktns *pktns, int64_t pkt_num) { static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num, int ack_eliciting, ngtcp2_tstamp ts) { int rv; - - if (ack_eliciting && pktns->rx.max_ack_eliciting_pkt_num + 1 != pkt_num) { - ngtcp2_acktr_immediate_ack(&pktns->acktr); - } - if (pktns->rx.max_pkt_num < pkt_num) { - pktns->rx.max_pkt_num = pkt_num; - pktns->rx.max_pkt_ts = ts; - } - if (ack_eliciting && pktns->rx.max_ack_eliciting_pkt_num < pkt_num) { - pktns->rx.max_ack_eliciting_pkt_num = pkt_num; - } + ngtcp2_range r; rv = ngtcp2_gaptr_push(&pktns->rx.pngap, (uint64_t)pkt_num, 1); if (rv != 0) { @@ -6040,6 +5916,30 @@ static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num, ngtcp2_gaptr_drop_first_gap(&pktns->rx.pngap); } + if (ack_eliciting) { + if (pktns->rx.max_ack_eliciting_pkt_num != -1) { + if (pkt_num < pktns->rx.max_ack_eliciting_pkt_num) { + ngtcp2_acktr_immediate_ack(&pktns->acktr); + } else if (pkt_num > pktns->rx.max_ack_eliciting_pkt_num) { + r = ngtcp2_gaptr_get_first_gap_after( + &pktns->rx.pngap, (uint64_t)pktns->rx.max_ack_eliciting_pkt_num); + + if (r.begin < (uint64_t)pkt_num) { + ngtcp2_acktr_immediate_ack(&pktns->acktr); + } + } + } + + if (pktns->rx.max_ack_eliciting_pkt_num < pkt_num) { + pktns->rx.max_ack_eliciting_pkt_num = pkt_num; + } + } + + if (pktns->rx.max_pkt_num < pkt_num) { + pktns->rx.max_pkt_num = pkt_num; + pktns->rx.max_pkt_ts = ts; + } + return 0; } @@ -6047,9 +5947,9 @@ static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num, * verify_token verifies |hd| contains |token| in its token field. It * returns 0 if it succeeds, or NGTCP2_ERR_PROTO. */ -static int verify_token(const ngtcp2_vec *token, const ngtcp2_pkt_hd *hd) { - if (token->len == hd->token.len && - ngtcp2_cmemeq(token->base, hd->token.base, token->len)) { +static int verify_token(const uint8_t *token, size_t tokenlen, + const ngtcp2_pkt_hd *hd) { + if (tokenlen == hd->tokenlen && ngtcp2_cmemeq(token, hd->token, tokenlen)) { return 0; } return NGTCP2_ERR_PROTO; @@ -6071,34 +5971,80 @@ static void pktns_increase_ecn_counts(ngtcp2_pktns *pktns, } /* - * vneg_other_versions_includes returns nonzero if |other_versions| of - * length |other_versionslen| includes |version|. |other_versions| is - * the wire image of other_versions field of version_information - * transport parameter, and each version is encoded in network byte - * order. + * vneg_available_versions_includes returns nonzero if + * |available_versions| of length |available_versionslen| includes + * |version|. |available_versions| is the wire image of + * available_versions field of version_information transport + * parameter, and each version is encoded in network byte order. */ -static int vneg_other_versions_includes(const uint8_t *other_versions, - size_t other_versionslen, - uint32_t version) { +static int vneg_available_versions_includes(const uint8_t *available_versions, + size_t available_versionslen, + uint32_t version) { size_t i; + uint32_t v; + + assert(!(available_versionslen & 0x3)); + + if (available_versionslen == 0) { + return 0; + } + + for (i = 0; i < available_versionslen; i += sizeof(uint32_t)) { + available_versions = ngtcp2_get_uint32(&v, available_versions); + + if (version == v) { + return 1; + } + } + + return 0; +} + +/* + * conn_verify_fixed_bit verifies that fixed bit in |hd| is + * acceptable. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_INVALID_ARGUMENT + * Clearing fixed bit is not permitted. + */ +static int conn_verify_fixed_bit(ngtcp2_conn *conn, ngtcp2_pkt_hd *hd) { + if (!(hd->flags & NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR)) { + return 0; + } - assert(!(other_versionslen & 0x3)); + if (conn->server) { + switch (hd->type) { + case NGTCP2_PKT_INITIAL: + case NGTCP2_PKT_0RTT: + case NGTCP2_PKT_HANDSHAKE: + /* TODO we cannot determine whether a token comes from NEW_TOKEN + frame or Retry packet. RFC 9287 requires that a token from + NEW_TOKEN. */ + if (!(conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) && + (conn->local.settings.token_type != NGTCP2_TOKEN_TYPE_NEW_TOKEN || + !conn->local.settings.tokenlen)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } - if (other_versionslen == 0) { - return 0; + break; + } } - for (i = 0; i < other_versionslen; i += sizeof(uint32_t)) { - if (version == ngtcp2_get_uint32(&other_versions[i])) { - return 1; - } + /* TODO we have no information that we enabled grease_quic_bit in + the previous connection. */ + if (!conn->local.transport_params.grease_quic_bit) { + return NGTCP2_ERR_INVALID_ARGUMENT; } return 0; } -static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, - ngtcp2_strm *strm, const ngtcp2_crypto *fr); +static int conn_recv_crypto(ngtcp2_conn *conn, + ngtcp2_encryption_level encryption_level, + ngtcp2_strm *strm, const ngtcp2_stream *fr); static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, const ngtcp2_pkt_info *pi, const uint8_t *pkt, @@ -6164,7 +6110,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_decrypt decrypt; ngtcp2_pktns *pktns; ngtcp2_strm *crypto; - ngtcp2_crypto_level crypto_level; + ngtcp2_encryption_level encryption_level; int invalid_reserved_bits = 0; if (pktlen == 0) { @@ -6210,7 +6156,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, /* Receiving Version Negotiation packet after getting Handshake packet from server is invalid. */ - if (conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) { + if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) { return NGTCP2_ERR_DISCARD_PKT; } @@ -6244,9 +6190,13 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + /* Receiving Retry packet after getting Initial packet from server is invalid. */ - if (conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) { + if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) { return NGTCP2_ERR_DISCARD_PKT; } @@ -6285,9 +6235,13 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + /* Quoted from spec: if subsequent packets of those types include a different Source Connection ID, they MUST be discarded. */ - if ((conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) && + if ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) && !ngtcp2_cid_eq(&conn->dcid.current.cid, &hd.scid)) { ngtcp2_log_rx_pkt_hd(&conn->log, &hd); ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, @@ -6305,7 +6259,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } - if (conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) { + if (conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) { if (conn->early.ckm) { ngtcp2_ssize nread2; /* TODO Avoid to parse header twice. */ @@ -6351,15 +6305,16 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, NGTCP2_MAX_UDP_PAYLOAD_SIZE, dgramlen); return NGTCP2_ERR_DISCARD_PKT; } - if (conn->local.settings.token.len) { - rv = verify_token(&conn->local.settings.token, &hd); + if (conn->local.settings.tokenlen) { + rv = verify_token(conn->local.settings.token, + conn->local.settings.tokenlen, &hd); if (rv != 0) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet was ignored because token is invalid"); return NGTCP2_ERR_DISCARD_PKT; } } - if ((conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) == 0) { + if ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) == 0) { /* Set rcid here so that it is available to callback. If this packet is discarded later in this function and no packet is processed in this connection attempt so far, connection @@ -6372,7 +6327,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } } } else { - if (hd.token.len != 0) { + if (hd.tokenlen != 0) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet was ignored because token is not empty"); return NGTCP2_ERR_DISCARD_PKT; @@ -6380,9 +6335,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, if (hd.version != conn->client_chosen_version && !conn->negotiated_version && conn->vneg.version != hd.version) { - if (!vneg_other_versions_includes(conn->vneg.other_versions, - conn->vneg.other_versionslen, - hd.version)) { + if (!vneg_available_versions_includes(conn->vneg.available_versions, + conn->vneg.available_versionslen, + hd.version)) { return NGTCP2_ERR_DISCARD_PKT; } @@ -6402,7 +6357,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = conn->in_pktns; crypto = &pktns->crypto.strm; - crypto_level = NGTCP2_CRYPTO_LEVEL_INITIAL; + encryption_level = NGTCP2_ENCRYPTION_LEVEL_INITIAL; if (hd.version == conn->client_chosen_version) { ckm = pktns->crypto.rx.ckm; @@ -6441,7 +6396,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, pktns = conn->hs_pktns; crypto = &pktns->crypto.strm; - crypto_level = NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + encryption_level = NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; ckm = pktns->crypto.rx.ckm; hp_ctx = &pktns->crypto.rx.hp_ctx; @@ -6543,8 +6498,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, switch (hd.type) { case NGTCP2_PKT_INITIAL: - if (!conn->server || ((conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) && - !ngtcp2_cid_eq(&conn->rcid, &hd.dcid))) { + if (!conn->server || + ((conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED) && + !ngtcp2_cid_eq(&conn->rcid, &hd.dcid))) { rv = conn_verify_dcid(conn, NULL, &hd); if (rv != 0) { if (ngtcp2_err_is_fatal(rv)) { @@ -6568,7 +6524,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } break; default: - assert(0); + ngtcp2_unreachable(); } if (payloadlen == 0) { @@ -6580,8 +6536,8 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } if (hd.type == NGTCP2_PKT_INITIAL && - !(conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED)) { - conn->flags |= NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED; + !(conn->flags & NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED)) { + conn->flags |= NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED; if (!conn->server) { conn->dcid.current.cid = hd.scid; } @@ -6623,7 +6579,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, break; case NGTCP2_FRAME_CRYPTO: if (!conn->server && !conn->negotiated_version && - ngtcp2_vec_len(fr->crypto.data, fr->crypto.datacnt)) { + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt)) { conn->negotiated_version = hd.version; ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, @@ -6631,7 +6587,7 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, conn->negotiated_version); } - rv = conn_recv_crypto(conn, crypto_level, crypto, &fr->crypto); + rv = conn_recv_crypto(conn, encryption_level, crypto, &fr->stream); if (rv != 0) { return rv; } @@ -6653,9 +6609,9 @@ conn_recv_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_qlog_write_frame(&conn->qlog, fr); } - if (conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) { - /* Successful processing of Handshake packet from client verifies - source address. */ + if (hd.type == NGTCP2_PKT_HANDSHAKE) { + /* Successful processing of Handshake packet from a remote + endpoint validates its source address. */ conn->dcid.current.flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; } @@ -6740,7 +6696,7 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn, if ((pkt[0] & NGTCP2_HEADER_FORM_BIT) && pktlen > 4) { /* Not a Version Negotiation packet */ - version = ngtcp2_get_uint32(&pkt[1]); + ngtcp2_get_uint32(&version, &pkt[1]); if (ngtcp2_pkt_get_type_long(version, pkt[0]) == NGTCP2_PKT_INITIAL) { if (conn->server) { if (is_unrecoverable_error((int)nread)) { @@ -6863,7 +6819,7 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, int rv; uint64_t offset; uint32_t sdflags; - int handshake_completed = conn_is_handshake_completed(conn); + int handshake_completed = conn_is_tls_handshake_completed(conn); if (!strm->rx.rob) { return 0; @@ -6892,7 +6848,7 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; } if (!handshake_completed) { - sdflags |= NGTCP2_STREAM_DATA_FLAG_EARLY; + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; } rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, datalen); @@ -6909,8 +6865,9 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, * |rx_offset_base| is the offset in the entire TLS handshake stream. * fr->offset specifies the offset in each encryption level. * |max_rx_offset| is, if it is nonzero, the maximum offset in the - * entire TLS handshake stream that |fr| can carry. |crypto_level| is - * the encryption level where this data is received. + * entire TLS handshake stream that |fr| can carry. + * |encryption_level| is the encryption level where this data is + * received. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -6926,8 +6883,9 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, * NGTCP2_ERR_CALLBACK_FAILURE * User-defined callback function failed. */ -static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, - ngtcp2_strm *crypto, const ngtcp2_crypto *fr) { +static int conn_recv_crypto(ngtcp2_conn *conn, + ngtcp2_encryption_level encryption_level, + ngtcp2_strm *crypto, const ngtcp2_stream *fr) { uint64_t fr_end_offset; uint64_t rx_offset; int rv; @@ -6947,8 +6905,9 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, if (fr_end_offset <= rx_offset) { if (conn->server && !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT) && - crypto_level == NGTCP2_CRYPTO_LEVEL_INITIAL) { - /* recovery draft: Speeding Up Handshake Completion + encryption_level == NGTCP2_ENCRYPTION_LEVEL_INITIAL) { + /* https://datatracker.ietf.org/doc/html/rfc9002#section-6.2.3: + Speeding Up Handshake Completion When a server receives an Initial packet containing duplicate CRYPTO data, it can assume the client did not receive all of @@ -6979,17 +6938,16 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, uint64_t offset = rx_offset; rx_offset += datalen; - rv = ngtcp2_strm_update_rx_offset(crypto, rx_offset); - if (rv != 0) { - return rv; - } + ngtcp2_strm_update_rx_offset(crypto, rx_offset); - rv = conn_call_recv_crypto_data(conn, crypto_level, offset, data, datalen); + rv = conn_call_recv_crypto_data(conn, encryption_level, offset, data, + datalen); if (rv != 0) { return rv; } - rv = conn_emit_pending_crypto_data(conn, crypto_level, crypto, rx_offset); + rv = conn_emit_pending_crypto_data(conn, encryption_level, crypto, + rx_offset); if (rv != 0) { return rv; } @@ -7106,14 +7064,15 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { 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; } - - if (!bidi) { - ngtcp2_strm_shutdown(strm, NGTCP2_STRM_FLAG_SHUT_WR); - } } fr_end_offset = fr->offset + datalen; @@ -7144,7 +7103,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { return NGTCP2_ERR_FINAL_SIZE; } - if (strm->flags & NGTCP2_STRM_FLAG_RECV_RST) { + if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) { return 0; } @@ -7170,7 +7129,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { return 0; } - if (strm->flags & NGTCP2_STRM_FLAG_RECV_RST) { + if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) { return 0; } } @@ -7186,10 +7145,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { datalen -= ncut; rx_offset += datalen; - rv = ngtcp2_strm_update_rx_offset(strm, rx_offset); - if (rv != 0) { - return rv; - } + ngtcp2_strm_update_rx_offset(strm, rx_offset); } else { data = NULL; datalen = 0; @@ -7206,8 +7162,8 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { if (fin) { sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; } - if (!conn_is_handshake_completed(conn)) { - sdflags |= NGTCP2_STREAM_DATA_FLAG_EARLY; + if (!conn_is_tls_handshake_completed(conn)) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; } rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, (size_t)datalen); @@ -7242,25 +7198,16 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { */ static int conn_reset_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { - int rv; - ngtcp2_frame_chain *frc; - ngtcp2_pktns *pktns = &conn->pktns; + strm->flags |= NGTCP2_STRM_FLAG_SEND_RESET_STREAM; + strm->tx.reset_stream_app_error_code = app_error_code; - rv = ngtcp2_frame_chain_objalloc_new(&frc, &conn->frc_objalloc); - if (rv != 0) { - return rv; + if (ngtcp2_strm_is_tx_queued(strm)) { + return 0; } - frc->fr.type = NGTCP2_FRAME_RESET_STREAM; - frc->fr.reset_stream.stream_id = strm->stream_id; - frc->fr.reset_stream.app_error_code = app_error_code; - frc->fr.reset_stream.final_size = strm->tx.offset; - - /* TODO This prepends RESET_STREAM to pktns->tx.frq. */ - frc->next = pktns->tx.frq; - pktns->tx.frq = frc; + strm->cycle = conn_tx_strmq_first_cycle(conn); - return 0; + return ngtcp2_conn_tx_strmq_push(conn, strm); } /* @@ -7275,24 +7222,16 @@ static int conn_reset_stream(ngtcp2_conn *conn, ngtcp2_strm *strm, */ static int conn_stop_sending(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { - int rv; - ngtcp2_frame_chain *frc; - ngtcp2_pktns *pktns = &conn->pktns; + strm->flags |= NGTCP2_STRM_FLAG_SEND_STOP_SENDING; + strm->tx.stop_sending_app_error_code = app_error_code; - rv = ngtcp2_frame_chain_objalloc_new(&frc, &conn->frc_objalloc); - if (rv != 0) { - return rv; + if (ngtcp2_strm_is_tx_queued(strm)) { + return 0; } - frc->fr.type = NGTCP2_FRAME_STOP_SENDING; - frc->fr.stop_sending.stream_id = strm->stream_id; - frc->fr.stop_sending.app_error_code = app_error_code; - - /* TODO This prepends STOP_SENDING to pktns->tx.frq. */ - frc->next = pktns->tx.frq; - pktns->tx.frq = frc; + strm->cycle = conn_tx_strmq_first_cycle(conn); - return 0; + return ngtcp2_conn_tx_strmq_push(conn, strm); } /* @@ -7427,7 +7366,7 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn, return NGTCP2_ERR_FINAL_SIZE; } - if (strm->flags & NGTCP2_STRM_FLAG_RECV_RST) { + if (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) { return 0; } @@ -7458,7 +7397,8 @@ static int conn_recv_reset_stream(ngtcp2_conn *conn, ngtcp2_conn_extend_max_offset(conn, datalen); strm->rx.last_offset = fr->final_size; - strm->flags |= NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_RECV_RST; + strm->flags |= + NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_RESET_STREAM_RECVED; ngtcp2_strm_set_app_error_code(strm, fr->app_error_code); @@ -7547,19 +7487,14 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn, /* No RESET_STREAM is required if we have sent FIN and all data have been acknowledged. */ if (!ngtcp2_strm_is_all_tx_data_fin_acked(strm) && - !(strm->flags & NGTCP2_STRM_FLAG_SENT_RST)) { + !(strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM)) { rv = conn_reset_stream(conn, strm, fr->app_error_code); if (rv != 0) { return rv; } } - strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_SENT_RST; - - if (ngtcp2_strm_is_tx_queued(strm) && !ngtcp2_strm_streamfrq_empty(strm)) { - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; - } + strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_RESET_STREAM; ngtcp2_strm_streamfrq_clear(strm); @@ -8042,11 +7977,11 @@ static int conn_recv_new_token(ngtcp2_conn *conn, const ngtcp2_new_token *fr) { return NGTCP2_ERR_PROTO; } - if (fr->token.len == 0) { + if (fr->tokenlen == 0) { return NGTCP2_ERR_FRAME_ENCODING; } - return conn_call_recv_new_token(conn, &fr->token); + return conn_call_recv_new_token(conn, fr->token, fr->tokenlen); } /* @@ -8087,6 +8022,144 @@ static int conn_recv_streams_blocked_uni(ngtcp2_conn *conn, return 0; } +/* + * conn_recv_stream_data_blocked processes the incoming + * STREAM_DATA_BLOCKED frame |fr|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_STREAM_STATE + * STREAM_DATA_BLOCKED is received for a local stream which is not + * initiated; or it is received for a local unidirectional stream. + * NGTCP2_ERR_STREAM_LIMIT + * STREAM_DATA_BLOCKED has remote stream ID which is strictly + * greater than the allowed limit. + * NGTCP2_ERR_FLOW_CONTROL + * STREAM_DATA_BLOCKED frame violates flow control limit. + * NGTCP2_ERR_FINAL_SIZE + * The offset is strictly larger than it is permitted. + * NGTCP2_ERR_NOMEM + * Out of memory. + * NGTCP2_ERR_CALLBACK_FAILURE + * User-defined callback function failed. + */ +static int conn_recv_stream_data_blocked(ngtcp2_conn *conn, + ngtcp2_stream_data_blocked *fr) { + int rv; + ngtcp2_strm *strm; + ngtcp2_idtr *idtr; + int local_stream = conn_local_stream(conn, fr->stream_id); + int bidi = bidi_stream(fr->stream_id); + uint64_t datalen; + + if (bidi) { + if (local_stream) { + if (conn->local.bidi.next_stream_id <= fr->stream_id) { + return NGTCP2_ERR_STREAM_STATE; + } + } else if (conn->remote.bidi.max_streams < + ngtcp2_ord_stream_id(fr->stream_id)) { + return NGTCP2_ERR_STREAM_LIMIT; + } + + idtr = &conn->remote.bidi.idtr; + } else { + if (local_stream) { + return NGTCP2_ERR_STREAM_STATE; + } + if (conn->remote.uni.max_streams < ngtcp2_ord_stream_id(fr->stream_id)) { + return NGTCP2_ERR_STREAM_LIMIT; + } + + idtr = &conn->remote.uni.idtr; + } + + strm = ngtcp2_conn_find_stream(conn, fr->stream_id); + if (strm == NULL) { + if (local_stream) { + return 0; + } + + rv = ngtcp2_idtr_open(idtr, fr->stream_id); + if (rv != 0) { + if (ngtcp2_err_is_fatal(rv)) { + return rv; + } + assert(rv == NGTCP2_ERR_STREAM_IN_USE); + return 0; + } + + /* Frame is received before we create ngtcp2_strm object. */ + strm = ngtcp2_objalloc_strm_get(&conn->strm_objalloc); + if (strm == NULL) { + return NGTCP2_ERR_NOMEM; + } + rv = ngtcp2_conn_init_stream(conn, strm, fr->stream_id, NULL); + if (rv != 0) { + ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm); + 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; + } + } + + if (strm->rx.max_offset < fr->offset) { + return NGTCP2_ERR_FLOW_CONTROL; + } + + if (fr->offset <= strm->rx.last_offset) { + return 0; + } + + if (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) { + return NGTCP2_ERR_FINAL_SIZE; + } + + datalen = fr->offset - strm->rx.last_offset; + if (datalen) { + if (conn_max_data_violated(conn, datalen)) { + return NGTCP2_ERR_FLOW_CONTROL; + } + + conn->rx.offset += datalen; + + if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) { + ngtcp2_conn_extend_max_offset(conn, datalen); + } + } + + strm->rx.last_offset = fr->offset; + + return 0; +} + +/* + * conn_recv_data_blocked processes the incoming DATA_BLOCKED frame + * |fr|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_FLOW_CONTROL + * It violates connection-level flow control limit. + */ +static int conn_recv_data_blocked(ngtcp2_conn *conn, ngtcp2_data_blocked *fr) { + if (conn->rx.max_offset < fr->offset) { + return NGTCP2_ERR_FLOW_CONTROL; + } + + return 0; +} + /* * conn_select_preferred_addr asks a client application to select a * server address from preferred addresses received from server. If a @@ -8103,7 +8176,6 @@ static int conn_recv_streams_blocked_uni(ngtcp2_conn *conn, static int conn_select_preferred_addr(ngtcp2_conn *conn) { ngtcp2_path_storage ps; int rv; - ngtcp2_duration pto, initial_pto, timeout; ngtcp2_pv *pv; ngtcp2_dcid *dcid; @@ -8129,12 +8201,8 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) { dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0); ngtcp2_dcid_set_path(dcid, &ps.path); - pto = conn_compute_pto(conn, &conn->pktns); - initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, initial_pto); - - rv = ngtcp2_pv_new(&pv, dcid, timeout, NGTCP2_PV_FLAG_PREFERRED_ADDR, - &conn->log, conn->mem); + rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_PREFERRED_ADDR, &conn->log, conn->mem); if (rv != 0) { /* TODO Call ngtcp2_dcid_free here if it is introduced */ return rv; @@ -8180,7 +8248,7 @@ static int conn_recv_handshake_done(ngtcp2_conn *conn, ngtcp2_tstamp ts) { assert(conn->remote.transport_params); - if (conn->remote.transport_params->preferred_address_present) { + if (conn->remote.transport_params->preferred_addr_present) { rv = conn_select_preferred_addr(conn); if (rv != 0) { return rv; @@ -8225,6 +8293,8 @@ static int conn_key_phase_changed(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) { !(hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE); } +static int conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts); + /* * conn_prepare_key_update installs new updated keys. */ @@ -8241,12 +8311,12 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) && tx_ckm->use_count >= pktns->crypto.ctx.max_encryption && - ngtcp2_conn_initiate_key_update(conn, ts) != 0) { + conn_initiate_key_update(conn, ts) != 0) { return NGTCP2_ERR_AEAD_LIMIT_REACHED; } if ((conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) || - (confirmed_ts != UINT64_MAX && confirmed_ts + pto > ts)) { + ngtcp2_tstamp_not_elapsed(confirmed_ts, pto, ts)) { return 0; } @@ -8369,7 +8439,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, ngtcp2_dcid dcid, *bound_dcid, *last; ngtcp2_pv *pv; int rv; - ngtcp2_duration pto, initial_pto, timeout; + ngtcp2_duration pto; int require_new_cid; int local_addr_eq; uint32_t remote_addr_cmp; @@ -8427,10 +8497,6 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "non-probing packet was received from new remote address"); - pto = conn_compute_pto(conn, &conn->pktns); - initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, initial_pto); - len = ngtcp2_ringbuf_len(&conn->dcid.bound.rb); for (i = 0; i < len; ++i) { @@ -8482,13 +8548,16 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, dcid.bytes_recv = 0; dcid.flags &= (uint8_t)~NGTCP2_DCID_FLAG_PATH_VALIDATED; } + + ngtcp2_dcid_set_path(&dcid, path); } - ngtcp2_dcid_set_path(&dcid, path); dcid.bytes_recv += dgramlen; - rv = ngtcp2_pv_new(&pv, &dcid, timeout, NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, - &conn->log, conn->mem); + pto = conn_compute_pto(conn, &conn->pktns); + + rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout_pto(conn, pto), + NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE, &conn->log, conn->mem); if (rv != 0) { return rv; } @@ -8507,11 +8576,6 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, if (!local_addr_eq || (remote_addr_cmp & (NGTCP2_ADDR_COMPARE_FLAG_ADDR | NGTCP2_ADDR_COMPARE_FLAG_FAMILY))) { conn_reset_congestion_state(conn, ts); - } else { - /* For NAT rebinding, keep max_udp_payload_size since client most - likely does not send a padded PATH_CHALLENGE. */ - dcid.max_udp_payload_size = ngtcp2_max( - dcid.max_udp_payload_size, conn->dcid.current.max_udp_payload_size); } ngtcp2_dcid_copy(&conn->dcid.current, &dcid); @@ -8706,6 +8770,61 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi, return 0; } +/* + * conn_allow_path_change_under_disable_active_migration returns + * nonzero if a packet from |path| is acceptable under + * disable_active_migration is on. + */ +static int +conn_allow_path_change_under_disable_active_migration(ngtcp2_conn *conn, + const ngtcp2_path *path) { + uint32_t remote_addr_cmp; + const ngtcp2_preferred_addr *paddr; + ngtcp2_addr addr; + + assert(conn->server); + assert(conn->local.transport_params.disable_active_migration); + + /* If local address does not change, it must be passive migration + (NAT rebinding). */ + if (ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, &path->local)) { + remote_addr_cmp = + ngtcp2_addr_compare(&conn->dcid.current.ps.path.remote, &path->remote); + + return (remote_addr_cmp | NGTCP2_ADDR_COMPARE_FLAG_PORT) == + NGTCP2_ADDR_COMPARE_FLAG_PORT; + } + + /* If local address changes, it must be one of the preferred + addresses. */ + + if (!conn->local.transport_params.preferred_addr_present) { + return 0; + } + + paddr = &conn->local.transport_params.preferred_addr; + + if (paddr->ipv4_present) { + ngtcp2_addr_init(&addr, (const ngtcp2_sockaddr *)&paddr->ipv4, + sizeof(paddr->ipv4)); + + if (ngtcp2_addr_eq(&addr, &path->local)) { + return 1; + } + } + + if (paddr->ipv6_present) { + ngtcp2_addr_init(&addr, (const ngtcp2_sockaddr *)&paddr->ipv6, + sizeof(paddr->ipv6)); + + if (ngtcp2_addr_eq(&addr, &path->local)) { + return 1; + } + } + + return 0; +} + /* * conn_recv_pkt processes a packet contained in the buffer pointed by * |pkt| of length |pktlen|. |pkt| may contain multiple QUIC packets. @@ -8769,6 +8888,15 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, int new_cid_used = 0; int path_challenge_recved = 0; + if (conn->server && conn->local.transport_params.disable_active_migration && + !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) && + !conn_allow_path_change_under_disable_active_migration(conn, path)) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "packet is discarded because active migration is disabled"); + + return NGTCP2_ERR_DISCARD_PKT; + } + if (pkt[0] & NGTCP2_HEADER_FORM_BIT) { nread = ngtcp2_pkt_decode_hd_long(&hd, pkt, pktlen); if (nread < 0) { @@ -8788,6 +8916,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + pktlen = (size_t)nread + hd.len; /* Quoted from spec: if subsequent packets of those types include @@ -8854,6 +8986,10 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_DISCARD_PKT; } + if (conn_verify_fixed_bit(conn, &hd) != 0) { + return NGTCP2_ERR_DISCARD_PKT; + } + pktns = &conn->pktns; aead = &pktns->crypto.ctx.aead; hp = &pktns->crypto.ctx.hp; @@ -9020,7 +9156,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, break; default: /* Unreachable */ - assert(0); + ngtcp2_unreachable(); } } else { rv = conn_verify_dcid(conn, &new_cid_used, &hd); @@ -9118,8 +9254,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, non_probing_pkt = 1; break; case NGTCP2_FRAME_CRYPTO: - rv = conn_recv_crypto(conn, NGTCP2_CRYPTO_LEVEL_APPLICATION, - &pktns->crypto.strm, &fr->crypto); + rv = conn_recv_crypto(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT, + &pktns->crypto.strm, &fr->stream); if (rv != 0) { return rv; } @@ -9221,8 +9357,18 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } non_probing_pkt = 1; break; + case NGTCP2_FRAME_STREAM_DATA_BLOCKED: + rv = conn_recv_stream_data_blocked(conn, &fr->stream_data_blocked); + if (rv != 0) { + return rv; + } + non_probing_pkt = 1; + break; case NGTCP2_FRAME_DATA_BLOCKED: - /* TODO Not implemented yet */ + rv = conn_recv_data_blocked(conn, &fr->data_blocked); + if (rv != 0) { + return rv; + } non_probing_pkt = 1; break; case NGTCP2_FRAME_DATAGRAM: @@ -9468,7 +9614,7 @@ static int conn_sync_stream_data_limit(ngtcp2_conn *conn) { static int conn_handshake_completed(ngtcp2_conn *conn) { int rv; - conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED; + conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; rv = conn_call_handshake_completed(conn); if (rv != 0) { @@ -9637,8 +9783,8 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn, } } - if (conn_is_handshake_completed(conn) && - !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { + if (conn_is_tls_handshake_completed(conn) && + !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { rv = conn_handshake_completed(conn); if (rv != 0) { return rv; @@ -9658,27 +9804,22 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn, } /* - * Client ServerHello might not fit into single Initial packet - * (e.g., resuming session with client authentication). If we get - * Client Initial which does not increase offset or it is 0RTT - * packet buffered, perform address validation in order to buffer + * Client Hello might not fit into single Initial packet (e.g., + * resuming session with client authentication). If we get Client + * Initial which does not increase offset or it is 0RTT packet + * buffered, perform address validation in order to buffer * validated data only. */ if (ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm) == 0) { if (conn->in_pktns->crypto.strm.rx.rob && ngtcp2_rob_data_buffered(conn->in_pktns->crypto.strm.rx.rob)) { /* Address has been validated with token */ - if (conn->local.settings.token.len) { + if (conn->local.settings.tokenlen) { return nread; } return NGTCP2_ERR_RETRY; } - if (conn->in_pktns->rx.buffed_pkts) { - /* 0RTT is buffered, force retry */ - return NGTCP2_ERR_RETRY; - } - /* If neither CRYPTO frame nor 0RTT packet is processed, just - drop connection. */ + /* If CRYPTO frame is not processed, just drop connection. */ return NGTCP2_ERR_DROP_CONN; } @@ -9711,7 +9852,7 @@ static ngtcp2_ssize conn_read_handshake(ngtcp2_conn *conn, conn_discard_initial_state(conn, ts); } - if (!conn_is_handshake_completed(conn)) { + if (!conn_is_tls_handshake_completed(conn)) { /* If server hits amplification limit, it cancels loss detection timer. If server receives a packet from client, the limit is increased and server can send more. If server has @@ -9814,8 +9955,9 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, const ngtcp2_pkt_info zero_pi = {0}; (void)pkt_info_version; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING)); + + conn_update_timestamp(conn, ts); ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu", pktlen); @@ -9840,7 +9982,6 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, switch (conn->state) { case NGTCP2_CS_CLIENT_INITIAL: case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: - case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: nread = conn_read_handshake(conn, path, pi, pkt, pktlen, ts); if (nread < 0) { return (int)nread; @@ -9858,7 +9999,6 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, break; case NGTCP2_CS_SERVER_INITIAL: case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: - case NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED: if (!ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "ignore packet from unknown path during handshake"); @@ -9899,8 +10039,7 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, } break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } return conn_recv_cpkt(conn, path, pi, pkt, pktlen, ts); @@ -9979,7 +10118,7 @@ static int conn_validate_early_transport_params_limits(ngtcp2_conn *conn) { /* * conn_write_handshake writes QUIC handshake packets to the buffer * pointed by |dest| of length |destlen|. |write_datalen| specifies - * the expected length of 0RTT or 1RTT packet payload. Specify 0 to + * the expected length of 0RTT packet payload. Specify 0 to * |write_datalen| if there is no such data. * * This function returns the number of bytes written to the buffer, or @@ -10054,7 +10193,7 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (!conn_handshake_probe_left(conn) && conn_cwnd_is_zero(conn)) { destlen = 0; } else { - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { pending_early_datalen = conn_retry_early_payloadlen(conn); if (pending_early_datalen) { write_datalen = pending_early_datalen; @@ -10072,7 +10211,7 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, destlen -= (size_t)nwrite; } - if (!conn_is_handshake_completed(conn)) { + if (!conn_is_tls_handshake_completed(conn)) { if (!(conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED)) { nwrite = conn_retransmit_retry_early(conn, pi, dest, destlen, NGTCP2_WRITE_PKT_FLAG_NONE, ts); @@ -10094,6 +10233,10 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, return res; } + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { + return res; + } + if (!(conn->flags & NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED)) { return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; } @@ -10117,10 +10260,10 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, assert(conn->remote.transport_params); - if (conn->remote.transport_params->preferred_address_present) { + if (conn->remote.transport_params->preferred_addr_present) { assert(!ngtcp2_ringbuf_full(&conn->dcid.unused.rb)); - paddr = &conn->remote.transport_params->preferred_address; + paddr = &conn->remote.transport_params->preferred_addr; dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused.rb); ngtcp2_dcid_init(dcid, 1, &paddr->cid, paddr->stateless_reset_token); @@ -10245,19 +10388,10 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, switch (vmsg->type) { case NGTCP2_VMSG_TYPE_STREAM: datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt); - send_stream = - conn_retry_early_payloadlen(conn) == 0 && - /* 0 length STREAM frame is allowed */ - (datalen == 0 || - (datalen > 0 && - (vmsg->stream.strm->tx.max_offset - vmsg->stream.strm->tx.offset) && - (conn->tx.max_offset - conn->tx.offset))); + send_stream = conn_retry_early_payloadlen(conn) == 0; if (send_stream) { - write_datalen = - conn_enforce_flow_control(conn, vmsg->stream.strm, datalen); - write_datalen = - ngtcp2_min(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); - write_datalen += NGTCP2_STREAM_OVERHEAD; + 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; @@ -10302,8 +10436,6 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_get_type_long(version, dest[0]) == NGTCP2_PKT_INITIAL) { wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING; conn->pkt.require_padding = 1; - } else { - conn->pkt.require_padding = 0; } } else { assert(!conn->pktns.crypto.rx.ckm); @@ -10325,11 +10457,17 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, early_spktlen = conn_write_pkt(conn, pi, dest, destlen, vmsg, NGTCP2_PKT_0RTT, wflags, ts); - if (early_spktlen < 0) { switch (early_spktlen) { case NGTCP2_ERR_STREAM_DATA_BLOCKED: - return spktlen; + if (!(wflags & NGTCP2_WRITE_PKT_FLAG_MORE)) { + if (spktlen) { + return spktlen; + } + + break; + } + /* fall through */ case NGTCP2_ERR_WRITE_MORE: conn->pkt.hs_spktlen = spktlen; break; @@ -10340,16 +10478,16 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, return spktlen + early_spktlen; } -void ngtcp2_conn_handshake_completed(ngtcp2_conn *conn) { - conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; +void ngtcp2_conn_tls_handshake_completed(ngtcp2_conn *conn) { + conn->flags |= NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED; if (conn->server) { conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED; } } int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn) { - return conn_is_handshake_completed(conn) && - (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED); + return conn_is_tls_handshake_completed(conn) && + (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED); } int ngtcp2_conn_sched_ack(ngtcp2_conn *conn, ngtcp2_acktr *acktr, @@ -10391,14 +10529,17 @@ int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t pktlen) { case NGTCP2_PKT_0RTT: /* 0-RTT packet may arrive before Initial packet due to re-ordering. ngtcp2 does not buffer 0RTT packet unless the - very first Initial packet is received or token is received. */ - return NGTCP2_ERR_RETRY; + very first Initial packet is received or token is received. + Previously, we returned NGTCP2_ERR_RETRY here, so that client + can resend 0RTT data. But it incurs 1RTT already and + diminishes the value of 0RTT. Therefore, we just discard the + packet here for now. */ default: return NGTCP2_ERR_INVALID_ARGUMENT; } if (pktlen < NGTCP2_MAX_UDP_PAYLOAD_SIZE || - (p->token.len == 0 && p->dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN)) { + (p->tokenlen == 0 && p->dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN)) { return NGTCP2_ERR_INVALID_ARGUMENT; } @@ -10526,7 +10667,7 @@ int ngtcp2_conn_install_rx_handshake_key( pktns->crypto.rx.hp_ctx = *hp_ctx; - rv = conn_call_recv_rx_key(conn, NGTCP2_CRYPTO_LEVEL_HANDSHAKE); + rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; @@ -10565,7 +10706,7 @@ int ngtcp2_conn_install_tx_handshake_key( } } - rv = conn_call_recv_tx_key(conn, NGTCP2_CRYPTO_LEVEL_HANDSHAKE); + rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; @@ -10578,10 +10719,10 @@ int ngtcp2_conn_install_tx_handshake_key( return 0; } -int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, - const ngtcp2_crypto_aead_ctx *aead_ctx, - const uint8_t *iv, size_t ivlen, - const ngtcp2_crypto_cipher_ctx *hp_ctx) { +int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn, + const ngtcp2_crypto_aead_ctx *aead_ctx, + const uint8_t *iv, size_t ivlen, + const ngtcp2_crypto_cipher_ctx *hp_ctx) { int rv; assert(ivlen >= 8); @@ -10599,9 +10740,9 @@ int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, conn->flags |= NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED; if (conn->server) { - rv = conn_call_recv_rx_key(conn, NGTCP2_CRYPTO_LEVEL_EARLY); + rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_0RTT); } else { - rv = conn_call_recv_tx_key(conn, NGTCP2_CRYPTO_LEVEL_EARLY); + rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_0RTT); } if (rv != 0) { ngtcp2_crypto_km_del(conn->early.ckm, conn->mem); @@ -10650,7 +10791,7 @@ int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, } } - rv = conn_call_recv_rx_key(conn, NGTCP2_CRYPTO_LEVEL_APPLICATION); + rv = conn_call_recv_rx_key(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; @@ -10696,7 +10837,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, conn_discard_early_key(conn); } - rv = conn_call_recv_tx_key(conn, NGTCP2_CRYPTO_LEVEL_APPLICATION); + rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_1RTT); if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; @@ -10709,7 +10850,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, return 0; } -int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { +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); @@ -10719,7 +10860,7 @@ int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) || !conn->crypto.key_update.new_tx_ckm || !conn->crypto.key_update.new_rx_ckm || - (confirmed_ts != UINT64_MAX && confirmed_ts + 3 * pto > ts)) { + ngtcp2_tstamp_not_elapsed(confirmed_ts, 3 * pto, ts)) { return NGTCP2_ERR_INVALID_STATE; } @@ -10728,6 +10869,12 @@ int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return 0; } +int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + conn_update_timestamp(conn, ts); + + return conn_initiate_key_update(conn, ts); +} + /* * conn_retire_stale_bound_dcid retires stale destination connection * ID in conn->dcid.bound to keep some unused destination connection @@ -10751,7 +10898,7 @@ static int conn_retire_stale_bound_dcid(ngtcp2_conn *conn, assert(dcid->cid.datalen); - if (dcid->bound_ts + timeout > ts) { + if (ngtcp2_tstamp_not_elapsed(dcid->bound_ts, timeout, ts)) { ++i; continue; } @@ -10846,8 +10993,10 @@ ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn) { } static ngtcp2_tstamp conn_handshake_expiry(ngtcp2_conn *conn) { - if (conn_is_handshake_completed(conn) || - conn->local.settings.handshake_timeout == UINT64_MAX) { + if (conn_is_tls_handshake_completed(conn) || + conn->local.settings.handshake_timeout == UINT64_MAX || + conn->local.settings.initial_ts >= + UINT64_MAX - conn->local.settings.handshake_timeout) { return UINT64_MAX; } @@ -10874,7 +11023,13 @@ ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn) { int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { int rv; - ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); + ngtcp2_duration pto; + + conn_update_timestamp(conn, ts); + + pto = conn_compute_pto(conn, &conn->pktns); + + assert(!(conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING)); if (ngtcp2_conn_get_idle_expiry(conn) <= ts) { return NGTCP2_ERR_IDLE_CLOSE; @@ -10919,17 +11074,13 @@ int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } if (conn->server && conn->early.ckm && - conn->early.discard_started_ts != UINT64_MAX) { - if (conn->early.discard_started_ts + 3 * pto <= ts) { - conn_discard_early_key(conn); - } + ngtcp2_tstamp_elapsed(conn->early.discard_started_ts, 3 * pto, ts)) { + conn_discard_early_key(conn); } - if (!conn_is_handshake_completed(conn) && - conn->local.settings.handshake_timeout != UINT64_MAX && - conn->local.settings.initial_ts + - conn->local.settings.handshake_timeout <= - ts) { + if (!conn_is_tls_handshake_completed(conn) && + ngtcp2_tstamp_elapsed(conn->local.settings.initial_ts, + conn->local.settings.handshake_timeout, ts)) { return NGTCP2_ERR_HANDSHAKE_TIMEOUT; } @@ -10940,8 +11091,7 @@ static void acktr_cancel_expired_ack_delay_timer(ngtcp2_acktr *acktr, ngtcp2_duration max_ack_delay, ngtcp2_tstamp ts) { if (!(acktr->flags & NGTCP2_ACKTR_FLAG_CANCEL_TIMER) && - acktr->first_unacked_ts != UINT64_MAX && - acktr->first_unacked_ts + max_ack_delay <= ts) { + ngtcp2_tstamp_elapsed(acktr->first_unacked_ts, max_ack_delay, ts)) { acktr->flags |= NGTCP2_ACKTR_FLAG_CANCEL_TIMER; } } @@ -11006,19 +11156,21 @@ void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts) { * select_preferred_version selects the most preferred version. * |fallback_version| is chosen if no preference is made, or * |preferred_versions| does not include any of |chosen_version| or - * |other_versions|. |chosen_version| is treated as an extra other - * version. + * |available_versions|. |chosen_version| is treated as an extra + * other version. */ static uint32_t select_preferred_version(const uint32_t *preferred_versions, size_t preferred_versionslen, uint32_t chosen_version, - const uint8_t *other_versions, - size_t other_versionslen, + const uint8_t *available_versions, + size_t available_versionslen, uint32_t fallback_version) { size_t i, j; + const uint8_t *p; + uint32_t v; if (!preferred_versionslen || - (!other_versionslen && chosen_version == fallback_version)) { + (!available_versionslen && chosen_version == fallback_version)) { return fallback_version; } @@ -11026,12 +11178,13 @@ static uint32_t select_preferred_version(const uint32_t *preferred_versions, if (preferred_versions[i] == chosen_version) { return chosen_version; } - for (j = 0; j < other_versionslen; j += sizeof(uint32_t)) { - if (preferred_versions[i] != ngtcp2_get_uint32(&other_versions[j])) { - continue; - } + for (j = 0, p = available_versions; j < available_versionslen; + j += sizeof(uint32_t)) { + p = ngtcp2_get_uint32(&v, p); - return preferred_versions[i]; + if (preferred_versions[i] == v) { + return v; + } } } @@ -11054,6 +11207,10 @@ static uint32_t select_preferred_version(const uint32_t *preferred_versions, static int conn_client_validate_transport_params(ngtcp2_conn *conn, const ngtcp2_transport_params *params) { + if (!params->original_dcid_present) { + return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + } + if (!ngtcp2_cid_eq(&conn->rcid, ¶ms->original_dcid)) { return NGTCP2_ERR_TRANSPORT_PARAM; } @@ -11069,8 +11226,7 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, return NGTCP2_ERR_TRANSPORT_PARAM; } - if (params->preferred_address_present && - conn->dcid.current.cid.datalen == 0) { + if (params->preferred_addr_present && conn->dcid.current.cid.datalen == 0) { return NGTCP2_ERR_TRANSPORT_PARAM; } @@ -11079,21 +11235,31 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } - assert(vneg_other_versions_includes(conn->vneg.other_versions, - conn->vneg.other_versionslen, - conn->negotiated_version)); - } else if (conn->client_chosen_version != conn->negotiated_version || - conn->client_chosen_version != - conn->local.settings.original_version) { + assert(vneg_available_versions_includes(conn->vneg.available_versions, + conn->vneg.available_versionslen, + conn->negotiated_version)); + } else if (conn->client_chosen_version != conn->negotiated_version) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } /* When client reacted upon Version Negotiation */ if (conn->local.settings.original_version != conn->client_chosen_version) { - assert(params->version_info_present); + if (!params->version_info_present) { + assert(conn->client_chosen_version == conn->negotiated_version); + + /* QUIC v1 is treated specially. If version_info is missing, no + further validation is necessary. See + https://datatracker.ietf.org/doc/html/rfc9368#section-8 + */ + if (conn->client_chosen_version == NGTCP2_PROTO_VER_V1) { + return 0; + } + + return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; + } - /* Server choose original version after Version Negotiation. - Draft does not say this particular case, but this smells like + /* Server choose original version after Version Negotiation. RFC + 9368 does not say this particular case, but this smells like misbehaved server because server should accept original_version in the original connection. */ if (conn->local.settings.original_version == @@ -11102,7 +11268,7 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, } /* Check version downgrade on incompatible version negotiation. */ - if (params->version_info.other_versionslen == 0) { + if (params->version_info.available_versionslen == 0) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } @@ -11110,8 +11276,8 @@ conn_client_validate_transport_params(ngtcp2_conn *conn, select_preferred_version(conn->vneg.preferred_versions, conn->vneg.preferred_versionslen, params->version_info.chosen_version, - params->version_info.other_versions, - params->version_info.other_versionslen, + params->version_info.available_versions, + params->version_info.available_versionslen, /* fallback_version = */ 0)) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } @@ -11128,8 +11294,8 @@ ngtcp2_conn_server_negotiate_version(ngtcp2_conn *conn, return select_preferred_version( conn->vneg.preferred_versions, conn->vneg.preferred_versionslen, - version_info->chosen_version, version_info->other_versions, - version_info->other_versionslen, version_info->chosen_version); + version_info->chosen_version, version_info->available_versions, + version_info->available_versionslen, version_info->chosen_version); } int ngtcp2_conn_set_remote_transport_params( @@ -11145,7 +11311,11 @@ int ngtcp2_conn_set_remote_transport_params( return 0; } - /* Assume that ngtcp2_decode_transport_params sets default value if + if (!params->initial_scid_present) { + return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + } + + /* Assume that ngtcp2_transport_params_decode sets default value if active_connection_id_limit is omitted. */ if (params->active_connection_id_limit < NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) { @@ -11164,7 +11334,20 @@ int ngtcp2_conn_set_remote_transport_params( } if (conn->server) { + if (params->original_dcid_present || + params->stateless_reset_token_present || + params->preferred_addr_present || params->retry_scid_present) { + return NGTCP2_ERR_TRANSPORT_PARAM; + } + if (params->version_info_present) { + if (!vneg_available_versions_includes( + params->version_info.available_versions, + params->version_info.available_versionslen, + params->version_info.chosen_version)) { + return NGTCP2_ERR_TRANSPORT_PARAM; + } + if (params->version_info.chosen_version != conn->client_chosen_version) { return NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE; } @@ -11195,11 +11378,7 @@ int ngtcp2_conn_set_remote_transport_params( } } - ngtcp2_log_remote_tp(&conn->log, - conn->server - ? NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO - : NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, - params); + ngtcp2_log_remote_tp(&conn->log, params); ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server, NGTCP2_QLOG_SIDE_REMOTE); @@ -11231,17 +11410,13 @@ int ngtcp2_conn_set_remote_transport_params( return 0; } -int ngtcp2_conn_decode_remote_transport_params(ngtcp2_conn *conn, - const uint8_t *data, - size_t datalen) { +int ngtcp2_conn_decode_and_set_remote_transport_params(ngtcp2_conn *conn, + const uint8_t *data, + size_t datalen) { ngtcp2_transport_params params; int rv; - rv = ngtcp2_decode_transport_params( - ¶ms, - conn->server ? NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO - : NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, - data, datalen); + rv = ngtcp2_transport_params_decode(¶ms, data, datalen); if (rv != 0) { return rv; } @@ -11258,20 +11433,72 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn) { return conn->remote.transport_params; } -void ngtcp2_conn_set_early_remote_transport_params_versioned( - ngtcp2_conn *conn, int transport_params_version, - const ngtcp2_transport_params *params) { +ngtcp2_ssize ngtcp2_conn_encode_0rtt_transport_params(ngtcp2_conn *conn, + uint8_t *dest, + size_t destlen) { + ngtcp2_transport_params params, *src; + + if (conn->server) { + src = &conn->local.transport_params; + } else { + assert(conn->remote.transport_params); + + src = conn->remote.transport_params; + } + + ngtcp2_transport_params_default(¶ms); + + params.initial_max_streams_bidi = src->initial_max_streams_bidi; + params.initial_max_streams_uni = src->initial_max_streams_uni; + params.initial_max_stream_data_bidi_local = + src->initial_max_stream_data_bidi_local; + params.initial_max_stream_data_bidi_remote = + src->initial_max_stream_data_bidi_remote; + params.initial_max_stream_data_uni = src->initial_max_stream_data_uni; + params.initial_max_data = src->initial_max_data; + params.active_connection_id_limit = src->active_connection_id_limit; + params.max_datagram_frame_size = src->max_datagram_frame_size; + + if (conn->server) { + params.max_idle_timeout = src->max_idle_timeout; + params.max_udp_payload_size = src->max_udp_payload_size; + params.disable_active_migration = src->disable_active_migration; + } + + return ngtcp2_transport_params_encode(dest, destlen, ¶ms); +} + +int ngtcp2_conn_decode_and_set_0rtt_transport_params(ngtcp2_conn *conn, + const uint8_t *data, + size_t datalen) { + ngtcp2_transport_params params; + int rv; + + rv = ngtcp2_transport_params_decode(¶ms, data, datalen); + if (rv != 0) { + return rv; + } + + return ngtcp2_conn_set_0rtt_remote_transport_params(conn, ¶ms); +} + +int ngtcp2_conn_set_0rtt_remote_transport_params( + ngtcp2_conn *conn, const ngtcp2_transport_params *params) { ngtcp2_transport_params *p; - (void)transport_params_version; assert(!conn->server); assert(!conn->remote.transport_params); /* Assume that all pointer fields in p are NULL */ p = ngtcp2_mem_calloc(conn->mem, 1, sizeof(*p)); + if (p == NULL) { + return NGTCP2_ERR_NOMEM; + } conn->remote.transport_params = p; + ngtcp2_transport_params_default(conn->remote.transport_params); + p->initial_max_streams_bidi = params->initial_max_streams_bidi; p->initial_max_streams_uni = params->initial_max_streams_uni; p->initial_max_stream_data_bidi_local = @@ -11280,18 +11507,17 @@ void ngtcp2_conn_set_early_remote_transport_params_versioned( params->initial_max_stream_data_bidi_remote; p->initial_max_stream_data_uni = params->initial_max_stream_data_uni; p->initial_max_data = params->initial_max_data; + /* we might hit garbage, then set the sane default. */ p->active_connection_id_limit = ngtcp2_max(NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT, params->active_connection_id_limit); - p->max_idle_timeout = params->max_idle_timeout; - if (!params->max_udp_payload_size) { - p->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; - } else { + 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(NGTCP2_MAX_UDP_PAYLOAD_SIZE, params->max_udp_payload_size); } - p->disable_active_migration = params->disable_active_migration; - p->max_datagram_frame_size = params->max_datagram_frame_size; /* These parameters are treated specially. If server accepts early data, it must not set values for these parameters that are @@ -11318,14 +11544,21 @@ void ngtcp2_conn_set_early_remote_transport_params_versioned( ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, p, conn->server, NGTCP2_QLOG_SIDE_REMOTE); + + return 0; } int ngtcp2_conn_set_local_transport_params_versioned( ngtcp2_conn *conn, int transport_params_version, const ngtcp2_transport_params *params) { - (void)transport_params_version; + ngtcp2_transport_params paramsbuf; + + params = ngtcp2_transport_params_convert_to_latest( + ¶msbuf, transport_params_version, params); assert(conn->server); + assert(params->active_connection_id_limit >= + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT); assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE); if (conn->hs_pktns == NULL || conn->hs_pktns->crypto.tx.ckm) { @@ -11345,24 +11578,20 @@ int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn) { assert(1 == ngtcp2_ksl_len(&conn->scid.set)); - if (params->active_connection_id_limit == 0) { - params->active_connection_id_limit = - NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; - } - params->initial_scid = conn->oscid; + params->initial_scid_present = 1; if (conn->oscid.datalen == 0) { - params->preferred_address_present = 0; + params->preferred_addr_present = 0; } - if (conn->server && params->preferred_address_present) { + if (conn->server && params->preferred_addr_present) { scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); if (scident == NULL) { return NGTCP2_ERR_NOMEM; } - ngtcp2_scid_init(scident, 1, ¶ms->preferred_address.cid); + ngtcp2_scid_init(scident, 1, ¶ms->preferred_addr.cid); rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scident->cid, scident); if (rv != 0) { @@ -11396,11 +11625,8 @@ ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn) { ngtcp2_ssize ngtcp2_conn_encode_local_transport_params(ngtcp2_conn *conn, uint8_t *dest, size_t destlen) { - return ngtcp2_encode_transport_params( - dest, destlen, - conn->server ? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS - : NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, - &conn->local.transport_params); + return ngtcp2_transport_params_encode(dest, destlen, + &conn->local.transport_params); } int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -11485,7 +11711,6 @@ static ngtcp2_ssize conn_write_vmsg_wrapper(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_ssize nwrite; - int undersized; nwrite = ngtcp2_conn_write_vmsg(conn, path, pkt_info_version, pi, dest, destlen, vmsg, ts); @@ -11497,20 +11722,11 @@ static ngtcp2_ssize conn_write_vmsg_wrapper(ngtcp2_conn *conn, conn->rst.is_cwnd_limited = 1; } - if (vmsg == NULL && cstat->bytes_in_flight < cstat->cwnd && - conn->tx.strmq_nretrans == 0) { - if (conn->local.settings.no_udp_payload_size_shaping) { - undersized = (size_t)nwrite < conn->local.settings.max_udp_payload_size; - } else { - undersized = (size_t)nwrite < conn->dcid.current.max_udp_payload_size; - } - - if (undersized) { - conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight; + if (nwrite == 0 && cstat->bytes_in_flight < cstat->cwnd) { + conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight; - if (conn->rst.app_limited == 0) { - conn->rst.app_limited = cstat->max_udp_payload_size; - } + if (conn->rst.app_limited == 0) { + conn->rst.app_limited = cstat->max_tx_udp_payload_size; } } @@ -11566,6 +11782,21 @@ ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( destlen, pvmsg, ts); } +ngtcp2_ssize ngtcp2_conn_write_datagram_versioned( + ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, + ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted, + uint32_t flags, uint64_t dgram_id, const uint8_t *data, size_t datalen, + ngtcp2_tstamp ts) { + ngtcp2_vec datav; + + datav.len = datalen; + datav.base = (uint8_t *)data; + + return ngtcp2_conn_writev_datagram_versioned(conn, path, pkt_info_version, pi, + dest, destlen, paccepted, flags, + dgram_id, &datav, 1, ts); +} + ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted, @@ -11584,8 +11815,12 @@ ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( } datalen = ngtcp2_vec_len_varint(datav, datavcnt); - if (datalen == -1 || (uint64_t)datalen > SIZE_MAX) { - return NGTCP2_ERR_INVALID_STATE; + if (datalen == -1 +#if UINT64_MAX > SIZE_MAX + || (uint64_t)datalen > SIZE_MAX +#endif /* UINT64_MAX > SIZE_MAX */ + ) { + return NGTCP2_ERR_INVALID_ARGUMENT; } if (conn->remote.transport_params->max_datagram_frame_size < @@ -11617,15 +11852,12 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_ssize res = 0; uint64_t server_tx_left; - uint64_t datalen; - uint64_t write_datalen = 0; int64_t prev_in_pkt_num = -1; ngtcp2_ksl_it it; ngtcp2_rtb_entry *rtbent; (void)pkt_info_version; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + conn_update_timestamp(conn, ts); if (path) { ngtcp2_path_copy(path, &conn->dcid.current.ps.path); @@ -11638,14 +11870,15 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, pi->ecn = NGTCP2_ECN_NOT_ECT; } - if (!conn_pacing_pkt_tx_allowed(conn, ts)) { - return 0; - } - switch (conn->state) { case NGTCP2_CS_CLIENT_INITIAL: case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: - case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: + if (!conn_pacing_pkt_tx_allowed(conn, ts)) { + assert(!ppe_pending); + + return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); + } + nwrite = conn_client_write_handshake(conn, pi, dest, destlen, vmsg, ts); /* We might be unable to write a packet because of depletion of congestion window budget, perhaps due to packet loss that @@ -11675,14 +11908,28 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, break; case NGTCP2_CS_SERVER_INITIAL: case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: - case NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED: + if (!conn_pacing_pkt_tx_allowed(conn, ts)) { + assert(!ppe_pending); + + if (!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { + server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); + if (server_tx_left == 0) { + return 0; + } + + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); + } + + return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); + } + if (!ppe_pending) { if (!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); if (server_tx_left == 0) { if (cstat->loss_detection_timer != UINT64_MAX) { ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer canceled due to amplification limit"); cstat->loss_detection_timer = UINT64_MAX; } @@ -11693,40 +11940,16 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); } - if (vmsg) { - switch (vmsg->type) { - case NGTCP2_VMSG_TYPE_STREAM: - datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt); - if (datalen == 0 || (datalen > 0 && - (vmsg->stream.strm->tx.max_offset - - vmsg->stream.strm->tx.offset) && - (conn->tx.max_offset - conn->tx.offset))) { - write_datalen = - conn_enforce_flow_control(conn, vmsg->stream.strm, datalen); - write_datalen = - ngtcp2_min(write_datalen, NGTCP2_MIN_COALESCED_PAYLOADLEN); - write_datalen += NGTCP2_STREAM_OVERHEAD; - } - break; - case NGTCP2_VMSG_TYPE_DATAGRAM: - write_datalen = - ngtcp2_vec_len(vmsg->datagram.data, vmsg->datagram.datacnt) + - NGTCP2_DATAGRAM_OVERHEAD; - break; - default: - assert(0); - } - - if (conn->in_pktns && write_datalen > 0) { - it = ngtcp2_rtb_head(&conn->in_pktns->rtb); - if (!ngtcp2_ksl_it_end(&it)) { - rtbent = ngtcp2_ksl_it_get(&it); - prev_in_pkt_num = rtbent->hd.pkt_num; - } + if (conn->in_pktns) { + it = ngtcp2_rtb_head(&conn->in_pktns->rtb); + if (!ngtcp2_ksl_it_end(&it)) { + rtbent = ngtcp2_ksl_it_get(&it); + prev_in_pkt_num = rtbent->hd.pkt_num; } } - nwrite = conn_write_handshake(conn, pi, dest, destlen, write_datalen, ts); + nwrite = conn_write_handshake(conn, pi, dest, destlen, + /* write_datalen = */ 0, ts); if (nwrite < 0) { return nwrite; } @@ -11735,7 +11958,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, dest += nwrite; destlen -= (size_t)nwrite; - if (conn->in_pktns && write_datalen > 0) { + if (conn->in_pktns && nwrite > 0) { it = ngtcp2_rtb_head(&conn->in_pktns->rtb); if (!ngtcp2_ksl_it_end(&it)) { rtbent = ngtcp2_ksl_it_get(&it); @@ -11748,12 +11971,27 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } } } - if (conn->state != NGTCP2_CS_POST_HANDSHAKE && - conn->pktns.crypto.tx.ckm == NULL) { + if (conn->pktns.crypto.tx.ckm == NULL) { return res; } break; case NGTCP2_CS_POST_HANDSHAKE: + if (!conn_pacing_pkt_tx_allowed(conn, ts)) { + assert(!ppe_pending); + + if (conn->server && + !(conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED)) { + server_tx_left = conn_server_tx_left(conn, &conn->dcid.current); + if (server_tx_left == 0) { + return 0; + } + + origlen = (size_t)ngtcp2_min((uint64_t)origlen, server_tx_left); + } + + return conn_write_ack_pkt(conn, pi, dest, origlen, NGTCP2_PKT_1RTT, ts); + } + break; case NGTCP2_CS_CLOSING: return NGTCP2_ERR_CLOSING; @@ -11788,7 +12026,6 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, if (ppe_pending) { res = conn->pkt.hs_spktlen; - conn->pkt.hs_spktlen = 0; if (conn->pkt.require_padding) { wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING; } @@ -11827,35 +12064,44 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } if (conn->pmtud && + (conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) && (!conn->hs_pktns || - ngtcp2_ksl_len(&conn->hs_pktns->crypto.tx.frq) == 0)) { + ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm))) { nwrite = conn_write_pmtud_probe(conn, pi, dest, origdestlen, ts); if (nwrite) { goto fin; } } } + } - 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_t)origlen, server_tx_left); - destlen = (size_t)ngtcp2_min((uint64_t)destlen, server_tx_left); + 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_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) { - ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, - "loss detection timer canceled due to amplification limit"); - conn->cstat.loss_detection_timer = UINT64_MAX; - } + if (server_tx_left == 0 && + conn->cstat.loss_detection_timer != UINT64_MAX) { + ngtcp2_log_info( + &conn->log, NGTCP2_LOG_EVENT_LDC, + "loss detection timer canceled due to amplification limit"); + conn->cstat.loss_detection_timer = UINT64_MAX; } } } if (res == 0) { if (conn_handshake_remnants_left(conn)) { - if (conn_handshake_probe_left(conn)) { + if (conn_handshake_probe_left(conn) || + /* Allow exceeding CWND if an Handshake packet needs to be + sent in order to avoid dead lock. In some situation, + typically for client, 1 RTT packets may occupy in-flight + bytes (e.g., some large requests and PMTUD), and + Handshake packet loss shrinks CWND, and we may get in the + situation that we are unable to send Handshake packet. */ + (conn->hs_pktns->rtb.num_pto_eliciting == 0 && + !ngtcp2_strm_streamfrq_empty(&conn->hs_pktns->crypto.strm))) { destlen = origlen; } nwrite = conn_write_handshake_pkts(conn, pi, dest, destlen, @@ -11867,6 +12113,11 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, res = nwrite; dest += nwrite; destlen -= (size_t)nwrite; + } else if (destlen == 0) { + res = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); + if (res) { + return res; + } } } } @@ -11894,16 +12145,24 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } fin: - conn->pkt.hs_spktlen = 0; - if (nwrite >= 0) { res += nwrite; return res; } - /* NGTCP2_CONN_FLAG_PPE_PENDING is set in conn_write_pkt above. - ppe_pending cannot be used here. */ - if (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) { + + switch (nwrite) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: + if (!(wflags & NGTCP2_WRITE_PKT_FLAG_MORE)) { + if (res) { + return res; + } + + break; + } + /* fall through */ + case NGTCP2_ERR_WRITE_MORE: conn->pkt.hs_spktlen = res; + break; } return nwrite; @@ -11989,9 +12248,6 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt( ngtcp2_ssize nwrite; uint64_t server_tx_left; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - if (conn_check_pkt_num_exhausted(conn)) { return NGTCP2_ERR_PKT_NUM_EXHAUSTED; } @@ -12054,9 +12310,6 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( ngtcp2_frame fr; uint64_t server_tx_left; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - if (conn_check_pkt_num_exhausted(conn)) { return NGTCP2_ERR_PKT_NUM_EXHAUSTED; } @@ -12135,11 +12388,9 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( return res; } -static void -connection_close_error_init(ngtcp2_connection_close_error *ccerr, - ngtcp2_connection_close_error_code_type type, - uint64_t error_code, const uint8_t *reason, - size_t reasonlen) { +static void ccerr_init(ngtcp2_ccerr *ccerr, ngtcp2_ccerr_type type, + uint64_t error_code, const uint8_t *reason, + size_t reasonlen) { ccerr->type = type; ccerr->error_code = error_code; ccerr->frame_type = 0; @@ -12147,72 +12398,63 @@ connection_close_error_init(ngtcp2_connection_close_error *ccerr, ccerr->reasonlen = reasonlen; } -void ngtcp2_connection_close_error_default( - ngtcp2_connection_close_error *ccerr) { - connection_close_error_init(ccerr, - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT, - NGTCP2_NO_ERROR, NULL, 0); +void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr) { + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_TRANSPORT, NGTCP2_NO_ERROR, NULL, 0); } -void ngtcp2_connection_close_error_set_transport_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen) { - connection_close_error_init(ccerr, - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT, - error_code, reason, reasonlen); +void ngtcp2_ccerr_set_transport_error(ngtcp2_ccerr *ccerr, uint64_t error_code, + const uint8_t *reason, size_t reasonlen) { + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_TRANSPORT, error_code, reason, reasonlen); } -void ngtcp2_connection_close_error_set_transport_error_liberr( - ngtcp2_connection_close_error *ccerr, int liberr, const uint8_t *reason, - size_t reasonlen) { +void ngtcp2_ccerr_set_liberr(ngtcp2_ccerr *ccerr, int liberr, + const uint8_t *reason, size_t reasonlen) { switch (liberr) { case NGTCP2_ERR_RECV_VERSION_NEGOTIATION: - connection_close_error_init( - ccerr, - NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_VERSION_NEGOTIATION, - NGTCP2_NO_ERROR, reason, reasonlen); + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION, NGTCP2_NO_ERROR, + reason, reasonlen); return; case NGTCP2_ERR_IDLE_CLOSE: - connection_close_error_init( - ccerr, NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE, - NGTCP2_NO_ERROR, reason, reasonlen); + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_IDLE_CLOSE, NGTCP2_NO_ERROR, reason, + reasonlen); return; }; - ngtcp2_connection_close_error_set_transport_error( + ngtcp2_ccerr_set_transport_error( ccerr, ngtcp2_err_infer_quic_transport_error_code(liberr), reason, reasonlen); } -void ngtcp2_connection_close_error_set_transport_error_tls_alert( - ngtcp2_connection_close_error *ccerr, uint8_t tls_alert, - const uint8_t *reason, size_t reasonlen) { - ngtcp2_connection_close_error_set_transport_error( - ccerr, NGTCP2_CRYPTO_ERROR | tls_alert, reason, reasonlen); +void ngtcp2_ccerr_set_tls_alert(ngtcp2_ccerr *ccerr, uint8_t tls_alert, + const uint8_t *reason, size_t reasonlen) { + ngtcp2_ccerr_set_transport_error(ccerr, NGTCP2_CRYPTO_ERROR | tls_alert, + reason, reasonlen); } -void ngtcp2_connection_close_error_set_application_error( - ngtcp2_connection_close_error *ccerr, uint64_t error_code, - const uint8_t *reason, size_t reasonlen) { - connection_close_error_init( - ccerr, NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION, error_code, - reason, reasonlen); +void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr, + uint64_t error_code, + const uint8_t *reason, + size_t reasonlen) { + ccerr_init(ccerr, NGTCP2_CCERR_TYPE_APPLICATION, error_code, reason, + reasonlen); } ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - const ngtcp2_connection_close_error *ccerr, ngtcp2_tstamp ts) { + const ngtcp2_ccerr *ccerr, ngtcp2_tstamp ts) { (void)pkt_info_version; + conn_update_timestamp(conn, ts); + switch (ccerr->type) { - case NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT: + case NGTCP2_CCERR_TYPE_TRANSPORT: return ngtcp2_conn_write_connection_close_pkt( conn, path, pi, dest, destlen, ccerr->error_code, ccerr->reason, ccerr->reasonlen, ts); - case NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_APPLICATION: + case NGTCP2_CCERR_TYPE_APPLICATION: return ngtcp2_conn_write_application_close_pkt( conn, path, pi, dest, destlen, ccerr->error_code, ccerr->reason, ccerr->reasonlen, ts); @@ -12221,51 +12463,46 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_versioned( } } -int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn) { +int ngtcp2_conn_in_closing_period(ngtcp2_conn *conn) { return conn->state == NGTCP2_CS_CLOSING; } -int ngtcp2_conn_is_in_draining_period(ngtcp2_conn *conn) { +int ngtcp2_conn_in_draining_period(ngtcp2_conn *conn) { return conn->state == NGTCP2_CS_DRAINING; } int ngtcp2_conn_close_stream(ngtcp2_conn *conn, ngtcp2_strm *strm) { int rv; - rv = ngtcp2_map_remove(&conn->strms, (ngtcp2_map_key_type)strm->stream_id); + rv = conn_call_stream_close(conn, strm); if (rv != 0) { - assert(rv != NGTCP2_ERR_INVALID_ARGUMENT); return rv; } - rv = conn_call_stream_close(conn, strm); + rv = ngtcp2_map_remove(&conn->strms, (ngtcp2_map_key_type)strm->stream_id); if (rv != 0) { - goto fin; + assert(rv != NGTCP2_ERR_INVALID_ARGUMENT); + return rv; } if (ngtcp2_strm_is_tx_queued(strm)) { ngtcp2_pq_remove(&conn->tx.strmq, &strm->pe); - if (!ngtcp2_strm_streamfrq_empty(strm)) { - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; - } } -fin: ngtcp2_strm_free(strm); ngtcp2_objalloc_strm_release(&conn->strm_objalloc, strm); - return rv; + return 0; } int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, ngtcp2_strm *strm) { if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RDWR) == NGTCP2_STRM_FLAG_SHUT_RDWR && - ((strm->flags & NGTCP2_STRM_FLAG_RECV_RST) || + ((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_RECVED) || ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) && - (((strm->flags & NGTCP2_STRM_FLAG_SENT_RST) && - (strm->flags & NGTCP2_STRM_FLAG_RST_ACKED)) || + (((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM) && + (strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM_ACKED)) || ngtcp2_strm_is_all_tx_data_fin_acked(strm))) { return ngtcp2_conn_close_stream(conn, strm); } @@ -12286,14 +12523,14 @@ static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { ngtcp2_strm_set_app_error_code(strm, app_error_code); - if ((strm->flags & NGTCP2_STRM_FLAG_SENT_RST) || + if ((strm->flags & NGTCP2_STRM_FLAG_RESET_STREAM) || ngtcp2_strm_is_all_tx_data_fin_acked(strm)) { return 0; } /* Set this flag so that we don't accidentally send DATA to this stream. */ - strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_SENT_RST; + strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_RESET_STREAM; ngtcp2_strm_streamfrq_clear(strm); @@ -12312,6 +12549,8 @@ static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm, */ static int conn_shutdown_stream_read(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { + ngtcp2_strm_set_app_error_code(strm, app_error_code); + if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) { return 0; } @@ -12322,44 +12561,54 @@ static int conn_shutdown_stream_read(ngtcp2_conn *conn, ngtcp2_strm *strm, /* Extend connection flow control window for the amount of data which are not passed to application. */ - if (!(strm->flags & - (NGTCP2_STRM_FLAG_STOP_SENDING | NGTCP2_STRM_FLAG_RECV_RST))) { + if (!(strm->flags & (NGTCP2_STRM_FLAG_STOP_SENDING | + NGTCP2_STRM_FLAG_RESET_STREAM_RECVED))) { ngtcp2_conn_extend_max_offset(conn, strm->rx.last_offset - ngtcp2_strm_rx_offset(strm)); } strm->flags |= NGTCP2_STRM_FLAG_STOP_SENDING; - ngtcp2_strm_set_app_error_code(strm, app_error_code); return conn_stop_sending(conn, strm, app_error_code); } -int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, int64_t stream_id, - uint64_t app_error_code) { +int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t app_error_code) { int rv; ngtcp2_strm *strm; + (void)flags; strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { return 0; } - rv = conn_shutdown_stream_read(conn, strm, app_error_code); - if (rv != 0) { - return rv; + if (bidi_stream(stream_id) || !conn_local_stream(conn, stream_id)) { + rv = conn_shutdown_stream_read(conn, strm, app_error_code); + if (rv != 0) { + return rv; + } } - rv = conn_shutdown_stream_write(conn, strm, app_error_code); - if (rv != 0) { - return rv; + if (bidi_stream(stream_id) || conn_local_stream(conn, stream_id)) { + rv = conn_shutdown_stream_write(conn, strm, app_error_code); + if (rv != 0) { + return rv; + } } return 0; } -int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, int64_t stream_id, +int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t app_error_code) { ngtcp2_strm *strm; + (void)flags; + + if (!bidi_stream(stream_id) && !conn_local_stream(conn, stream_id)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { @@ -12369,9 +12618,15 @@ int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, int64_t stream_id, return conn_shutdown_stream_write(conn, strm, app_error_code); } -int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, int64_t stream_id, +int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t app_error_code) { ngtcp2_strm *strm; + (void)flags; + + if (!bidi_stream(stream_id) && conn_local_stream(conn, stream_id)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { @@ -12421,6 +12676,10 @@ int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, uint64_t datalen) { ngtcp2_strm *strm; + if (!bidi_stream(stream_id) && conn_local_stream(conn, stream_id)) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } + strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { return 0; @@ -12469,10 +12728,6 @@ static int delete_strms_pq_each(void *data, void *ptr) { if (ngtcp2_strm_is_tx_queued(s)) { ngtcp2_pq_remove(&conn->tx.strmq, &s->pe); - if (!ngtcp2_strm_streamfrq_empty(s)) { - assert(conn->tx.strmq_nretrans); - --conn->tx.strmq_nretrans; - } } ngtcp2_strm_free(s); @@ -12494,6 +12749,7 @@ static void conn_discard_early_data_state(ngtcp2_conn *conn) { ngtcp2_map_clear(&conn->strms); conn->tx.offset = 0; + conn->tx.last_blocked_offset = UINT64_MAX; conn->rx.unsent_max_offset = conn->rx.max_offset = conn->local.transport_params.initial_max_data; @@ -12519,14 +12775,28 @@ static void conn_discard_early_data_state(ngtcp2_conn *conn) { } } -void ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn) { +int ngtcp2_conn_tls_early_data_rejected(ngtcp2_conn *conn) { if (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) { - return; + return 0; } conn->flags |= NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED; conn_discard_early_data_state(conn); + + if (conn->callbacks.tls_early_data_rejected) { + return conn->callbacks.tls_early_data_rejected(conn, conn->user_data); + } + + if (conn->early.ckm) { + conn_discard_early_key(conn); + } + + return 0; +} + +int ngtcp2_conn_get_tls_early_data_rejected(ngtcp2_conn *conn) { + return (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) != 0; } int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, @@ -12550,7 +12820,7 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, /* Ignore RTT sample if adjusting ack_delay causes the sample less than min_rtt before handshake confirmation. */ ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &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, @@ -12573,7 +12843,7 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, } ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_RCV, + &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, @@ -12584,12 +12854,19 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, return 0; } -void ngtcp2_conn_get_conn_stat_versioned(ngtcp2_conn *conn, - int conn_stat_version, - ngtcp2_conn_stat *cstat) { - (void)conn_stat_version; +void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn, + int conn_info_version, + ngtcp2_conn_info *cinfo) { + const ngtcp2_conn_stat *cstat = &conn->cstat; + (void)conn_info_version; - *cstat = conn->cstat; + cinfo->latest_rtt = cstat->latest_rtt; + cinfo->min_rtt = cstat->min_rtt; + cinfo->smoothed_rtt = cstat->smoothed_rtt; + cinfo->rttvar = cstat->rttvar; + cinfo->cwnd = cstat->cwnd; + cinfo->ssthresh = cstat->ssthresh; + cinfo->bytes_in_flight = cstat->bytes_in_flight; } static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn, @@ -12597,14 +12874,13 @@ static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn, ngtcp2_pktns **ppktns) { ngtcp2_pktns *const ns[] = {conn->hs_pktns, &conn->pktns}; ngtcp2_conn_stat *cstat = &conn->cstat; - ngtcp2_duration *loss_time = cstat->loss_time; - ngtcp2_tstamp earliest_loss_time = loss_time[NGTCP2_PKTNS_ID_INITIAL]; + ngtcp2_duration *loss_time = cstat->loss_time + 1; + ngtcp2_tstamp earliest_loss_time = cstat->loss_time[NGTCP2_PKTNS_ID_INITIAL]; ngtcp2_pktns *pktns = conn->in_pktns; size_t i; - for (i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) { - if (ns[i] == NULL || ns[i]->rtb.num_pto_eliciting == 0 || - loss_time[i] >= earliest_loss_time) { + for (i = 0; i < ngtcp2_arraylen(ns); ++i) { + if (ns[i] == NULL || loss_time[i] >= earliest_loss_time) { continue; } @@ -12672,7 +12948,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { if (earliest_loss_time != UINT64_MAX) { cstat->loss_detection_timer = earliest_loss_time; - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss_detection_timer=%" PRIu64 " nonzero crypto loss time", cstat->loss_detection_timer); return; @@ -12686,7 +12962,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED | NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) { if (cstat->loss_detection_timer != UINT64_MAX) { - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer canceled"); cstat->loss_detection_timer = UINT64_MAX; cstat->pto_count = 0; @@ -12699,7 +12975,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { timeout = cstat->loss_detection_timer > ts ? cstat->loss_detection_timer - ts : 0; - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64, cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS); } @@ -12712,9 +12988,6 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_tstamp earliest_loss_time; ngtcp2_pktns *loss_pktns = NULL; - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - switch (conn->state) { case NGTCP2_CS_CLOSING: case NGTCP2_CS_DRAINING: @@ -12731,7 +13004,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { conn_get_loss_time_and_pktns(conn, &earliest_loss_time, &loss_pktns); - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "loss detection timer fired"); if (earliest_loss_time != UINT64_MAX) { @@ -12745,7 +13018,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return 0; } - if (!conn->server && !conn_is_handshake_completed(conn)) { + if (!conn->server && !conn_is_tls_handshake_completed(conn)) { if (hs_pktns->crypto.tx.ckm) { hs_pktns->rtb.probe_pkt_left = 1; } else { @@ -12762,7 +13035,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { hs_pktns->rtb.probe_pkt_left = 1; } } else if (hs_pktns && hs_pktns->rtb.num_pto_eliciting) { - hs_pktns->rtb.probe_pkt_left = 1; + hs_pktns->rtb.probe_pkt_left = 2; } else { conn->pktns.rtb.probe_pkt_left = 2; } @@ -12770,7 +13043,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ++cstat->pto_count; - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "pto_count=%zu", + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_LDC, "pto_count=%zu", cstat->pto_count); ngtcp2_conn_set_loss_detection_timer(conn, ts); @@ -12807,27 +13080,27 @@ static int conn_buffer_crypto_data(ngtcp2_conn *conn, const uint8_t **pdata, } int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, - ngtcp2_crypto_level crypto_level, + ngtcp2_encryption_level encryption_level, const uint8_t *data, const size_t datalen) { ngtcp2_pktns *pktns; ngtcp2_frame_chain *frc; - ngtcp2_crypto *fr; + ngtcp2_stream *fr; int rv; if (datalen == 0) { return 0; } - switch (crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: + switch (encryption_level) { + case NGTCP2_ENCRYPTION_LEVEL_INITIAL: assert(conn->in_pktns); pktns = conn->in_pktns; break; - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE: assert(conn->hs_pktns); pktns = conn->hs_pktns; break; - case NGTCP2_CRYPTO_LEVEL_APPLICATION: + case NGTCP2_ENCRYPTION_LEVEL_1RTT: pktns = &conn->pktns; break; default: @@ -12844,15 +13117,18 @@ int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, return rv; } - fr = &frc->fr.crypto; + fr = &frc->fr.stream; fr->type = NGTCP2_FRAME_CRYPTO; + fr->flags = 0; + fr->fin = 0; + fr->stream_id = 0; fr->offset = pktns->crypto.tx.offset; fr->datacnt = 1; fr->data[0].len = datalen; fr->data[0].base = (uint8_t *)data; - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &fr->offset, frc); + rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc); if (rv != 0) { ngtcp2_frame_chain_objalloc_del(frc, &conn->frc_objalloc, conn->mem); return rv; @@ -12868,14 +13144,13 @@ int ngtcp2_conn_submit_new_token(ngtcp2_conn *conn, const uint8_t *token, size_t tokenlen) { int rv; ngtcp2_frame_chain *nfrc; - ngtcp2_vec tokenv = {(uint8_t *)token, tokenlen}; assert(conn->server); assert(token); assert(tokenlen); rv = ngtcp2_frame_chain_new_token_objalloc_new( - &nfrc, &tokenv, &conn->frc_objalloc, conn->mem); + &nfrc, token, tokenlen, &conn->frc_objalloc, conn->mem); if (rv != 0) { return rv; } @@ -12902,16 +13177,11 @@ 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_uncommited_preferred_address_cid(ngtcp2_conn *conn) { +static int conn_has_uncommitted_preferred_addr_cid(ngtcp2_conn *conn) { return conn->server && !(conn->flags & NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED) && conn->oscid.datalen && - conn->local.transport_params.preferred_address_present; -} - -size_t ngtcp2_conn_get_num_scid(ngtcp2_conn *conn) { - return ngtcp2_ksl_len(&conn->scid.set) + - (size_t)conn_has_uncommited_preferred_address_cid(conn); + conn->local.transport_params.preferred_addr_present; } size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest) { @@ -12919,27 +13189,28 @@ size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest) { ngtcp2_ksl_it it; ngtcp2_scid *scid; + if (dest == NULL) { + return ngtcp2_ksl_len(&conn->scid.set) + + (size_t)conn_has_uncommitted_preferred_addr_cid(conn); + } + for (it = ngtcp2_ksl_begin(&conn->scid.set); !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { scid = ngtcp2_ksl_it_get(&it); *dest++ = scid->cid; } - if (conn_has_uncommited_preferred_address_cid(conn)) { - *dest++ = conn->local.transport_params.preferred_address.cid; + if (conn_has_uncommitted_preferred_addr_cid(conn)) { + *dest++ = conn->local.transport_params.preferred_addr.cid; } return (size_t)(dest - origdest); } -size_t ngtcp2_conn_get_num_active_dcid(ngtcp2_conn *conn) { +static size_t conn_get_num_active_dcid(ngtcp2_conn *conn) { size_t n = 1; /* for conn->dcid.current */ ngtcp2_pv *pv = conn->pv; - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { - return 0; - } - if (pv) { if (pv->dcid.seq != conn->dcid.current.seq) { ++n; @@ -12973,10 +13244,14 @@ size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) { ngtcp2_dcid *dcid; size_t len, i; - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { return 0; } + if (dest == NULL) { + return conn_get_num_active_dcid(conn); + } + copy_dcid_to_cid_token(dest, &conn->dcid.current); ++dest; @@ -13019,13 +13294,13 @@ const ngtcp2_path *ngtcp2_conn_get_path(ngtcp2_conn *conn) { return &conn->dcid.current.ps.path; } -size_t ngtcp2_conn_get_max_udp_payload_size(ngtcp2_conn *conn) { - return conn->local.settings.max_udp_payload_size; +size_t ngtcp2_conn_get_max_tx_udp_payload_size(ngtcp2_conn *conn) { + return conn->local.settings.max_tx_udp_payload_size; } -size_t ngtcp2_conn_get_path_max_udp_payload_size(ngtcp2_conn *conn) { - if (conn->local.settings.no_udp_payload_size_shaping) { - return ngtcp2_conn_get_max_udp_payload_size(conn); +size_t ngtcp2_conn_get_path_max_tx_udp_payload_size(ngtcp2_conn *conn) { + if (conn->local.settings.no_tx_udp_payload_size_shaping) { + return ngtcp2_conn_get_max_tx_udp_payload_size(conn); } return conn->dcid.current.max_udp_payload_size; @@ -13056,11 +13331,11 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn, ngtcp2_tstamp ts) { int rv; ngtcp2_dcid *dcid; + ngtcp2_pv *pv; assert(!conn->server); - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + conn_update_timestamp(conn, ts); rv = conn_initiate_migration_precheck(conn, &path->local); if (rv != 0) { @@ -13087,35 +13362,33 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn, ngtcp2_dcid_copy(&conn->dcid.current, dcid); ngtcp2_ringbuf_pop_front(&conn->dcid.unused.rb); - rv = conn_call_activate_dcid(conn, &conn->dcid.current); - if (rv != 0) { - return rv; - } - conn_reset_congestion_state(conn, ts); conn_reset_ecn_validation_state(conn); - if (!conn->local.settings.no_pmtud) { - rv = conn_start_pmtud(conn); - if (rv != 0) { - return rv; - } + /* TODO It might be better to add a new flag which indicates that a + connection should be closed if this path validation failed. The + current design allows an application to continue, by migrating + into yet another path. */ + rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); + if (rv != 0) { + return rv; } - return 0; + conn->pv = pv; + + return conn_call_activate_dcid(conn, &conn->dcid.current); } int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_tstamp ts) { int rv; ngtcp2_dcid *dcid; - ngtcp2_duration pto, initial_pto, timeout; ngtcp2_pv *pv; assert(!conn->server); - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; + conn_update_timestamp(conn, ts); rv = conn_initiate_migration_precheck(conn, &path->local); if (rv != 0) { @@ -13132,12 +13405,8 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, dcid = ngtcp2_ringbuf_get(&conn->dcid.unused.rb, 0); ngtcp2_dcid_set_path(dcid, path); - pto = conn_compute_pto(conn, &conn->pktns); - initial_pto = conn_compute_initial_pto(conn, &conn->pktns); - timeout = 3 * ngtcp2_max(pto, initial_pto); - - rv = ngtcp2_pv_new(&pv, dcid, timeout, NGTCP2_PV_FLAG_NONE, &conn->log, - conn->mem); + rv = ngtcp2_pv_new(&pv, dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); if (rv != 0) { return rv; } @@ -13148,10 +13417,6 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, return conn_call_activate_dcid(conn, &pv->dcid); } -uint64_t ngtcp2_conn_get_max_local_streams_uni(ngtcp2_conn *conn) { - return conn->local.uni.max_streams; -} - uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) { return conn->tx.max_offset - conn->tx.offset; } @@ -13200,7 +13465,7 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { /* TODO Remote max_idle_timeout becomes effective after handshake completion. */ - if (!conn_is_handshake_completed(conn) || + if (!conn_is_tls_handshake_completed(conn) || conn->remote.transport_params->max_idle_timeout == 0 || (conn->local.transport_params.max_idle_timeout && conn->local.transport_params.max_idle_timeout < @@ -13214,16 +13479,23 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { return UINT64_MAX; } - trpto = 3 * conn_compute_pto(conn, conn_is_handshake_completed(conn) + trpto = 3 * conn_compute_pto(conn, conn_is_tls_handshake_completed(conn) ? &conn->pktns : conn->hs_pktns); - return conn->idle_ts + ngtcp2_max(idle_timeout, trpto); + idle_timeout = ngtcp2_max(idle_timeout, trpto); + + if (conn->idle_ts >= UINT64_MAX - idle_timeout) { + return UINT64_MAX; + } + + return conn->idle_ts + idle_timeout; } ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn) { - return conn_compute_pto( - conn, conn_is_handshake_completed(conn) ? &conn->pktns : conn->hs_pktns); + return 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, @@ -13257,12 +13529,12 @@ const ngtcp2_crypto_ctx *ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn) { return &conn->pktns.crypto.ctx; } -void ngtcp2_conn_set_early_crypto_ctx(ngtcp2_conn *conn, - const ngtcp2_crypto_ctx *ctx) { +void ngtcp2_conn_set_0rtt_crypto_ctx(ngtcp2_conn *conn, + const ngtcp2_crypto_ctx *ctx) { conn->early.ctx = *ctx; } -const ngtcp2_crypto_ctx *ngtcp2_conn_get_early_crypto_ctx(ngtcp2_conn *conn) { +const ngtcp2_crypto_ctx *ngtcp2_conn_get_0rtt_crypto_ctx(ngtcp2_conn *conn) { return &conn->early.ctx; } @@ -13275,9 +13547,8 @@ void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, conn->crypto.tls_native_handle = tls_native_handle; } -void ngtcp2_conn_get_connection_close_error( - ngtcp2_conn *conn, ngtcp2_connection_close_error *ccerr) { - *ccerr = conn->rx.ccerr; +const ngtcp2_ccerr *ngtcp2_conn_get_ccerr(ngtcp2_conn *conn) { + return &conn->rx.ccerr; } void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr) { @@ -13320,13 +13591,29 @@ int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, int64_t stream_id, } void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - if (!(conn->cstat.pacing_rate > 0) || conn->tx.pacing.pktlen == 0) { + ngtcp2_duration pacing_interval; + ngtcp2_duration wait; + + conn_update_timestamp(conn, ts); + + if (conn->tx.pacing.pktlen == 0) { return; } - conn->tx.pacing.next_ts = - ts + (ngtcp2_duration)((double)conn->tx.pacing.pktlen / - conn->cstat.pacing_rate); + if (conn->cstat.pacing_interval) { + pacing_interval = conn->cstat.pacing_interval; + } else { + /* 1.25 is the under-utilization avoidance factor described in + https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */ + pacing_interval = (conn->cstat.first_rtt_sample_ts == UINT64_MAX + ? NGTCP2_MILLISECONDS + : conn->cstat.smoothed_rtt) * + 100 / 125 / conn->cstat.cwnd; + } + + wait = (ngtcp2_duration)(conn->tx.pacing.pktlen * pacing_interval); + + conn->tx.pacing.next_ts = ts + wait; conn->tx.pacing.pktlen = 0; } @@ -13338,15 +13625,14 @@ int ngtcp2_conn_track_retired_dcid_seq(ngtcp2_conn *conn, uint64_t seq) { size_t i; if (conn->dcid.retire_unacked.len >= - sizeof(conn->dcid.retire_unacked.seqs) / - sizeof(conn->dcid.retire_unacked.seqs[0])) { + ngtcp2_arraylen(conn->dcid.retire_unacked.seqs)) { return NGTCP2_ERR_CONNECTION_ID_LIMIT; } /* Make sure that we do not have a duplicate */ for (i = 0; i < conn->dcid.retire_unacked.len; ++i) { if (conn->dcid.retire_unacked.seqs[i] == seq) { - assert(0); + ngtcp2_unreachable(); } } @@ -13399,20 +13685,35 @@ void ngtcp2_settings_default_versioned(int settings_version, settings->cc_algo = NGTCP2_CC_ALGO_CUBIC; settings->initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT; settings->ack_thresh = 2; - settings->max_udp_payload_size = 1500 - 48; - settings->handshake_timeout = NGTCP2_DEFAULT_HANDSHAKE_TIMEOUT; + settings->max_tx_udp_payload_size = 1500 - 48; + settings->handshake_timeout = UINT64_MAX; } void ngtcp2_transport_params_default_versioned( int transport_params_version, ngtcp2_transport_params *params) { - (void)transport_params_version; - - memset(params, 0, sizeof(*params)); - params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; - params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; - params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; - params->active_connection_id_limit = - NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; + size_t len; + + switch (transport_params_version) { + case NGTCP2_TRANSPORT_PARAMS_VERSION: + len = sizeof(*params); + + break; + default: + ngtcp2_unreachable(); + } + + memset(params, 0, len); + + switch (transport_params_version) { + case NGTCP2_TRANSPORT_PARAMS_VERSION: + params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; + params->active_connection_id_limit = + NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; + params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; + params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; + + break; + } } /* The functions prefixed with ngtcp2_pkt_ are usually put inside diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h index b1c6564175d482..4ed67876bc3749 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h @@ -43,7 +43,6 @@ #include "ngtcp2_pq.h" #include "ngtcp2_cc.h" #include "ngtcp2_bbr.h" -#include "ngtcp2_bbr2.h" #include "ngtcp2_pv.h" #include "ngtcp2_pmtud.h" #include "ngtcp2_cid.h" @@ -51,16 +50,15 @@ #include "ngtcp2_ppe.h" #include "ngtcp2_qlog.h" #include "ngtcp2_rst.h" +#include "ngtcp2_conn_stat.h" typedef enum { /* Client specific handshake states */ NGTCP2_CS_CLIENT_INITIAL, NGTCP2_CS_CLIENT_WAIT_HANDSHAKE, - NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED, /* Server specific handshake states */ NGTCP2_CS_SERVER_INITIAL, NGTCP2_CS_SERVER_WAIT_HANDSHAKE, - NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED, /* Shared by both client and server */ NGTCP2_CS_POST_HANDSHAKE, NGTCP2_CS_CLOSING, @@ -111,18 +109,14 @@ typedef enum { to put the sane limit.*/ #define NGTCP2_MAX_SCID_POOL_SIZE 8 -/* NGTCP2_MAX_NON_ACK_TX_PKT is the maximum number of continuous non - ACK-eliciting packets. */ -#define NGTCP2_MAX_NON_ACK_TX_PKT 3 - /* NGTCP2_ECN_MAX_NUM_VALIDATION_PKTS is the maximum number of ECN marked packets sent in NGTCP2_ECN_STATE_TESTING period. */ #define NGTCP2_ECN_MAX_NUM_VALIDATION_PKTS 10 -/* NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN is the maximum length - of reason phrase to remember. If the received reason phrase is - longer than this value, it is truncated. */ -#define NGTCP2_CONNECTION_CLOSE_ERROR_MAX_REASONLEN 1024 +/* NGTCP2_CCERR_MAX_REASONLEN is the maximum length of reason phrase + to remember. If the received reason phrase is longer than this + value, it is truncated. */ +#define NGTCP2_CCERR_MAX_REASONLEN 1024 /* NGTCP2_WRITE_PKT_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_WRITE_PKT_FLAG_NONE 0x00u @@ -142,8 +136,8 @@ typedef union ngtcp2_max_frame { ngtcp2_frame fr; struct { ngtcp2_ack ack; - /* ack includes 1 ngtcp2_ack_blk. */ - ngtcp2_ack_blk blks[NGTCP2_MAX_ACK_BLKS - 1]; + /* ack includes 1 ngtcp2_ack_range. */ + ngtcp2_ack_range ranges[NGTCP2_MAX_ACK_RANGES - 1]; } ackfr; } ngtcp2_max_frame; @@ -158,17 +152,17 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, /* NGTCP2_CONN_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_CONN_FLAG_NONE 0x00u -/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set when TLS stack declares - that TLS handshake has completed. The condition of this +/* NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED is set when TLS stack + declares that TLS handshake has completed. The condition of this declaration varies between TLS implementations and this flag does not indicate the completion of QUIC handshake. Some implementations declare TLS handshake completion as server when they write off Server Finished and before deriving application rx secret. */ -#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x01u -/* NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED is set if connection ID is - negotiated. This is only used for client. */ -#define NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED 0x02u +#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01u +/* NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED is set when the first + Initial packet has successfully been processed. */ +#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02u /* NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED is set if transport parameters are received. */ #define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04u @@ -187,9 +181,9 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, /* NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED is set when an endpoint confirmed completion of handshake. */ #define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80u -/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED is set when the - library transitions its state to "post handshake". */ -#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED 0x0100u +/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set when the library + transitions its state to "post handshake". */ +#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100u /* NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT is set when the early handshake retransmission has done when server receives overlapping Initial crypto data. */ @@ -221,23 +215,15 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, endpoint has initiated key update. */ #define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000u -typedef struct ngtcp2_crypto_data { - ngtcp2_buf buf; - /* pkt_type is the type of packet to send data in buf. If it is 0, - it must be sent in Short packet. Otherwise, it is sent the long - packet type denoted by pkt_type. */ - uint8_t pkt_type; -} ngtcp2_crypto_data; - typedef struct ngtcp2_pktns { struct { /* last_pkt_num is the packet number which the local endpoint sent last time.*/ int64_t last_pkt_num; ngtcp2_frame_chain *frq; - /* num_non_ack_pkt is the number of continuous non ACK-eliciting - packets. */ - size_t num_non_ack_pkt; + /* non_ack_pkt_start_ts is the timestamp since the local endpoint + starts sending continuous non ACK-eliciting packets. */ + ngtcp2_tstamp non_ack_pkt_start_ts; struct { /* ect0 is the number of QUIC packets, not UDP datagram, which @@ -307,8 +293,6 @@ typedef struct ngtcp2_pktns { struct { struct { - /* frq contains crypto data sorted by their offset. */ - ngtcp2_ksl frq; /* offset is the offset of crypto stream in this packet number space. */ uint64_t offset; @@ -344,6 +328,19 @@ typedef enum ngtcp2_ecn_state { NGTCP2_ECN_STATE_CAPABLE, } ngtcp2_ecn_state; +/* ngtcp2_early_transport_params is the values remembered by client + from the previous session. */ +typedef struct ngtcp2_early_transport_params { + uint64_t initial_max_streams_bidi; + uint64_t initial_max_streams_uni; + uint64_t initial_max_stream_data_bidi_local; + uint64_t initial_max_stream_data_bidi_remote; + uint64_t initial_max_stream_data_uni; + uint64_t initial_max_data; + uint64_t active_connection_id_limit; + uint64_t max_datagram_frame_size; +} ngtcp2_early_transport_params; + ngtcp2_static_ringbuf_def(dcid_bound, NGTCP2_MAX_BOUND_DCID_POOL_SIZE, sizeof(ngtcp2_dcid)); ngtcp2_static_ringbuf_def(dcid_unused, NGTCP2_MAX_DCID_POOL_SIZE, @@ -353,7 +350,7 @@ ngtcp2_static_ringbuf_def(dcid_retired, NGTCP2_MAX_DCID_RETIRED_SIZE, ngtcp2_static_ringbuf_def(path_challenge, 4, sizeof(ngtcp2_path_challenge_entry)); -ngtcp2_objalloc_def(strm, ngtcp2_strm, oplent); +ngtcp2_objalloc_decl(strm, ngtcp2_strm, oplent); struct ngtcp2_conn { ngtcp2_objalloc frc_objalloc; @@ -421,25 +418,28 @@ struct ngtcp2_conn { /* num_retired is the number of retired Connection ID still included in set. */ size_t num_retired; + /* num_in_flight is the number of NEW_CONNECTION_ID frames that + are in-flight and not acknowledged yet. */ + size_t num_in_flight; } scid; struct { /* strmq contains ngtcp2_strm which has frames to send. */ ngtcp2_pq strmq; - /* strmq_nretrans is the number of entries in strmq which has - stream data to resent. */ - size_t strmq_nretrans; /* ack is ACK frame. The underlying buffer is reused. */ ngtcp2_frame *ack; - /* max_ack_blks is the number of additional ngtcp2_ack_blk which - ack can contain. */ - size_t max_ack_blks; + /* max_ack_ranges is the number of additional ngtcp2_ack_range + which ack can contain. */ + size_t max_ack_ranges; /* offset is the offset the local endpoint has sent to the remote endpoint. */ uint64_t offset; /* max_offset is the maximum offset that local endpoint can send. */ uint64_t max_offset; + /* last_blocked_offset is the largest offset where the + transmission of stream data is blocked. */ + uint64_t last_blocked_offset; /* last_max_data_ts is the timestamp when last MAX_DATA frame is sent. */ ngtcp2_tstamp last_max_data_ts; @@ -482,7 +482,7 @@ struct ngtcp2_conn { /* path_challenge stores received PATH_CHALLENGE data. */ ngtcp2_static_ringbuf_path_challenge path_challenge; /* ccerr is the received connection close error. */ - ngtcp2_connection_close_error ccerr; + ngtcp2_ccerr ccerr; } rx; struct { @@ -497,16 +497,7 @@ struct ngtcp2_conn { ngtcp2_conn_set_early_remote_transport_params(). Server does not use this field. Server must not set values for these parameters that are smaller than the remembered values. */ - struct { - uint64_t initial_max_streams_bidi; - uint64_t initial_max_streams_uni; - uint64_t initial_max_stream_data_bidi_local; - uint64_t initial_max_stream_data_bidi_remote; - uint64_t initial_max_stream_data_uni; - uint64_t initial_max_data; - uint64_t active_connection_id_limit; - uint64_t max_datagram_frame_size; - } transport_params; + ngtcp2_early_transport_params transport_params; } early; struct { @@ -658,14 +649,14 @@ struct ngtcp2_conn { array pointed by preferred_versions. This field is only used by server. */ size_t preferred_versionslen; - /* other_versions is the versions that the local endpoint sends in - version_information transport parameter. This is the wire - image of other_versions field of version_information transport - parameter. */ - uint8_t *other_versions; - /* other_versionslen is the length of data pointed by - other_versions field. */ - size_t other_versionslen; + /* available_versions is the versions that the local endpoint + sends in version_information transport parameter. This is the + wire image of available_versions field of version_information + transport parameter. */ + uint8_t *available_versions; + /* available_versionslen is the length of data pointed by + available_versions field. */ + size_t available_versionslen; } vneg; ngtcp2_map strms; @@ -676,7 +667,12 @@ struct ngtcp2_conn { ngtcp2_qlog qlog; ngtcp2_rst rst; ngtcp2_cc_algo cc_algo; - ngtcp2_cc cc; + union { + ngtcp2_cc cc; + ngtcp2_cc_reno reno; + ngtcp2_cc_cubic cubic; + ngtcp2_cc_bbr bbr; + }; const ngtcp2_mem *mem; /* idle_ts is the time instant when idle timer started. */ ngtcp2_tstamp idle_ts; @@ -913,19 +909,6 @@ ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn); */ void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts); -/* - * ngtcp2_conn_resched_frames reschedules frames linked from |*pfrc| - * for retransmission. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -int ngtcp2_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_frame_chain **pfrc); - uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn); /** @@ -1112,4 +1095,65 @@ void ngtcp2_conn_stop_pmtud(ngtcp2_conn *conn); int ngtcp2_conn_set_remote_transport_params( ngtcp2_conn *conn, const ngtcp2_transport_params *params); +/** + * @function + * + * `ngtcp2_conn_set_0rtt_remote_transport_params` sets |params| as + * transport parameters previously received from a server. The + * parameters are used to send early data. QUIC requires that client + * application should remember transport parameters along with a + * session ticket. + * + * At least following fields should be set: + * + * - initial_max_stream_id_bidi + * - initial_max_stream_id_uni + * - initial_max_stream_data_bidi_local + * - initial_max_stream_data_bidi_remote + * - initial_max_stream_data_uni + * - initial_max_data + * - active_connection_id_limit + * - max_datagram_frame_size (if DATAGRAM extension was negotiated) + * + * The following fields are ignored: + * + * - ack_delay_exponent + * - max_ack_delay + * - initial_scid + * - original_dcid + * - preferred_address and preferred_address_present + * - retry_scid and retry_scid_present + * - stateless_reset_token and stateless_reset_token_present + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGTCP2_ERR_NOMEM` + * Out of memory. + */ +int ngtcp2_conn_set_0rtt_remote_transport_params( + ngtcp2_conn *conn, const ngtcp2_transport_params *params); + +/* + * ngtcp2_conn_create_ack_frame creates ACK frame, and assigns its + * pointer to |*pfr| if there are any received packets to acknowledge. + * If there are no packets to acknowledge, this function returns 0, + * and |*pfr| is untouched. The caller is advised to set |*pfr| to + * NULL before calling this function, and check it after this function + * returns. + * + * Call ngtcp2_acktr_commit_ack after a created ACK frame is + * successfully serialized into a packet. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory. + */ +int ngtcp2_conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr, + ngtcp2_pktns *pktns, uint8_t type, + ngtcp2_tstamp ts, ngtcp2_duration ack_delay, + uint64_t ack_delay_exponent); + #endif /* NGTCP2_CONN_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h new file mode 100644 index 00000000000000..1a93867aab3cae --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h @@ -0,0 +1,132 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 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_CONN_STAT_H +#define NGTCP2_CONN_STAT_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/** + * @struct + * + * :type:`ngtcp2_conn_stat` holds various connection statistics, and + * computed data for recovery and congestion controller. + */ +typedef struct ngtcp2_conn_stat { + /** + * :member:`latest_rtt` is the latest RTT sample which is not + * adjusted by acknowledgement delay. + */ + ngtcp2_duration latest_rtt; + /** + * :member:`min_rtt` is the minimum RTT seen so far. It is not + * adjusted by acknowledgement delay. + */ + ngtcp2_duration min_rtt; + /** + * :member:`smoothed_rtt` is the smoothed RTT. + */ + ngtcp2_duration smoothed_rtt; + /** + * :member:`rttvar` is a mean deviation of observed RTT. + */ + ngtcp2_duration rttvar; + /** + * :member:`initial_rtt` is the initial RTT which is used when no + * RTT sample is available. + */ + ngtcp2_duration initial_rtt; + /** + * :member:`first_rtt_sample_ts` is the timestamp when the first RTT + * sample is obtained. + */ + ngtcp2_tstamp first_rtt_sample_ts; + /** + * :member:`pto_count` is the count of successive PTO timer + * expiration. + */ + size_t pto_count; + /** + * :member:`loss_detection_timer` is the deadline of the current + * loss detection timer. + */ + ngtcp2_tstamp loss_detection_timer; + /** + * :member:`last_tx_pkt_ts` corresponds to + * time_of_last_ack_eliciting_packet in :rfc:`9002`. + */ + ngtcp2_tstamp last_tx_pkt_ts[NGTCP2_PKTNS_ID_MAX]; + /** + * :member:`loss_time` corresponds to loss_time in :rfc:`9002`. + */ + ngtcp2_tstamp loss_time[NGTCP2_PKTNS_ID_MAX]; + /** + * :member:`cwnd` is the size of congestion window. + */ + uint64_t cwnd; + /** + * :member:`ssthresh` is slow start threshold. + */ + uint64_t ssthresh; + /** + * :member:`congestion_recovery_start_ts` is the timestamp when + * congestion recovery started. + */ + ngtcp2_tstamp congestion_recovery_start_ts; + /** + * :member:`bytes_in_flight` is the number in bytes of all sent + * packets which have not been acknowledged. + */ + uint64_t bytes_in_flight; + /** + * :member:`max_tx_udp_payload_size` is the maximum size of UDP + * datagram payload that this endpoint transmits. It is used by + * congestion controller to compute congestion window. + */ + size_t max_tx_udp_payload_size; + /** + * :member:`delivery_rate_sec` is the current sending rate measured + * in byte per second. + */ + uint64_t delivery_rate_sec; + /** + * :member:`pacing_interval` is the inverse of pacing rate, which is + * the current packet sending rate computed by a congestion + * controller. 0 if a congestion controller does not set pacing + * interval. Even if this value is set to 0, the library paces + * packets. + */ + ngtcp2_duration pacing_interval; + /** + * :member:`send_quantum` is the maximum size of a data aggregate + * scheduled and transmitted together. + */ + size_t send_quantum; +} ngtcp2_conn_stat; + +#endif /* NGTCP2_CONN_STAT_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c index dcf72e4d0ec980..336721772b4e4c 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c @@ -30,40 +30,51 @@ #include "ngtcp2_str.h" #include "ngtcp2_pkt.h" #include "ngtcp2_net.h" +#include "ngtcp2_unreachable.h" -uint64_t ngtcp2_get_uint64(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint64(uint64_t *dest, const uint8_t *p) { uint64_t n; - memcpy(&n, p, 8); - return ngtcp2_ntohl64(n); + memcpy(&n, p, sizeof(n)); + *dest = ngtcp2_ntohl64(n); + return p + sizeof(n); } -uint64_t ngtcp2_get_uint48(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint48(uint64_t *dest, const uint8_t *p) { uint64_t n = 0; memcpy(((uint8_t *)&n) + 2, p, 6); - return ngtcp2_ntohl64(n); + *dest = ngtcp2_ntohl64(n); + return p + 6; } -uint32_t ngtcp2_get_uint32(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint32(uint32_t *dest, const uint8_t *p) { uint32_t n; - memcpy(&n, p, 4); - return ngtcp2_ntohl(n); + memcpy(&n, p, sizeof(n)); + *dest = ngtcp2_ntohl(n); + return p + sizeof(n); } -uint32_t ngtcp2_get_uint24(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint24(uint32_t *dest, const uint8_t *p) { uint32_t n = 0; memcpy(((uint8_t *)&n) + 1, p, 3); - return ngtcp2_ntohl(n); + *dest = ngtcp2_ntohl(n); + return p + 3; } -uint16_t ngtcp2_get_uint16(const uint8_t *p) { +const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p) { uint16_t n; - memcpy(&n, p, 2); - return ngtcp2_ntohs(n); + memcpy(&n, p, sizeof(n)); + *dest = ngtcp2_ntohs(n); + return p + sizeof(n); } -uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p) { +const uint8_t *ngtcp2_get_uint16be(uint16_t *dest, const uint8_t *p) { + memcpy(dest, p, sizeof(*dest)); + return p + sizeof(*dest); +} + +static uint64_t get_uvarint(size_t *plen, const uint8_t *p) { union { - char b[8]; + uint8_t n8; uint16_t n16; uint32_t n32; uint64_t n64; @@ -76,36 +87,55 @@ uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p) { return *p; case 2: memcpy(&n, p, 2); - n.b[0] &= 0x3f; + n.n8 &= 0x3f; return ngtcp2_ntohs(n.n16); case 4: memcpy(&n, p, 4); - n.b[0] &= 0x3f; + n.n8 &= 0x3f; return ngtcp2_ntohl(n.n32); case 8: memcpy(&n, p, 8); - n.b[0] &= 0x3f; + n.n8 &= 0x3f; return ngtcp2_ntohl64(n.n64); default: - assert(0); + ngtcp2_unreachable(); } +} + +const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p) { + size_t len; - return 0; + *dest = get_uvarint(&len, p); + + return p + len; +} + +const uint8_t *ngtcp2_get_varint(int64_t *dest, const uint8_t *p) { + size_t len; + + *dest = (int64_t)get_uvarint(&len, p); + + return p + len; } int64_t ngtcp2_get_pkt_num(const uint8_t *p, size_t pkt_numlen) { + uint32_t l; + uint16_t s; + switch (pkt_numlen) { case 1: return *p; case 2: - return (int64_t)ngtcp2_get_uint16(p); + ngtcp2_get_uint16(&s, p); + return (int64_t)s; case 3: - return (int64_t)ngtcp2_get_uint24(p); + ngtcp2_get_uint24(&l, p); + return (int64_t)l; case 4: - return (int64_t)ngtcp2_get_uint32(p); + ngtcp2_get_uint32(&l, p); + return (int64_t)l; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } @@ -134,7 +164,11 @@ uint8_t *ngtcp2_put_uint16be(uint8_t *p, uint16_t n) { return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n)); } -uint8_t *ngtcp2_put_varint(uint8_t *p, uint64_t n) { +uint8_t *ngtcp2_put_uint16(uint8_t *p, uint16_t n) { + return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n)); +} + +uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n) { uint8_t *rv; if (n < 64) { *p++ = (uint8_t)n; @@ -156,7 +190,7 @@ uint8_t *ngtcp2_put_varint(uint8_t *p, uint64_t n) { return rv; } -uint8_t *ngtcp2_put_varint30(uint8_t *p, uint32_t n) { +uint8_t *ngtcp2_put_uvarint30(uint8_t *p, uint32_t n) { uint8_t *rv; assert(n < 1073741824); @@ -182,16 +216,15 @@ uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len) { ngtcp2_put_uint32be(p, (uint32_t)pkt_num); return p + 4; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } -size_t ngtcp2_get_varint_len(const uint8_t *p) { +size_t ngtcp2_get_uvarintlen(const uint8_t *p) { return (size_t)(1u << (*p >> 6)); } -size_t ngtcp2_put_varint_len(uint64_t n) { +size_t ngtcp2_put_uvarintlen(uint64_t n) { if (n < 64) { return 1; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h index 99746fdb4cefb7..ef089a971a37f1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h @@ -33,45 +33,61 @@ /* * ngtcp2_get_uint64 reads 8 bytes from |p| as 64 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 8. */ -uint64_t ngtcp2_get_uint64(const uint8_t *p); +const uint8_t *ngtcp2_get_uint64(uint64_t *dest, const uint8_t *p); /* * ngtcp2_get_uint48 reads 6 bytes from |p| as 48 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 6. */ -uint64_t ngtcp2_get_uint48(const uint8_t *p); +const uint8_t *ngtcp2_get_uint48(uint64_t *dest, const uint8_t *p); /* * ngtcp2_get_uint32 reads 4 bytes from |p| as 32 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 4. */ -uint32_t ngtcp2_get_uint32(const uint8_t *p); +const uint8_t *ngtcp2_get_uint32(uint32_t *dest, const uint8_t *p); /* * ngtcp2_get_uint24 reads 3 bytes from |p| as 24 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 3. */ -uint32_t ngtcp2_get_uint24(const uint8_t *p); +const uint8_t *ngtcp2_get_uint24(uint32_t *dest, const uint8_t *p); /* * ngtcp2_get_uint16 reads 2 bytes from |p| as 16 bits unsigned - * integer encoded as network byte order, and returns it in host byte - * order. + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| in host byte order. It returns |p| + 2. */ -uint16_t ngtcp2_get_uint16(const uint8_t *p); +const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p); /* - * ngtcp2_get_varint reads variable-length integer from |p|, and - * returns it in host byte order. The number of bytes read is stored - * in |*plen|. + * ngtcp2_get_uint16be reads 2 bytes from |p| as 16 bits unsigned + * integer encoded as network byte order, and stores it in the buffer + * pointed by |dest| as is. It returns |p| + 2. */ -uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p); +const uint8_t *ngtcp2_get_uint16be(uint16_t *dest, const uint8_t *p); + +/* + * ngtcp2_get_uvarint reads variable-length unsigned integer from |p|, + * and stores it in the buffer pointed by |dest| in host byte order. + * It returns |p| plus the number of bytes read from |p|. + */ +const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p); + +/* + * ngtcp2_get_varint reads variable-length unsigned integer from |p|, + * and casts it to the signed integer, and stores it in the buffer + * pointed by |dest| in host byte order. No information should be + * 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); /* * ngtcp2_get_pkt_num reads encoded packet number from |p|. The @@ -115,18 +131,24 @@ uint8_t *ngtcp2_put_uint24be(uint8_t *p, uint32_t n); uint8_t *ngtcp2_put_uint16be(uint8_t *p, uint16_t n); /* - * ngtcp2_put_varint writes |n| in |p| using variable-length integer + * ngtcp2_put_uint16 writes |n| as is in |p|. It returns the one + * beyond of the last written position. + */ +uint8_t *ngtcp2_put_uint16(uint8_t *p, uint16_t n); + +/* + * ngtcp2_put_uvarint writes |n| in |p| using variable-length integer * encoding. It returns the one beyond of the last written position. */ -uint8_t *ngtcp2_put_varint(uint8_t *p, uint64_t n); +uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n); /* - * ngtcp2_put_varint30 writes |n| in |p| using variable-length integer - * encoding. |n| must be strictly less than 1073741824. The function - * always encodes |n| in 4 bytes. It returns the one beyond of the - * last written position. + * ngtcp2_put_uvarint30 writes |n| in |p| using variable-length + * integer encoding. |n| must be strictly less than 1073741824. The + * function always encodes |n| in 4 bytes. It returns the one beyond + * of the last written position. */ -uint8_t *ngtcp2_put_varint30(uint8_t *p, uint32_t n); +uint8_t *ngtcp2_put_uvarint30(uint8_t *p, uint32_t n); /* * ngtcp2_put_pkt_num encodes |pkt_num| using |len| bytes. It @@ -135,16 +157,16 @@ uint8_t *ngtcp2_put_varint30(uint8_t *p, uint32_t n); uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len); /* - * ngtcp2_get_varint_len returns the required number of bytes to read + * ngtcp2_get_uvarintlen returns the required number of bytes to read * variable-length integer starting at |p|. */ -size_t ngtcp2_get_varint_len(const uint8_t *p); +size_t ngtcp2_get_uvarintlen(const uint8_t *p); /* - * ngtcp2_put_varint_len returns the required number of bytes to + * ngtcp2_put_uvarintlen returns the required number of bytes to * encode |n|. */ -size_t ngtcp2_put_varint_len(uint64_t n); +size_t ngtcp2_put_uvarintlen(uint64_t n); /* * ngtcp2_nth_server_bidi_id returns |n|-th server bidirectional diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c new file mode 100644 index 00000000000000..eb85687a068449 --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.c @@ -0,0 +1,66 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 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_conversion.h" + +#include +#include + +static void transport_params_copy(int transport_params_version, + ngtcp2_transport_params *dest, + const ngtcp2_transport_params *src) { + assert(transport_params_version != NGTCP2_TRANSPORT_PARAMS_VERSION); + + switch (transport_params_version) { + case NGTCP2_TRANSPORT_PARAMS_V1: + memcpy(dest, src, + offsetof(ngtcp2_transport_params, version_info_present) + + sizeof(src->version_info_present)); + + break; + } +} + +const ngtcp2_transport_params * +ngtcp2_transport_params_convert_to_latest(ngtcp2_transport_params *dest, + int transport_params_version, + const ngtcp2_transport_params *src) { + if (transport_params_version == NGTCP2_TRANSPORT_PARAMS_VERSION) { + return src; + } + + ngtcp2_transport_params_default(dest); + + transport_params_copy(transport_params_version, dest, src); + + return dest; +} + +void ngtcp2_transport_params_convert_to_old( + int transport_params_version, ngtcp2_transport_params *dest, + const ngtcp2_transport_params *src) { + assert(transport_params_version != NGTCP2_TRANSPORT_PARAMS_VERSION); + + transport_params_copy(transport_params_version, dest, src); +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h new file mode 100644 index 00000000000000..3457a8f2053aba --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conversion.h @@ -0,0 +1,71 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 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_CONVERSION_H +#define NGTCP2_CONVERSION_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/* + * ngtcp2_transport_params_convert_to_latest converts |src| of version + * |transport_params_version| to the latest version + * NGTCP2_TRANSPORT_PARAMS_VERSION. + * + * |dest| must point to the latest version. |src| may be the older + * version, and if so, it may have fewer fields. Accessing those + * fields causes undefined behavior. + * + * If |transport_params_version| == NGTCP2_TRANSPORT_PARAMS_VERSION, + * no conversion is made, and |src| is returned. Otherwise, first + * |dest| is initialized via ngtcp2_transport_params_default, and then + * all valid fields in |src| are copied into |dest|. Finally, |dest| + * is returned. + */ +const ngtcp2_transport_params * +ngtcp2_transport_params_convert_to_latest(ngtcp2_transport_params *dest, + int transport_params_version, + const ngtcp2_transport_params *src); + +/* + * ngtcp2_transport_params_convert_to_old converts |src| of the latest + * version to |dest| of version |transport_params_version|. + * + * |transport_params_version| must not be the latest version + * NGTCP2_TRANSPORT_PARAMS_VERSION. + * + * |dest| points to the older version, and it may have fewer fields. + * Accessing those fields causes undefined behavior. + * + * This function copies all valid fields in version + * |transport_params_version| from |src| to |dest|. + */ +void ngtcp2_transport_params_convert_to_old(int transport_params_version, + ngtcp2_transport_params *dest, + const ngtcp2_transport_params *src); + +#endif /* NGTCP2_CONVERSION_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c index f7592f885b4cb2..2c00af5ea53d99 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c @@ -31,6 +31,7 @@ #include "ngtcp2_conv.h" #include "ngtcp2_conn.h" #include "ngtcp2_net.h" +#include "ngtcp2_conversion.h" int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret, size_t secretlen, @@ -107,8 +108,8 @@ void ngtcp2_crypto_create_nonce(uint8_t *dest, const uint8_t *iv, size_t ivlen, * which has variable integer in its parameter. */ static size_t varint_paramlen(ngtcp2_transport_param_id id, uint64_t param) { - size_t valuelen = ngtcp2_put_varint_len(param); - return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(valuelen) + valuelen; + size_t valuelen = ngtcp2_put_uvarintlen(param); + return ngtcp2_put_uvarintlen(id) + ngtcp2_put_uvarintlen(valuelen) + valuelen; } /* @@ -117,9 +118,9 @@ static size_t varint_paramlen(ngtcp2_transport_param_id id, uint64_t param) { */ static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id, uint64_t value) { - p = ngtcp2_put_varint(p, id); - p = ngtcp2_put_varint(p, ngtcp2_put_varint_len(value)); - return ngtcp2_put_varint(p, value); + p = ngtcp2_put_uvarint(p, id); + p = ngtcp2_put_uvarint(p, ngtcp2_put_uvarintlen(value)); + return ngtcp2_put_uvarint(p, value); } /* @@ -128,7 +129,7 @@ static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id, */ static size_t cid_paramlen(ngtcp2_transport_param_id id, const ngtcp2_cid *cid) { - return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(cid->datalen) + + return ngtcp2_put_uvarintlen(id) + ngtcp2_put_uvarintlen(cid->datalen) + cid->datalen; } @@ -141,8 +142,8 @@ static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id, assert(cid->datalen == 0 || cid->datalen >= NGTCP2_MIN_CIDLEN); assert(cid->datalen <= NGTCP2_MAX_CIDLEN); - p = ngtcp2_put_varint(p, id); - p = ngtcp2_put_varint(p, cid->datalen); + p = ngtcp2_put_uvarint(p, id); + p = ngtcp2_put_uvarint(p, cid->datalen); if (cid->datalen) { p = ngtcp2_cpymem(p, cid->data, cid->datalen); } @@ -151,52 +152,52 @@ static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id, static const uint8_t empty_address[16]; -ngtcp2_ssize ngtcp2_encode_transport_params_versioned( - uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype, - int transport_params_version, const ngtcp2_transport_params *params) { +ngtcp2_ssize ngtcp2_transport_params_encode_versioned( + uint8_t *dest, size_t destlen, int transport_params_version, + const ngtcp2_transport_params *params) { uint8_t *p; size_t len = 0; /* For some reason, gcc 7.3.0 requires this initialization. */ size_t preferred_addrlen = 0; size_t version_infolen = 0; - (void)transport_params_version; + const ngtcp2_sockaddr_in *sa_in; + const ngtcp2_sockaddr_in6 *sa_in6; + ngtcp2_transport_params paramsbuf; - switch (exttype) { - case NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO: - break; - case NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS: + params = ngtcp2_transport_params_convert_to_latest( + ¶msbuf, transport_params_version, params); + + if (params->original_dcid_present) { len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID, ¶ms->original_dcid); + } - if (params->stateless_reset_token_present) { - len += - ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) + - ngtcp2_put_varint_len(NGTCP2_STATELESS_RESET_TOKENLEN) + - NGTCP2_STATELESS_RESET_TOKENLEN; - } - if (params->preferred_address_present) { - assert(params->preferred_address.cid.datalen >= NGTCP2_MIN_CIDLEN); - assert(params->preferred_address.cid.datalen <= NGTCP2_MAX_CIDLEN); - preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ + - 16 /* ipv6Address */ + 2 /* ipv6Port */ - + 1 + - params->preferred_address.cid.datalen /* CID */ + - NGTCP2_STATELESS_RESET_TOKENLEN; - len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) + - ngtcp2_put_varint_len(preferred_addrlen) + preferred_addrlen; - } - if (params->retry_scid_present) { - len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, - ¶ms->retry_scid); - } - break; - default: - return NGTCP2_ERR_INVALID_ARGUMENT; + if (params->stateless_reset_token_present) { + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) + + ngtcp2_put_uvarintlen(NGTCP2_STATELESS_RESET_TOKENLEN) + + NGTCP2_STATELESS_RESET_TOKENLEN; + } + + if (params->preferred_addr_present) { + assert(params->preferred_addr.cid.datalen >= NGTCP2_MIN_CIDLEN); + assert(params->preferred_addr.cid.datalen <= NGTCP2_MAX_CIDLEN); + preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ + + 16 /* ipv6Address */ + 2 /* ipv6Port */ + + 1 + params->preferred_addr.cid.datalen /* CID */ + + NGTCP2_STATELESS_RESET_TOKENLEN; + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) + + ngtcp2_put_uvarintlen(preferred_addrlen) + preferred_addrlen; + } + if (params->retry_scid_present) { + len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, + ¶ms->retry_scid); } - len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, - ¶ms->initial_scid); + if (params->initial_scid_present) { + len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, + ¶ms->initial_scid); + } if (params->initial_max_stream_data_bidi_local) { len += varint_paramlen( @@ -235,8 +236,8 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( } if (params->disable_active_migration) { len += - ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) + - ngtcp2_put_varint_len(0); + ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) + + ngtcp2_put_uvarintlen(0); } if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) { len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY, @@ -257,14 +258,14 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( params->max_datagram_frame_size); } if (params->grease_quic_bit) { - len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT) + - ngtcp2_put_varint_len(0); + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT) + + ngtcp2_put_uvarintlen(0); } if (params->version_info_present) { - version_infolen = sizeof(uint32_t) + params->version_info.other_versionslen; - len += ngtcp2_put_varint_len( - NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT) + - ngtcp2_put_varint_len(version_infolen) + version_infolen; + version_infolen = + sizeof(uint32_t) + params->version_info.available_versionslen; + len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION) + + ngtcp2_put_uvarintlen(version_infolen) + version_infolen; } if (dest == NULL && destlen == 0) { @@ -277,58 +278,59 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( p = dest; - if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { + if (params->original_dcid_present) { p = write_cid_param( p, NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID, ¶ms->original_dcid); + } + + if (params->stateless_reset_token_present) { + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN); + p = ngtcp2_put_uvarint(p, sizeof(params->stateless_reset_token)); + p = ngtcp2_cpymem(p, params->stateless_reset_token, + sizeof(params->stateless_reset_token)); + } - if (params->stateless_reset_token_present) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN); - p = ngtcp2_put_varint(p, sizeof(params->stateless_reset_token)); - p = ngtcp2_cpymem(p, params->stateless_reset_token, - sizeof(params->stateless_reset_token)); + if (params->preferred_addr_present) { + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS); + p = ngtcp2_put_uvarint(p, preferred_addrlen); + + if (params->preferred_addr.ipv4_present) { + sa_in = ¶ms->preferred_addr.ipv4; + p = ngtcp2_cpymem(p, &sa_in->sin_addr, sizeof(sa_in->sin_addr)); + p = ngtcp2_put_uint16(p, sa_in->sin_port); + } else { + p = ngtcp2_cpymem(p, empty_address, sizeof(sa_in->sin_addr)); + p = ngtcp2_put_uint16(p, 0); } - if (params->preferred_address_present) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS); - p = ngtcp2_put_varint(p, preferred_addrlen); - - if (params->preferred_address.ipv4_present) { - p = ngtcp2_cpymem(p, params->preferred_address.ipv4_addr, - sizeof(params->preferred_address.ipv4_addr)); - p = ngtcp2_put_uint16be(p, params->preferred_address.ipv4_port); - } else { - p = ngtcp2_cpymem(p, empty_address, - sizeof(params->preferred_address.ipv4_addr)); - p = ngtcp2_put_uint16be(p, 0); - } - - if (params->preferred_address.ipv6_present) { - p = ngtcp2_cpymem(p, params->preferred_address.ipv6_addr, - sizeof(params->preferred_address.ipv6_addr)); - p = ngtcp2_put_uint16be(p, params->preferred_address.ipv6_port); - } else { - p = ngtcp2_cpymem(p, empty_address, - sizeof(params->preferred_address.ipv6_addr)); - p = ngtcp2_put_uint16be(p, 0); - } - - *p++ = (uint8_t)params->preferred_address.cid.datalen; - if (params->preferred_address.cid.datalen) { - p = ngtcp2_cpymem(p, params->preferred_address.cid.data, - params->preferred_address.cid.datalen); - } - p = ngtcp2_cpymem( - p, params->preferred_address.stateless_reset_token, - sizeof(params->preferred_address.stateless_reset_token)); + + if (params->preferred_addr.ipv6_present) { + sa_in6 = ¶ms->preferred_addr.ipv6; + p = ngtcp2_cpymem(p, &sa_in6->sin6_addr, sizeof(sa_in6->sin6_addr)); + p = ngtcp2_put_uint16(p, sa_in6->sin6_port); + } else { + p = ngtcp2_cpymem(p, empty_address, sizeof(sa_in6->sin6_addr)); + p = ngtcp2_put_uint16(p, 0); } - if (params->retry_scid_present) { - p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, - ¶ms->retry_scid); + + *p++ = (uint8_t)params->preferred_addr.cid.datalen; + if (params->preferred_addr.cid.datalen) { + p = ngtcp2_cpymem(p, params->preferred_addr.cid.data, + params->preferred_addr.cid.datalen); } + p = ngtcp2_cpymem(p, params->preferred_addr.stateless_reset_token, + sizeof(params->preferred_addr.stateless_reset_token)); } - p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, - ¶ms->initial_scid); + if (params->retry_scid_present) { + p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, + ¶ms->retry_scid); + } + + if (params->initial_scid_present) { + p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, + ¶ms->initial_scid); + } if (params->initial_max_stream_data_bidi_local) { p = write_varint_param( @@ -375,8 +377,8 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( } if (params->disable_active_migration) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION); - p = ngtcp2_put_varint(p, 0); + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION); + p = ngtcp2_put_uvarint(p, 0); } if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) { @@ -402,17 +404,17 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( } if (params->grease_quic_bit) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT); - p = ngtcp2_put_varint(p, 0); + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT); + p = ngtcp2_put_uvarint(p, 0); } if (params->version_info_present) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT); - p = ngtcp2_put_varint(p, version_infolen); + p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION); + p = ngtcp2_put_uvarint(p, version_infolen); p = ngtcp2_put_uint32be(p, params->version_info.chosen_version); - if (params->version_info.other_versionslen) { - p = ngtcp2_cpymem(p, params->version_info.other_versions, - params->version_info.other_versionslen); + if (params->version_info.available_versionslen) { + p = ngtcp2_cpymem(p, params->version_info.available_versions, + params->version_info.available_versionslen); } } @@ -423,49 +425,46 @@ ngtcp2_ssize ngtcp2_encode_transport_params_versioned( /* * decode_varint decodes a single varint from the buffer pointed by - * |p| of length |end - p|. If it decodes an integer successfully, it - * stores the integer in |*pdest| and returns 0. Otherwise it returns - * -1. + * |*pp| of length |end - *pp|. If it decodes an integer + * successfully, it stores the integer in |*pdest|, increment |*pp| by + * the number of bytes read from |*pp|, and returns 0. Otherwise it + * returns -1. */ -static ngtcp2_ssize decode_varint(uint64_t *pdest, const uint8_t *p, - const uint8_t *end) { +static int decode_varint(uint64_t *pdest, const uint8_t **pp, + const uint8_t *end) { + const uint8_t *p = *pp; size_t len; if (p == end) { return -1; } - len = ngtcp2_get_varint_len(p); + len = ngtcp2_get_uvarintlen(p); if ((uint64_t)(end - p) < len) { return -1; } - *pdest = ngtcp2_get_varint(&len, p); + *pp = ngtcp2_get_uvarint(pdest, p); - return (ngtcp2_ssize)len; + return 0; } /* * decode_varint_param decodes length prefixed value from the buffer - * pointed by |p| of length |end - p|. The length and value are + * pointed by |*pp| of length |end - *pp|. The length and value are * encoded in varint form. If it decodes a value successfully, it - * stores the value in |*pdest| and returns 0. Otherwise it returns - * -1. + * stores the value in |*pdest|, increment |*pp| by the number of + * bytes read from |*pp|, and returns 0. Otherwise it returns -1. */ -static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p, - const uint8_t *end) { - const uint8_t *begin = p; - ngtcp2_ssize nread; +static int decode_varint_param(uint64_t *pdest, const uint8_t **pp, + const uint8_t *end) { + const uint8_t *p = *pp; uint64_t valuelen; - size_t n; - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + if (decode_varint(&valuelen, &p, end) != 0) { return -1; } - p += nread; - if (p == end) { return -1; } @@ -474,36 +473,35 @@ static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p, return -1; } - if (ngtcp2_get_varint_len(p) != valuelen) { + if (ngtcp2_get_uvarintlen(p) != valuelen) { return -1; } - *pdest = ngtcp2_get_varint(&n, p); + *pp = ngtcp2_get_uvarint(pdest, p); - p += valuelen; - - return (ngtcp2_ssize)(p - begin); + return 0; } /* * decode_cid_param decodes length prefixed ngtcp2_cid from the buffer - * pointed by |p| of length |end - p|. The length is encoded in + * pointed by |*pp| of length |end - *pp|. The length is encoded in * varint form. If it decodes a value successfully, it stores the - * value in |*pdest| and returns the number of bytes read. Otherwise - * it returns -1. + * value in |*pdest|, increment |*pp| by the number of read from + * |*pp|, and returns the number of bytes read. Otherwise it returns + * the one of the negative error code: + * + * NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM + * Could not decode Connection ID. */ -static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p, - const uint8_t *end) { - const uint8_t *begin = p; +static int decode_cid_param(ngtcp2_cid *pdest, const uint8_t **pp, + const uint8_t *end) { + const uint8_t *p = *pp; uint64_t valuelen; - ngtcp2_ssize nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; - if ((valuelen != 0 && valuelen < NGTCP2_MIN_CIDLEN) || valuelen > NGTCP2_MAX_CIDLEN || (size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; @@ -513,28 +511,35 @@ static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p, p += valuelen; - return (ngtcp2_ssize)(p - begin); + *pp = p; + + return 0; } -int ngtcp2_decode_transport_params_versioned( - int transport_params_version, ngtcp2_transport_params *params, - ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen) { - const uint8_t *p, *end; +int ngtcp2_transport_params_decode_versioned(int transport_params_version, + ngtcp2_transport_params *dest, + const uint8_t *data, + size_t datalen) { + const uint8_t *p, *end, *lend; size_t len; uint64_t param_type; uint64_t valuelen; - ngtcp2_ssize nread; - int initial_scid_present = 0; - int original_dcid_present = 0; - size_t i; - (void)transport_params_version; + int rv; + ngtcp2_sockaddr_in *sa_in; + ngtcp2_sockaddr_in6 *sa_in6; + uint32_t version; + ngtcp2_transport_params *params, paramsbuf; - if (datalen == 0) { - return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + if (transport_params_version == NGTCP2_TRANSPORT_PARAMS_VERSION) { + params = dest; + } else { + params = ¶msbuf; } /* Set default values */ memset(params, 0, sizeof(*params)); + params->original_dcid_present = 0; + params->initial_scid_present = 0; params->initial_max_streams_bidi = 0; params->initial_max_streams_uni = 0; params->initial_max_stream_data_bidi_local = 0; @@ -543,7 +548,7 @@ int ngtcp2_decode_transport_params_versioned( params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE; params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; params->stateless_reset_token_present = 0; - params->preferred_address_present = 0; + params->preferred_addr_present = 0; params->disable_active_migration = 0; params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; params->max_idle_timeout = 0; @@ -560,87 +565,66 @@ int ngtcp2_decode_transport_params_versioned( end = data + datalen; for (; (size_t)(end - p) >= 2;) { - nread = decode_varint(¶m_type, p, end); - if (nread < 0) { + if (decode_varint(¶m_type, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; switch (param_type) { case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL: - nread = decode_varint_param(¶ms->initial_max_stream_data_bidi_local, - p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_stream_data_bidi_local, &p, + end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE: - nread = decode_varint_param(¶ms->initial_max_stream_data_bidi_remote, - p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_stream_data_bidi_remote, &p, + end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI: - nread = decode_varint_param(¶ms->initial_max_stream_data_uni, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_stream_data_uni, &p, end) != + 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA: - nread = decode_varint_param(¶ms->initial_max_data, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_data, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI: - nread = decode_varint_param(¶ms->initial_max_streams_bidi, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_streams_bidi, &p, end) != + 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } if (params->initial_max_streams_bidi > NGTCP2_MAX_STREAMS) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI: - nread = decode_varint_param(¶ms->initial_max_streams_uni, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->initial_max_streams_uni, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } if (params->initial_max_streams_uni > NGTCP2_MAX_STREAMS) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT: - nread = decode_varint_param(¶ms->max_idle_timeout, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->max_idle_timeout, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } params->max_idle_timeout *= NGTCP2_MILLISECONDS; - p += nread; break; case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE: - nread = decode_varint_param(¶ms->max_udp_payload_size, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->max_udp_payload_size, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; - } - p += nread; if ((size_t)valuelen != sizeof(params->stateless_reset_token)) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } @@ -648,28 +632,23 @@ int ngtcp2_decode_transport_params_versioned( return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - memcpy(params->stateless_reset_token, p, - sizeof(params->stateless_reset_token)); + p = ngtcp2_get_bytes(params->stateless_reset_token, p, + sizeof(params->stateless_reset_token)); params->stateless_reset_token_present = 1; - p += sizeof(params->stateless_reset_token); break; case NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT: - nread = decode_varint_param(¶ms->ack_delay_exponent, p, end); - if (nread < 0 || params->ack_delay_exponent > 20) { + if (decode_varint_param(¶ms->ack_delay_exponent, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; - break; - case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { + if (params->ack_delay_exponent > 20) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + break; + case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS: + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; if ((size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } @@ -680,143 +659,128 @@ int ngtcp2_decode_transport_params_versioned( return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - memcpy(params->preferred_address.ipv4_addr, p, - sizeof(params->preferred_address.ipv4_addr)); - p += sizeof(params->preferred_address.ipv4_addr); - params->preferred_address.ipv4_port = ngtcp2_get_uint16(p); - p += sizeof(uint16_t); + sa_in = ¶ms->preferred_addr.ipv4; - if (params->preferred_address.ipv4_port || - memcmp(empty_address, params->preferred_address.ipv4_addr, - sizeof(params->preferred_address.ipv4_addr)) != 0) { - params->preferred_address.ipv4_present = 1; + p = ngtcp2_get_bytes(&sa_in->sin_addr, p, sizeof(sa_in->sin_addr)); + p = ngtcp2_get_uint16be(&sa_in->sin_port, p); + + if (sa_in->sin_port || memcmp(empty_address, &sa_in->sin_addr, + sizeof(sa_in->sin_addr)) != 0) { + sa_in->sin_family = NGTCP2_AF_INET; + params->preferred_addr.ipv4_present = 1; } - memcpy(params->preferred_address.ipv6_addr, p, - sizeof(params->preferred_address.ipv6_addr)); - p += sizeof(params->preferred_address.ipv6_addr); - params->preferred_address.ipv6_port = ngtcp2_get_uint16(p); - p += sizeof(uint16_t); + sa_in6 = ¶ms->preferred_addr.ipv6; + + p = ngtcp2_get_bytes(&sa_in6->sin6_addr, p, sizeof(sa_in6->sin6_addr)); + p = ngtcp2_get_uint16be(&sa_in6->sin6_port, p); - if (params->preferred_address.ipv6_port || - memcmp(empty_address, params->preferred_address.ipv6_addr, - sizeof(params->preferred_address.ipv6_addr)) != 0) { - params->preferred_address.ipv6_present = 1; + if (sa_in6->sin6_port || memcmp(empty_address, &sa_in6->sin6_addr, + sizeof(sa_in6->sin6_addr)) != 0) { + sa_in6->sin6_family = NGTCP2_AF_INET6; + params->preferred_addr.ipv6_present = 1; } /* cid */ - params->preferred_address.cid.datalen = *p++; - len += params->preferred_address.cid.datalen; + params->preferred_addr.cid.datalen = *p++; + len += params->preferred_addr.cid.datalen; if (valuelen != len || - params->preferred_address.cid.datalen > NGTCP2_MAX_CIDLEN || - params->preferred_address.cid.datalen < NGTCP2_MIN_CIDLEN) { + params->preferred_addr.cid.datalen > NGTCP2_MAX_CIDLEN || + params->preferred_addr.cid.datalen < NGTCP2_MIN_CIDLEN) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - if (params->preferred_address.cid.datalen) { - memcpy(params->preferred_address.cid.data, p, - params->preferred_address.cid.datalen); - p += params->preferred_address.cid.datalen; + if (params->preferred_addr.cid.datalen) { + p = ngtcp2_get_bytes(params->preferred_addr.cid.data, p, + params->preferred_addr.cid.datalen); } /* stateless reset token */ - memcpy(params->preferred_address.stateless_reset_token, p, - sizeof(params->preferred_address.stateless_reset_token)); - p += sizeof(params->preferred_address.stateless_reset_token); - params->preferred_address_present = 1; + p = ngtcp2_get_bytes( + params->preferred_addr.stateless_reset_token, p, + sizeof(params->preferred_addr.stateless_reset_token)); + params->preferred_addr_present = 1; break; case NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION: - nread = decode_varint(&valuelen, p, end); - if (nread < 0 || valuelen != 0) { + if (decode_varint(&valuelen, &p, end) != 0) { + return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; + } + if (valuelen != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; params->disable_active_migration = 1; break; case NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; - } - nread = decode_cid_param(¶ms->original_dcid, p, end); - if (nread < 0) { - return (int)nread; + rv = decode_cid_param(¶ms->original_dcid, &p, end); + if (rv != 0) { + return rv; } - original_dcid_present = 1; - p += nread; + params->original_dcid_present = 1; break; case NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID: - if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; - } - nread = decode_cid_param(¶ms->retry_scid, p, end); - if (nread < 0) { - return (int)nread; + rv = decode_cid_param(¶ms->retry_scid, &p, end); + if (rv != 0) { + return rv; } params->retry_scid_present = 1; - p += nread; break; case NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID: - nread = decode_cid_param(¶ms->initial_scid, p, end); - if (nread < 0) { - return (int)nread; + rv = decode_cid_param(¶ms->initial_scid, &p, end); + if (rv != 0) { + return rv; } - initial_scid_present = 1; - p += nread; + params->initial_scid_present = 1; break; case NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY: - nread = decode_varint_param(¶ms->max_ack_delay, p, end); - if (nread < 0 || params->max_ack_delay >= 16384) { + if (decode_varint_param(¶ms->max_ack_delay, &p, end) != 0) { + return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; + } + if (params->max_ack_delay >= 16384) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } params->max_ack_delay *= NGTCP2_MILLISECONDS; - p += nread; break; case NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT: - nread = decode_varint_param(¶ms->active_connection_id_limit, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->active_connection_id_limit, &p, end) != + 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE: - nread = decode_varint_param(¶ms->max_datagram_frame_size, p, end); - if (nread < 0) { + if (decode_varint_param(¶ms->max_datagram_frame_size, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; break; case NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT: - nread = decode_varint(&valuelen, p, end); - if (nread < 0 || valuelen != 0) { + if (decode_varint(&valuelen, &p, end) != 0) { + return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; + } + if (valuelen != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; params->grease_quic_bit = 1; break; - case NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT: - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + case NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION: + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; if ((size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } if (valuelen < sizeof(uint32_t) || (valuelen & 0x3)) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - params->version_info.chosen_version = ngtcp2_get_uint32(p); + p = ngtcp2_get_uint32(¶ms->version_info.chosen_version, p); if (params->version_info.chosen_version == 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += sizeof(uint32_t); if (valuelen > sizeof(uint32_t)) { - params->version_info.other_versions = (uint8_t *)p; - params->version_info.other_versionslen = + params->version_info.available_versions = (uint8_t *)p; + params->version_info.available_versionslen = (size_t)valuelen - sizeof(uint32_t); - for (i = sizeof(uint32_t); i < valuelen; - i += sizeof(uint32_t), p += sizeof(uint32_t)) { - if (ngtcp2_get_uint32(p) == 0) { + for (lend = p + (valuelen - sizeof(uint32_t)); p != lend;) { + p = ngtcp2_get_uint32(&version, p); + if (version == 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } } @@ -825,11 +789,9 @@ int ngtcp2_decode_transport_params_versioned( break; default: /* Ignore unknown parameter */ - nread = decode_varint(&valuelen, p, end); - if (nread < 0) { + if (decode_varint(&valuelen, &p, end) != 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - p += nread; if ((size_t)(end - p) < valuelen) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } @@ -842,10 +804,9 @@ int ngtcp2_decode_transport_params_versioned( return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - if (!initial_scid_present || - (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS && - !original_dcid_present)) { - return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; + if (transport_params_version != NGTCP2_TRANSPORT_PARAMS_VERSION) { + ngtcp2_transport_params_convert_to_old(transport_params_version, dest, + params); } return 0; @@ -859,7 +820,7 @@ static int transport_params_copy_new(ngtcp2_transport_params **pdest, uint8_t *p; if (src->version_info_present) { - len += src->version_info.other_versionslen; + len += src->version_info.available_versionslen; } dest = ngtcp2_mem_malloc(mem, len); @@ -869,11 +830,11 @@ static int transport_params_copy_new(ngtcp2_transport_params **pdest, *dest = *src; - if (src->version_info_present && src->version_info.other_versionslen) { + if (src->version_info_present && src->version_info.available_versionslen) { p = (uint8_t *)dest + sizeof(*dest); - memcpy(p, src->version_info.other_versions, - src->version_info.other_versionslen); - dest->version_info.other_versions = p; + memcpy(p, src->version_info.available_versions, + src->version_info.available_versionslen); + dest->version_info.available_versions = p; } *pdest = dest; @@ -881,14 +842,13 @@ static int transport_params_copy_new(ngtcp2_transport_params **pdest, return 0; } -int ngtcp2_decode_transport_params_new(ngtcp2_transport_params **pparams, - ngtcp2_transport_params_type exttype, +int ngtcp2_transport_params_decode_new(ngtcp2_transport_params **pparams, const uint8_t *data, size_t datalen, const ngtcp2_mem *mem) { int rv; ngtcp2_transport_params params; - rv = ngtcp2_decode_transport_params(¶ms, exttype, data, datalen); + rv = ngtcp2_transport_params_decode(¶ms, data, datalen); if (rv < 0) { return rv; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h index 9a9d95f5b9fe82..b78429bb38f582 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h @@ -43,30 +43,30 @@ /* ngtcp2_transport_param_id is the registry of QUIC transport parameter ID. */ -typedef enum ngtcp2_transport_param_id { - NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID = 0x0000, - NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT = 0x0001, - NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN = 0x0002, - NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE = 0x0003, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA = 0x0004, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 0x0005, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = 0x0006, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI = 0x0007, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI = 0x0008, - NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI = 0x0009, - NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT = 0x000a, - NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY = 0x000b, - NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION = 0x000c, - NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS = 0x000d, - NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT = 0x000e, - NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID = 0x000f, - NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID = 0x0010, - /* https://datatracker.ietf.org/doc/html/rfc9221 */ - NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE = 0x0020, - NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT = 0x2ab2, - /* https://quicwg.org/quic-v2/draft-ietf-quic-v2.html */ - NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT = 0xff73db, -} ngtcp2_transport_param_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 +/* https://datatracker.ietf.org/doc/html/rfc9221 */ +#define NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE 0x20 +#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2ab2 +/* https://datatracker.ietf.org/doc/html/rfc9368 */ +#define NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION 0x11 /* NGTCP2_CRYPTO_KM_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00u diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c index 8f676da3ef0a13..5e4794cd72e7d4 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c @@ -137,6 +137,9 @@ uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr) { case NGTCP2_ERR_INVALID_ARGUMENT: case NGTCP2_ERR_NOMEM: case NGTCP2_ERR_CALLBACK_FAILURE: + case NGTCP2_ERR_HANDSHAKE_TIMEOUT: + case NGTCP2_ERR_PKT_NUM_EXHAUSTED: + case NGTCP2_ERR_INTERNAL: return NGTCP2_INTERNAL_ERROR; case NGTCP2_ERR_STREAM_STATE: return NGTCP2_STREAM_STATE_ERROR; @@ -147,7 +150,7 @@ uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr) { case NGTCP2_ERR_NO_VIABLE_PATH: return NGTCP2_NO_VIABLE_PATH; case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE: - return NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT; + return NGTCP2_VERSION_NEGOTIATION_ERROR; default: return NGTCP2_PROTOCOL_VIOLATION; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c new file mode 100644 index 00000000000000..41c2a6a755cc8a --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c @@ -0,0 +1,220 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 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_frame_chain.h" + +#include +#include + +ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent); + +int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem) { + *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain)); + if (*pfrc == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_frame_chain_init(*pfrc); + + return 0; +} + +int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, + ngtcp2_objalloc *objalloc) { + *pfrc = ngtcp2_objalloc_frame_chain_get(objalloc); + if (*pfrc == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_frame_chain_init(*pfrc); + + return 0; +} + +int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, + const ngtcp2_mem *mem) { + *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain) + extralen); + if (*pfrc == NULL) { + return NGTCP2_ERR_NOMEM; + } + + ngtcp2_frame_chain_init(*pfrc); + + return 0; +} + +int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, + size_t datacnt, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + size_t need, avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream); + + if (datacnt > 1) { + need = sizeof(ngtcp2_vec) * (datacnt - 1); + + if (need > avail) { + return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); + } + } + + return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); +} + +int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, + const uint8_t *token, + size_t tokenlen, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token); + int rv; + uint8_t *p; + ngtcp2_frame *fr; + + if (tokenlen > avail) { + rv = ngtcp2_frame_chain_extralen_new(pfrc, tokenlen - avail, mem); + } else { + rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); + } + if (rv != 0) { + return rv; + } + + fr = &(*pfrc)->fr; + fr->type = NGTCP2_FRAME_NEW_TOKEN; + + p = (uint8_t *)fr + sizeof(ngtcp2_new_token); + memcpy(p, token, tokenlen); + + fr->new_token.token = p; + fr->new_token.tokenlen = tokenlen; + + return 0; +} + +void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) { + ngtcp2_frame_chain_binder *binder; + + if (frc == NULL) { + return; + } + + binder = frc->binder; + if (binder && --binder->refcount == 0) { + ngtcp2_mem_free(mem, binder); + } + + ngtcp2_mem_free(mem, frc); +} + +void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + ngtcp2_frame_chain_binder *binder; + + if (frc == NULL) { + return; + } + + switch (frc->fr.type) { + case NGTCP2_FRAME_CRYPTO: + case NGTCP2_FRAME_STREAM: + if (frc->fr.stream.datacnt && + sizeof(ngtcp2_vec) * (frc->fr.stream.datacnt - 1) > + sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream)) { + ngtcp2_frame_chain_del(frc, mem); + + return; + } + + break; + case NGTCP2_FRAME_NEW_TOKEN: + if (frc->fr.new_token.tokenlen > + sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token)) { + ngtcp2_frame_chain_del(frc, mem); + + return; + } + + break; + } + + binder = frc->binder; + if (binder && --binder->refcount == 0) { + ngtcp2_mem_free(mem, binder); + } + + frc->binder = NULL; + + ngtcp2_objalloc_frame_chain_release(objalloc, frc); +} + +void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) { + frc->next = NULL; + frc->binder = NULL; +} + +void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem) { + ngtcp2_frame_chain *next; + + for (; frc; frc = next) { + next = frc->next; + + ngtcp2_frame_chain_objalloc_del(frc, objalloc, mem); + } +} + +int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, + const ngtcp2_mem *mem) { + *pbinder = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_frame_chain_binder)); + if (*pbinder == NULL) { + return NGTCP2_ERR_NOMEM; + } + + return 0; +} + +int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, + const ngtcp2_mem *mem) { + ngtcp2_frame_chain_binder *binder; + int rv; + + assert(b->binder == NULL); + + if (a->binder == NULL) { + rv = ngtcp2_frame_chain_binder_new(&binder, mem); + if (rv != 0) { + return rv; + } + + a->binder = binder; + ++a->binder->refcount; + } + + b->binder = a->binder; + ++b->binder->refcount; + + return 0; +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h new file mode 100644 index 00000000000000..656fa5b799450e --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h @@ -0,0 +1,171 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 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_FRAME_CHAIN_H +#define NGTCP2_FRAME_CHAIN_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include "ngtcp2_pkt.h" +#include "ngtcp2_objalloc.h" + +/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is + set. */ +#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u +/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information + which a frame carries has been acknowledged. */ +#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u + +/* + * ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to + * share the acknowledgement state. In general, all + * ngtcp2_frame_chains bound to the same binder must have the same + * information. + */ +typedef struct ngtcp2_frame_chain_binder { + size_t refcount; + /* flags is bitwise OR of zero or more of + NGTCP2_FRAME_CHAIN_BINDER_FLAG_*. */ + uint32_t flags; +} ngtcp2_frame_chain_binder; + +int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, + const ngtcp2_mem *mem); + +typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; + +/* + * ngtcp2_frame_chain chains frames in a single packet. + */ +struct ngtcp2_frame_chain { + union { + struct { + ngtcp2_frame_chain *next; + ngtcp2_frame_chain_binder *binder; + ngtcp2_frame fr; + }; + + ngtcp2_opl_entry oplent; + }; +}; + +ngtcp2_objalloc_decl(frame_chain, ngtcp2_frame_chain, oplent); + +/* + * ngtcp2_bind_frame_chains binds two frame chains |a| and |b| using + * new or existing ngtcp2_frame_chain_binder. |a| might have non-NULL + * a->binder. |b| must not have non-NULL b->binder. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory + */ +int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, + const ngtcp2_mem *mem); + +/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that + a ngtcp2_stream can include. */ +#define NGTCP2_MAX_STREAM_DATACNT 256 + +/* + * ngtcp2_frame_chain_new allocates ngtcp2_frame_chain object and + * assigns its pointer to |*pfrc|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGTCP2_ERR_NOMEM + * Out of memory. + */ +int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_objalloc_new behaves like + * ngtcp2_frame_chain_new, but it uses |objalloc| to allocate the object. + */ +int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, + ngtcp2_objalloc *objalloc); + +/* + * ngtcp2_frame_chain_extralen_new works like ngtcp2_frame_chain_new, + * but it allocates extra memory |extralen| in order to extend + * ngtcp2_frame. + */ +int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, + const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_stream_datacnt_objalloc_new works like + * ngtcp2_frame_chain_new, but it allocates enough data to store + * additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_stream + * object. If no additional space is required, + * ngtcp2_frame_chain_objalloc_new is called internally. + */ +int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, + size_t datacnt, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, + const uint8_t *token, + size_t tokenlen, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_del deallocates |frc|. It also deallocates the + * memory pointed by |frc|. + */ +void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse. + * It might just delete |frc| depending on the frame type and the size + * of |frc|. + */ +void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +/* + * ngtcp2_frame_chain_init initializes |frc|. + */ +void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc); + +/* + * ngtcp2_frame_chain_list_objalloc_del adds all ngtcp2_frame_chain + * linked from |frc| to |objalloc| for reuse. Depending on the frame type + * and its size, ngtcp2_frame_chain might be deleted instead. + */ +void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, + ngtcp2_objalloc *objalloc, + const ngtcp2_mem *mem); + +#endif /* NGTCP2_FRAME_CHAIN_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c index 0bd424cb0bc1f1..0ccc048b5b16b1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c @@ -35,6 +35,8 @@ static ngtcp2_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}}; +ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent); + static size_t ksl_nodelen(size_t keylen) { return (sizeof(ngtcp2_ksl_node) + keylen - sizeof(uint64_t) + 0xfu) & ~(uintptr_t)0xfu; @@ -714,6 +716,24 @@ void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key, } } +size_t ngtcp2_ksl_len(ngtcp2_ksl *ksl) { return ksl->n; } + +void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) { + if (!ksl->head) { + return; + } + +#ifdef NOMEMPOOL + ksl_free_blk(ksl, ksl->head); +#endif /* NOMEMPOOL */ + + ksl->front = ksl->back = ksl->head = NULL; + ksl->n = 0; + + ngtcp2_objalloc_clear(&ksl->blkalloc); +} + +#ifndef WIN32 static void ksl_print(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t level) { size_t i; ngtcp2_ksl_node *node; @@ -734,23 +754,6 @@ static void ksl_print(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t level) { } } -size_t ngtcp2_ksl_len(ngtcp2_ksl *ksl) { return ksl->n; } - -void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) { - if (!ksl->head) { - return; - } - -#ifdef NOMEMPOOL - ksl_free_blk(ksl, ksl->head); -#endif /* NOMEMPOOL */ - - ksl->front = ksl->back = ksl->head = NULL; - ksl->n = 0; - - ngtcp2_objalloc_clear(&ksl->blkalloc); -} - void ngtcp2_ksl_print(ngtcp2_ksl *ksl) { if (!ksl->head) { return; @@ -758,6 +761,7 @@ void ngtcp2_ksl_print(ngtcp2_ksl *ksl) { ksl_print(ksl, ksl->head, 0); } +#endif /* !WIN32 */ ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl) { ngtcp2_ksl_it it; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h index 312a151d4aa9ec..7e08f15cdae6e8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h @@ -106,7 +106,7 @@ struct ngtcp2_ksl_blk { }; }; -ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent); +ngtcp2_objalloc_decl(ksl_blk, ngtcp2_ksl_blk, oplent); /* * ngtcp2_ksl_compar is a function type which returns nonzero if key @@ -263,12 +263,14 @@ void ngtcp2_ksl_clear(ngtcp2_ksl *ksl); #define ngtcp2_ksl_nth_node(KSL, BLK, N) \ ((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) +#ifndef WIN32 /* * ngtcp2_ksl_print prints its internal state in stderr. It assumes * that the key is of type int64_t. This function should be used for * the debugging purpose only. */ void ngtcp2_ksl_print(ngtcp2_ksl *ksl); +#endif /* !WIN32 */ /* * ngtcp2_ksl_it_init initializes |it|. diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c index ee37ff3517b2bc..760bd60a9aff76 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c @@ -35,6 +35,8 @@ #include "ngtcp2_vec.h" #include "ngtcp2_macro.h" #include "ngtcp2_conv.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_net.h" void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, ngtcp2_printf log_printf, ngtcp2_tstamp ts, @@ -45,6 +47,7 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, log->scid[0] = '\0'; } log->log_printf = log_printf; + log->events = 0xff; log->ts = log->last_ts = ts; log->user_data = user_data; } @@ -65,7 +68,7 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, * Source Connection ID in hex string. * * : - * Event. pkt=packet, frm=frame, rcv=recovery, cry=crypto, + * Event. pkt=packet, frm=frame, ldc=loss-detection, cry=crypto, * con=connection(catch all) * * # Frame event @@ -138,7 +141,7 @@ static const char *strerrorcode(uint64_t error_code) { return "CRYPTO_BUFFER_EXCEEDED"; case NGTCP2_KEY_UPDATE_ERROR: return "KEY_UPDATE_ERROR"; - case NGTCP2_VERSION_NEGOTIATION_ERROR_DRAFT: + case NGTCP2_VERSION_NEGOTIATION_ERROR: return "VERSION_NEGOTIATION_ERROR"; default: if (0x100u <= error_code && error_code <= 0x1ffu) { @@ -202,12 +205,14 @@ static const char *strevent(ngtcp2_log_event ev) { return "pkt"; case NGTCP2_LOG_EVENT_FRM: return "frm"; - case NGTCP2_LOG_EVENT_RCV: - return "rcv"; + case NGTCP2_LOG_EVENT_LDC: + return "ldc"; case NGTCP2_LOG_EVENT_CRY: return "cry"; case NGTCP2_LOG_EVENT_PTV: return "ptv"; + case NGTCP2_LOG_EVENT_CCA: + return "cca"; case NGTCP2_LOG_EVENT_NONE: default: return "non"; @@ -220,8 +225,8 @@ static void log_fr_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stream *fr, const char *dir) { log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " STREAM(0x%02x) id=0x%" PRIx64 " fin=%d offset=%" PRIu64 - " len=%" PRIu64 " uni=%d"), + (NGTCP2_LOG_PKT " STREAM(0x%02" PRIx64 ") id=0x%" PRIx64 + " fin=%d offset=%" PRIu64 " len=%" PRIu64 " uni=%d"), NGTCP2_LOG_FRM_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); @@ -233,36 +238,37 @@ static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, size_t i; log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) largest_ack=%" PRId64 + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") largest_ack=%" PRId64 " ack_delay=%" PRIu64 "(%" PRIu64 - ") ack_block_count=%zu"), + ") ack_range_count=%zu"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->largest_ack, fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, fr->ack_delay, - fr->num_blks); + fr->rangecnt); largest_ack = fr->largest_ack; - min_ack = fr->largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = fr->largest_ack - (int64_t)fr->first_ack_range; log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) block=[%" PRId64 "..%" PRId64 - "] block_count=%" PRIu64), + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64 + "..%" PRId64 "] len=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, min_ack, - fr->first_ack_blklen); + fr->first_ack_range); - for (i = 0; i < fr->num_blks; ++i) { - const ngtcp2_ack_blk *blk = &fr->blks[i]; - largest_ack = min_ack - (int64_t)blk->gap - 2; - min_ack = largest_ack - (int64_t)blk->blklen; + 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; log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) block=[%" PRId64 "..%" PRId64 - "] gap=%" PRIu64 " block_count=%" PRIu64), + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") range=[%" PRId64 + "..%" PRId64 "] gap=%" PRIu64 + " len=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, - min_ack, blk->gap, blk->blklen); + min_ack, range->gap, range->len); } if (fr->type == NGTCP2_FRAME_ACK_ECN) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " ACK(0x%02x) ect0=%" PRIu64 + (NGTCP2_LOG_PKT " ACK(0x%02" PRIx64 ") ect0=%" PRIu64 " ect1=%" PRIu64 " ce=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->ecn.ect0, fr->ecn.ect1, fr->ecn.ce); @@ -271,7 +277,8 @@ static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_padding(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_padding *fr, const char *dir) { - log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PADDING(0x%02x) len=%zu"), + log->log_printf(log->user_data, + (NGTCP2_LOG_PKT " PADDING(0x%02" PRIx64 ") len=%zu"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->len); } @@ -280,7 +287,7 @@ static void log_fr_reset_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const char *dir) { log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " RESET_STREAM(0x%02x) id=0x%" PRIx64 + (NGTCP2_LOG_PKT " RESET_STREAM(0x%02" PRIx64 ") id=0x%" PRIx64 " app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, strapperrorcode(fr->app_error_code), fr->app_error_code, fr->final_size); @@ -293,9 +300,10 @@ static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, size_t reasonlen = ngtcp2_min(sizeof(reason) - 1, fr->reasonlen); log->log_printf(log->user_data, - (NGTCP2_LOG_PKT - " CONNECTION_CLOSE(0x%02x) error_code=%s(0x%" PRIx64 ") " - "frame_type=%" PRIx64 " reason_len=%zu reason=[%s]"), + (NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02" PRIx64 + ") error_code=%s(0x%" PRIx64 ") " + "frame_type=%" PRIx64 + " reason_len=%zu reason=[%s]"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->type == NGTCP2_FRAME_CONNECTION_CLOSE ? strerrorcode(fr->error_code) @@ -306,16 +314,18 @@ static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_max_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_data *fr, const char *dir) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " MAX_DATA(0x%02x) max_data=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_data); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " MAX_DATA(0x%02" PRIx64 ") max_data=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, 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) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02x) id=0x%" PRIx64 + (NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02" PRIx64 + ") id=0x%" PRIx64 " max_stream_data=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, fr->max_stream_data); @@ -323,31 +333,33 @@ static void log_fr_max_stream_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_max_streams(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_max_streams *fr, const char *dir) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " MAX_STREAMS(0x%02x) max_streams=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " MAX_STREAMS(0x%02" PRIx64 ") max_streams=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams); } static void log_fr_ping(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_ping *fr, const char *dir) { - log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PING(0x%02x)"), + log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PING(0x%02" PRIx64 ")"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type); } static void log_fr_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_data_blocked *fr, const char *dir) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02x) offset=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02" PRIx64 ") offset=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, 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) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02x) id=0x%" PRIx64 - " offset=%" PRIu64), + (NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02" PRIx64 + ") id=0x%" PRIx64 " offset=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, fr->offset); } @@ -357,7 +369,7 @@ static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const char *dir) { log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02x) max_streams=%" PRIu64), + (NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02" PRIx64 ") max_streams=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams); } @@ -369,7 +381,7 @@ static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log->log_printf( log->user_data, - (NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02x) seq=%" PRIu64 + (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_FRM_HD_FIELDS(dir), fr->type, fr->seq, @@ -383,7 +395,7 @@ static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_stop_sending *fr, const char *dir) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " STOP_SENDING(0x%02x) id=0x%" PRIx64 + (NGTCP2_LOG_PKT " STOP_SENDING(0x%02" PRIx64 ") id=0x%" PRIx64 " app_error_code=%s(0x%" PRIx64 ")"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, strapperrorcode(fr->app_error_code), fr->app_error_code); @@ -395,7 +407,8 @@ static void log_fr_path_challenge(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t buf[sizeof(fr->data) * 2 + 1]; log->log_printf( - log->user_data, (NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02x) data=0x%s"), + log->user_data, + (NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data))); } @@ -406,18 +419,19 @@ static void log_fr_path_response(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t buf[sizeof(fr->data) * 2 + 1]; log->log_printf( - log->user_data, (NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02x) data=0x%s"), + log->user_data, + (NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data))); } static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, - const ngtcp2_crypto *fr, const char *dir) { - log->log_printf( - log->user_data, - (NGTCP2_LOG_PKT " CRYPTO(0x%02x) offset=%" PRIu64 " len=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset, - ngtcp2_vec_len(fr->data, fr->datacnt)); + const ngtcp2_stream *fr, const char *dir) { + log->log_printf(log->user_data, + (NGTCP2_LOG_PKT " CRYPTO(0x%02" PRIx64 ") offset=%" PRIu64 + " len=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset, + ngtcp2_vec_len(fr->data, fr->datacnt)); } static void log_fr_new_token(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -427,38 +441,41 @@ static void log_fr_new_token(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t buf[128 + 1 + 1]; uint8_t *p; - if (fr->token.len > 64) { - p = ngtcp2_encode_hex(buf, fr->token.base, 64); + if (fr->tokenlen > 64) { + p = ngtcp2_encode_hex(buf, fr->token, 64); p[128] = '*'; p[129] = '\0'; } else { - p = ngtcp2_encode_hex(buf, fr->token.base, fr->token.len); + p = ngtcp2_encode_hex(buf, fr->token, fr->tokenlen); } log->log_printf( - log->user_data, (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02x) token=0x%s len=%zu"), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, fr->token.len); + log->user_data, + (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu"), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, 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) { - log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02x) seq=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq); + log->log_printf( + log->user_data, + (NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02" PRIx64 ") seq=%" PRIu64), + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq); } static void log_fr_handshake_done(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_handshake_done *fr, const char *dir) { - log->log_printf(log->user_data, (NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02x)"), + log->log_printf(log->user_data, + (NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02" PRIx64 ")"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type); } static void log_fr_datagram(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_datagram *fr, const char *dir) { log->log_printf(log->user_data, - (NGTCP2_LOG_PKT " DATAGRAM(0x%02x) len=%" PRIu64), + (NGTCP2_LOG_PKT " DATAGRAM(0x%02" PRIx64 ") len=%" PRIu64), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, ngtcp2_vec_len(fr->data, fr->datacnt)); } @@ -519,7 +536,7 @@ static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log_fr_path_response(log, hd, &fr->path_response, dir); break; case NGTCP2_FRAME_CRYPTO: - log_fr_crypto(log, hd, &fr->crypto, dir); + log_fr_crypto(log, hd, &fr->stream, dir); break; case NGTCP2_FRAME_NEW_TOKEN: log_fr_new_token(log, hd, &fr->new_token, dir); @@ -535,13 +552,13 @@ static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log_fr_datagram(log, hd, &fr->datagram, dir); break; default: - assert(0); + ngtcp2_unreachable(); } } void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_frame *fr) { - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_FRM)) { return; } @@ -550,7 +567,7 @@ 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) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_FRM)) { return; } @@ -561,7 +578,7 @@ 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) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } @@ -576,7 +593,7 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) { ngtcp2_pkt_hd shd; ngtcp2_pkt_hd *hd = &shd; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } @@ -592,82 +609,94 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) { sr->randlen); } -void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype, +void ngtcp2_log_remote_tp(ngtcp2_log *log, const ngtcp2_transport_params *params) { uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1]; uint8_t addr[16 * 2 + 7 + 1]; uint8_t 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) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_CRY)) { return; } - if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { - if (params->stateless_reset_token_present) { - log->log_printf(log->user_data, - (NGTCP2_LOG_TP " stateless_reset_token=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex( - token, params->stateless_reset_token, - sizeof(params->stateless_reset_token))); - } + if (params->stateless_reset_token_present) { + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " stateless_reset_token=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(token, params->stateless_reset_token, + sizeof(params->stateless_reset_token))); + } + + if (params->preferred_addr_present) { + if (params->preferred_addr.ipv4_present) { + sa_in = ¶ms->preferred_addr.ipv4; - if (params->preferred_address_present) { log->log_printf(log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s"), NGTCP2_LOG_TP_HD_FIELDS, (const char *)ngtcp2_encode_ipv4( - addr, params->preferred_address.ipv4_addr)); - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"), - NGTCP2_LOG_TP_HD_FIELDS, params->preferred_address.ipv4_port); + addr, (const uint8_t *)&sa_in->sin_addr)); + log->log_printf(log->user_data, + (NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"), + NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in->sin_port)); + } + + if (params->preferred_addr.ipv6_present) { + sa_in6 = ¶ms->preferred_addr.ipv6; log->log_printf(log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s"), NGTCP2_LOG_TP_HD_FIELDS, (const char *)ngtcp2_encode_ipv6( - addr, params->preferred_address.ipv6_addr)); - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"), - NGTCP2_LOG_TP_HD_FIELDS, params->preferred_address.ipv6_port); - + addr, (const uint8_t *)&sa_in6->sin6_addr)); log->log_printf(log->user_data, - (NGTCP2_LOG_TP " preferred_address.cid=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex( - cid, params->preferred_address.cid.data, - params->preferred_address.cid.datalen)); - log->log_printf( - log->user_data, - (NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex( - token, params->preferred_address.stateless_reset_token, - sizeof(params->preferred_address.stateless_reset_token))); + (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"), + NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in6->sin6_port)); } + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " preferred_address.cid=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(cid, params->preferred_addr.cid.data, + params->preferred_addr.cid.datalen)); + log->log_printf( + log->user_data, + (NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex( + token, params->preferred_addr.stateless_reset_token, + sizeof(params->preferred_addr.stateless_reset_token))); + } + + if (params->original_dcid_present) { log->log_printf( log->user_data, (NGTCP2_LOG_TP " original_destination_connection_id=0x%s"), NGTCP2_LOG_TP_HD_FIELDS, (const char *)ngtcp2_encode_hex(cid, params->original_dcid.data, params->original_dcid.datalen)); + } - if (params->retry_scid_present) { - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " retry_source_connection_id=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex(cid, params->retry_scid.data, - params->retry_scid.datalen)); - } + if (params->retry_scid_present) { + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " retry_source_connection_id=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(cid, params->retry_scid.data, + params->retry_scid.datalen)); } - log->log_printf( - log->user_data, (NGTCP2_LOG_TP " initial_source_connection_id=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex(cid, params->initial_scid.data, - params->initial_scid.datalen)); + if (params->initial_scid_present) { + log->log_printf( + log->user_data, (NGTCP2_LOG_TP " initial_source_connection_id=0x%s"), + NGTCP2_LOG_TP_HD_FIELDS, + (const char *)ngtcp2_encode_hex(cid, params->initial_scid.data, + params->initial_scid.datalen)); + } log->log_printf( log->user_data, @@ -718,26 +747,28 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype, (NGTCP2_LOG_TP " version_information.chosen_version=0x%08x"), NGTCP2_LOG_TP_HD_FIELDS, params->version_info.chosen_version); - assert(!(params->version_info.other_versionslen & 0x3)); + assert(!(params->version_info.available_versionslen & 0x3)); - for (i = 0; i < params->version_info.other_versionslen; + for (i = 0, p = params->version_info.available_versions; + i < params->version_info.available_versionslen; i += sizeof(uint32_t)) { + p = ngtcp2_get_uint32(&version, p); + log->log_printf( log->user_data, - (NGTCP2_LOG_TP " version_information.other_versions[%zu]=0x%08x"), - NGTCP2_LOG_TP_HD_FIELDS, i >> 2, - ngtcp2_get_uint32(¶ms->version_info.other_versions[i])); + (NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x"), + NGTCP2_LOG_TP_HD_FIELDS, i >> 2, version); } } } 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) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_LDC)) { return; } - ngtcp2_log_info(log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num, strpkttype_type_flags(type, flags), sent_ts); } @@ -747,7 +778,7 @@ static void log_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, uint8_t dcid[sizeof(hd->dcid.data) * 2 + 1]; uint8_t scid[sizeof(hd->scid.data) * 2 + 1]; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) { return; } @@ -782,7 +813,7 @@ void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt, int n; char buf[NGTCP2_LOG_BUFLEN]; - if (!log->log_printf) { + if (!log->log_printf || !(log->events & ev)) { return; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h index 029ef1b757ab09..1280ce04d6385a 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h @@ -37,6 +37,9 @@ typedef struct ngtcp2_log { /* log_printf is a sink to write log. NULL means no logging output. */ ngtcp2_printf log_printf; + /* events is an event filter. Only events set in this field are + emitted. */ + uint8_t events; /* ts is the time point used to write time delta in the log. */ ngtcp2_tstamp ts; /* last_ts is the most recent time point that this object is @@ -63,27 +66,33 @@ typedef enum ngtcp2_log_event { /** * :enum:`NGTCP2_LOG_EVENT_CON` is a connection (catch-all) event */ - NGTCP2_LOG_EVENT_CON, + NGTCP2_LOG_EVENT_CON = 0x1, /** * :enum:`NGTCP2_LOG_EVENT_PKT` is a packet event. */ - NGTCP2_LOG_EVENT_PKT, + NGTCP2_LOG_EVENT_PKT = 0x2, /** * :enum:`NGTCP2_LOG_EVENT_FRM` is a QUIC frame event. */ - NGTCP2_LOG_EVENT_FRM, + NGTCP2_LOG_EVENT_FRM = 0x4, /** - * :enum:`NGTCP2_LOG_EVENT_RCV` is a congestion and recovery event. + * :enum:`NGTCP2_LOG_EVENT_LDC` is a loss detection and congestion + * control event. */ - NGTCP2_LOG_EVENT_RCV, + NGTCP2_LOG_EVENT_LDC = 0x8, /** * :enum:`NGTCP2_LOG_EVENT_CRY` is a crypto event. */ - NGTCP2_LOG_EVENT_CRY, + NGTCP2_LOG_EVENT_CRY = 0x10, /** * :enum:`NGTCP2_LOG_EVENT_PTV` is a path validation event. */ - NGTCP2_LOG_EVENT_PTV, + NGTCP2_LOG_EVENT_PTV = 0x20, + /** + * :enum:`NGTCP2_LOG_EVENT_CCA` is a congestion controller algorithm + * event. + */ + NGTCP2_LOG_EVENT_CCA = 0x40, } ngtcp2_log_event; void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, @@ -100,7 +109,7 @@ void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr); -void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype, +void ngtcp2_log_remote_tp(ngtcp2_log *log, const ngtcp2_transport_params *params); void ngtcp2_log_pkt_lost(ngtcp2_log *log, int64_t pkt_num, uint8_t type, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h index e2603aae15dd04..28d3461bef9238 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h @@ -50,4 +50,9 @@ *(PD) = (T); \ } while (0) +/* + * ngtcp2_arraylen returns the number of elements in array |A|. + */ +#define ngtcp2_arraylen(A) (sizeof(A) / sizeof(A[0])) + #endif /* NGTCP2_MACRO_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c index 12bc6e84bd4f0c..33e9fcc018b5db 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c @@ -126,6 +126,7 @@ static void map_bucket_set_data(ngtcp2_map_bucket *bkt, uint32_t hash, bkt->data = data; } +#ifndef WIN32 void ngtcp2_map_print_distance(ngtcp2_map *map) { uint32_t i; size_t idx; @@ -145,6 +146,7 @@ void ngtcp2_map_print_distance(ngtcp2_map *map) { distance(map->tablelen, map->tablelenbits, bkt, idx)); } } +#endif /* !WIN32 */ static int insert(ngtcp2_map_bucket *table, uint32_t tablelen, uint32_t tablelenbits, uint32_t hash, ngtcp2_map_key_type key, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h index a64344a9a301a3..d05b1657489e45 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h @@ -131,6 +131,8 @@ size_t ngtcp2_map_size(ngtcp2_map *map); int ngtcp2_map_each(ngtcp2_map *map, int (*func)(void *data, void *ptr), void *ptr); +#ifndef WIN32 void ngtcp2_map_print_distance(ngtcp2_map *map); +#endif /* !WIN32 */ #endif /* NGTCP2_MAP_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h index b1f28096174605..bf697927351851 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h @@ -52,16 +52,11 @@ # include #endif /* HAVE_SYS_ENDIAN_H */ -#include +#if defined(__APPLE__) +# include +#endif // __APPLE__ -#if defined(HAVE_BSWAP_64) || \ - (defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0) -# define ngtcp2_bswap64 bswap_64 -#else /* !HAVE_BSWAP_64 */ -# define ngtcp2_bswap64(N) \ - ((uint64_t)(ngtcp2_ntohl((uint32_t)(N))) << 32 | \ - ngtcp2_ntohl((uint32_t)((N) >> 32))) -#endif /* !HAVE_BSWAP_64 */ +#include #if defined(HAVE_BE64TOH) || \ (defined(HAVE_DECL_BE64TOH) && HAVE_DECL_BE64TOH > 0) @@ -72,6 +67,18 @@ # define ngtcp2_ntohl64(N) (N) # define ngtcp2_htonl64(N) (N) # else /* !WORDS_BIGENDIAN */ +# if defined(HAVE_BSWAP_64) || \ + (defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0) +# define ngtcp2_bswap64 bswap_64 +# elif defined(WIN32) +# define ngtcp2_bswap64 _byteswap_uint64 +# elif defined(__APPLE__) +# define ngtcp2_bswap64 OSSwapInt64 +# else /* !HAVE_BSWAP_64 && !WIN32 && !__APPLE__ */ +# define ngtcp2_bswap64(N) \ + ((uint64_t)(ngtcp2_ntohl((uint32_t)(N))) << 32 | \ + ngtcp2_ntohl((uint32_t)((N) >> 32))) +# endif /* !HAVE_BSWAP_64 && !WIN32 && !__APPLE__ */ # define ngtcp2_ntohl64(N) ngtcp2_bswap64(N) # define ngtcp2_htonl64(N) ngtcp2_bswap64(N) # endif /* !WORDS_BIGENDIAN */ @@ -109,9 +116,9 @@ STIN uint16_t ngtcp2_htons(uint16_t hostshort) { STIN uint32_t ngtcp2_ntohl(uint32_t netlong) { uint32_t res; unsigned char *p = (unsigned char *)&netlong; - res = *p++ << 24; - res += *p++ << 16; - res += *p++ << 8; + res = (uint32_t)(*p++ << 24); + res += (uint32_t)(*p++ << 16); + res += (uint32_t)(*p++ << 8); res += *p; return res; } @@ -119,7 +126,7 @@ STIN uint32_t ngtcp2_ntohl(uint32_t netlong) { STIN uint16_t ngtcp2_ntohs(uint16_t netshort) { uint16_t res; unsigned char *p = (unsigned char *)&netshort; - res = *p++ << 8; + res = (uint16_t)(*p++ << 8); res += *p; return res; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h index f1bbd3a5c9405c..ea73e788317681 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h @@ -65,15 +65,25 @@ void ngtcp2_objalloc_free(ngtcp2_objalloc *objalloc); void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); #ifndef NOMEMPOOL -# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \ +# define ngtcp2_objalloc_decl(NAME, TYPE, OPLENTFIELD) \ 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); \ } \ \ - inline static TYPE *ngtcp2_objalloc_##NAME##_get( \ - ngtcp2_objalloc *objalloc) { \ + TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc); \ + \ + TYPE *ngtcp2_objalloc_##NAME##_len_get(ngtcp2_objalloc *objalloc, \ + size_t len); \ + \ + inline static void ngtcp2_objalloc_##NAME##_release( \ + ngtcp2_objalloc *objalloc, TYPE *obj) { \ + ngtcp2_opl_push(&objalloc->opl, &obj->OPLENTFIELD); \ + } + +# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \ + TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc) { \ ngtcp2_opl_entry *oplent = ngtcp2_opl_pop(&objalloc->opl); \ TYPE *obj; \ int rv; \ @@ -91,8 +101,8 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); return ngtcp2_struct_of(oplent, TYPE, OPLENTFIELD); \ } \ \ - inline static TYPE *ngtcp2_objalloc_##NAME##_len_get( \ - ngtcp2_objalloc *objalloc, size_t len) { \ + TYPE *ngtcp2_objalloc_##NAME##_len_get(ngtcp2_objalloc *objalloc, \ + size_t len) { \ ngtcp2_opl_entry *oplent = ngtcp2_opl_pop(&objalloc->opl); \ TYPE *obj; \ int rv; \ @@ -107,14 +117,9 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); } \ \ return ngtcp2_struct_of(oplent, TYPE, OPLENTFIELD); \ - } \ - \ - inline static void ngtcp2_objalloc_##NAME##_release( \ - ngtcp2_objalloc *objalloc, TYPE *obj) { \ - ngtcp2_opl_push(&objalloc->opl, &obj->OPLENTFIELD); \ } #else /* NOMEMPOOL */ -# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \ +# define ngtcp2_objalloc_decl(NAME, TYPE, OPLENTFIELD) \ inline static void ngtcp2_objalloc_##NAME##_init( \ ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \ ngtcp2_objalloc_init( \ @@ -135,6 +140,8 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); ngtcp2_objalloc *objalloc, TYPE *obj) { \ ngtcp2_mem_free(objalloc->balloc.mem, obj); \ } + +# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) #endif /* NOMEMPOOL */ #endif /* NGTCP2_OBJALLOC_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c index 62fef7d6005ed6..12f7daeaf242a9 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c @@ -33,6 +33,7 @@ #include "ngtcp2_cid.h" #include "ngtcp2_mem.h" #include "ngtcp2_vec.h" +#include "ngtcp2_unreachable.h" int ngtcp2_pkt_chain_new(ngtcp2_pkt_chain **ppc, const ngtcp2_path *path, const ngtcp2_pkt_info *pi, const uint8_t *pkt, @@ -91,7 +92,7 @@ int ngtcp2_pkt_decode_version_cid(ngtcp2_version_cid *dest, const uint8_t *data, return NGTCP2_ERR_INVALID_ARGUMENT; } - version = ngtcp2_get_uint32(&data[1]); + ngtcp2_get_uint32(&version, &data[1]); supported_version = ngtcp2_is_supported_version(version); @@ -155,15 +156,13 @@ void ngtcp2_pkt_hd_init(ngtcp2_pkt_hd *hd, uint8_t flags, uint8_t type, ngtcp2_cid_zero(&hd->scid); } hd->pkt_num = pkt_num; - hd->token.base = NULL; - hd->token.len = 0; + hd->token = NULL; + hd->tokenlen = 0; hd->pkt_numlen = pkt_numlen; hd->version = version; hd->len = len; } -static int has_mask(uint8_t b, uint8_t mask) { return (b & mask) == mask; } - ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t pktlen) { uint8_t type; @@ -186,7 +185,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, return NGTCP2_ERR_INVALID_ARGUMENT; } - version = ngtcp2_get_uint32(&pkt[1]); + ngtcp2_get_uint32(&version, &pkt[1]); if (version == 0) { type = NGTCP2_PKT_VERSION_NEGOTIATION; @@ -218,7 +217,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, break; default: /* Unreachable */ - assert(0); + ngtcp2_unreachable(); } } @@ -254,22 +253,20 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, if (type == NGTCP2_PKT_INITIAL) { /* Token Length */ - ntokenlen = ngtcp2_get_varint_len(p); + ntokenlen = ngtcp2_get_uvarintlen(p); len += ntokenlen - 1; if (pktlen < len) { return NGTCP2_ERR_INVALID_ARGUMENT; } - vi = ngtcp2_get_varint(&ntokenlen, p); + p = ngtcp2_get_uvarint(&vi, p); if (pktlen - len < vi) { return NGTCP2_ERR_INVALID_ARGUMENT; } tokenlen = (size_t)vi; len += tokenlen; - p += ntokenlen; - if (tokenlen) { token = p; } @@ -288,7 +285,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, } /* Length */ - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (pktlen < len) { @@ -308,8 +305,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, ngtcp2_cid_init(&dest->scid, p, scil); p += scil; - dest->token.base = (uint8_t *)token; - dest->token.len = tokenlen; + dest->token = token; + dest->tokenlen = tokenlen; p += ntokenlen + tokenlen; switch (type) { @@ -324,12 +321,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, break; } - vi = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_uvarint(&vi, p); if (vi > SIZE_MAX) { return NGTCP2_ERR_INVALID_ARGUMENT; } dest->len = (size_t)vi; - p += n; } assert((size_t)(p - pkt) == len); @@ -373,8 +369,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_short(ngtcp2_pkt_hd *dest, const uint8_t *pkt, dest->len = 0; dest->pkt_num = 0; dest->pkt_numlen = 0; - dest->token.base = NULL; - dest->token.len = 0; + dest->token = NULL; + dest->tokenlen = 0; assert((size_t)(p - pkt) == len); @@ -393,7 +389,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_long(uint8_t *out, size_t outlen, } if (hd->type == NGTCP2_PKT_INITIAL) { - len += ngtcp2_put_varint_len(hd->token.len) + hd->token.len; + len += ngtcp2_put_uvarintlen(hd->tokenlen) + hd->tokenlen; } if (outlen < len) { @@ -422,14 +418,14 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_long(uint8_t *out, size_t outlen, } if (hd->type == NGTCP2_PKT_INITIAL) { - p = ngtcp2_put_varint(p, hd->token.len); - if (hd->token.len) { - p = ngtcp2_cpymem(p, hd->token.base, hd->token.len); + p = ngtcp2_put_uvarint(p, hd->tokenlen); + if (hd->tokenlen) { + p = ngtcp2_cpymem(p, hd->token, hd->tokenlen); } } if (hd->type != NGTCP2_PKT_RETRY) { - p = ngtcp2_put_varint30(p, (uint32_t)hd->len); + p = ngtcp2_put_uvarint30(p, (uint32_t)hd->len); p = ngtcp2_put_pkt_num(p, hd->pkt_num, hd->pkt_numlen); } @@ -475,15 +471,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, uint8_t type; if (payloadlen == 0) { - return 0; + return NGTCP2_ERR_FRAME_ENCODING; } type = payload[0]; switch (type) { case NGTCP2_FRAME_PADDING: - return (ngtcp2_ssize)ngtcp2_pkt_decode_padding_frame(&dest->padding, - payload, payloadlen); + return ngtcp2_pkt_decode_padding_frame(&dest->padding, payload, payloadlen); case NGTCP2_FRAME_RESET_STREAM: return ngtcp2_pkt_decode_reset_stream_frame(&dest->reset_stream, payload, payloadlen); @@ -529,7 +524,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, return ngtcp2_pkt_decode_path_response_frame(&dest->path_response, payload, payloadlen); case NGTCP2_FRAME_CRYPTO: - return ngtcp2_pkt_decode_crypto_frame(&dest->crypto, payload, payloadlen); + return ngtcp2_pkt_decode_crypto_frame(&dest->stream, payload, payloadlen); case NGTCP2_FRAME_NEW_TOKEN: return ngtcp2_pkt_decode_new_token_frame(&dest->new_token, payload, payloadlen); @@ -544,9 +539,15 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, return ngtcp2_pkt_decode_datagram_frame(&dest->datagram, payload, payloadlen); default: - if (has_mask(type, NGTCP2_FRAME_STREAM)) { + if ((type & ~(NGTCP2_FRAME_STREAM - 1)) == NGTCP2_FRAME_STREAM) { return ngtcp2_pkt_decode_stream_frame(&dest->stream, payload, payloadlen); } + + /* For frame types > 0xff, use ngtcp2_get_uvarintlen and + ngtcp2_get_uvarint to get a frame type, and then switch over + it. Verify that payloadlen >= ngtcp2_get_uvarintlen(payload) + before calling ngtcp2_get_uvarint(payload). */ + return NGTCP2_ERR_FRAME_ENCODING; } } @@ -570,7 +571,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -585,7 +586,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, return NGTCP2_ERR_FRAME_ENCODING; } - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -601,14 +602,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, return NGTCP2_ERR_FRAME_ENCODING; } - ndatalen = ngtcp2_get_varint_len(p); + ndatalen = ngtcp2_get_uvarintlen(p); len += ndatalen - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&ndatalen, p); + /* p = */ ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -623,12 +624,10 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, dest->type = NGTCP2_FRAME_STREAM; dest->flags = (uint8_t)(type & ~NGTCP2_FRAME_STREAM); dest->fin = (type & NGTCP2_STREAM_FIN_BIT) != 0; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); if (type & NGTCP2_STREAM_OFF_BIT) { - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->offset, p); } else { dest->offset = 0; } @@ -656,12 +655,12 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, const uint8_t *payload, size_t payloadlen) { - size_t num_blks, max_num_blks; - size_t nnum_blks; + size_t rangecnt, max_rangecnt; + size_t nrangecnt; size_t len = 1 + 1 + 1 + 1 + 1; const uint8_t *p; size_t i, j; - ngtcp2_ack_blk *blk; + ngtcp2_ack_range *range; size_t n; uint8_t type; uint64_t vi; @@ -675,7 +674,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p = payload + 1; /* Largest Acknowledged */ - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -685,7 +684,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p += n; /* ACK Delay */ - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -694,26 +693,24 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p += n; - /* ACK Block Count */ - nnum_blks = ngtcp2_get_varint_len(p); - len += nnum_blks - 1; + /* ACK Range Count */ + nrangecnt = ngtcp2_get_uvarintlen(p); + len += nrangecnt - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&nnum_blks, p); + p = ngtcp2_get_uvarint(&vi, p); if (vi > SIZE_MAX / (1 + 1) || payloadlen - len < vi * (1 + 1)) { return NGTCP2_ERR_FRAME_ENCODING; } - num_blks = (size_t)vi; - len += num_blks * (1 + 1); - - p += nnum_blks; + rangecnt = (size_t)vi; + len += rangecnt * (1 + 1); - /* First ACK Block */ - n = ngtcp2_get_varint_len(p); + /* First ACK Range */ + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -722,10 +719,10 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, p += n; - for (i = 0; i < num_blks; ++i) { - /* Gap, and Additional ACK Block */ + for (i = 0; i < rangecnt; ++i) { + /* Gap, and Additional ACK Range */ for (j = 0; j < 2; ++j) { - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -743,7 +740,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, } for (i = 0; i < 3; ++i) { - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -754,44 +751,34 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, } } - /* TODO We might not decode all blocks. It could be very large. */ - max_num_blks = ngtcp2_min(NGTCP2_MAX_ACK_BLKS, num_blks); + /* TODO We might not decode all ranges. It could be very large. */ + max_rangecnt = ngtcp2_min(NGTCP2_MAX_ACK_RANGES, rangecnt); p = payload + 1; dest->type = type; - dest->largest_ack = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->ack_delay = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_varint(&dest->largest_ack, p); + p = ngtcp2_get_uvarint(&dest->ack_delay, p); /* This value will be assigned in the upper layer. */ dest->ack_delay_unscaled = 0; - p += n; - dest->num_blks = max_num_blks; - p += nnum_blks; - dest->first_ack_blklen = ngtcp2_get_varint(&n, p); - p += n; + dest->rangecnt = max_rangecnt; + p += nrangecnt; + p = ngtcp2_get_uvarint(&dest->first_ack_range, p); - for (i = 0; i < max_num_blks; ++i) { - blk = &dest->blks[i]; - blk->gap = ngtcp2_get_varint(&n, p); - p += n; - blk->blklen = ngtcp2_get_varint(&n, p); - p += n; + for (i = 0; i < max_rangecnt; ++i) { + range = &dest->ranges[i]; + p = ngtcp2_get_uvarint(&range->gap, p); + p = ngtcp2_get_uvarint(&range->len, p); } - for (i = max_num_blks; i < num_blks; ++i) { - p += ngtcp2_get_varint_len(p); - p += ngtcp2_get_varint_len(p); + for (i = max_rangecnt; i < rangecnt; ++i) { + p += ngtcp2_get_uvarintlen(p); + p += ngtcp2_get_uvarintlen(p); } if (type == NGTCP2_FRAME_ACK_ECN) { - dest->ecn.ect0 = ngtcp2_get_varint(&n, p); - p += n; - - dest->ecn.ect1 = ngtcp2_get_varint(&n, p); - p += n; - - dest->ecn.ce = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->ecn.ect0, p); + p = ngtcp2_get_uvarint(&dest->ecn.ect1, p); + p = ngtcp2_get_uvarint(&dest->ecn.ce, p); } assert((size_t)(p - payload) == len); @@ -799,9 +786,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, return (ngtcp2_ssize)len; } -size_t ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, - const uint8_t *payload, - size_t payloadlen) { +ngtcp2_ssize ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, + const uint8_t *payload, + size_t payloadlen) { const uint8_t *p, *ep; assert(payloadlen > 0); @@ -815,7 +802,7 @@ size_t ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, dest->type = NGTCP2_FRAME_PADDING; dest->len = (size_t)(p - payload); - return dest->len; + return (ngtcp2_ssize)dest->len; } ngtcp2_ssize ngtcp2_pkt_decode_reset_stream_frame(ngtcp2_reset_stream *dest, @@ -831,19 +818,19 @@ ngtcp2_ssize ngtcp2_pkt_decode_reset_stream_frame(ngtcp2_reset_stream *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -852,12 +839,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_reset_stream_frame(ngtcp2_reset_stream *dest, p = payload + 1; dest->type = NGTCP2_FRAME_RESET_STREAM; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->app_error_code = ngtcp2_get_varint(&n, p); - p += n; - dest->final_size = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->app_error_code, p); + p = ngtcp2_get_uvarint(&dest->final_size, p); assert((size_t)(p - payload) == len); @@ -882,7 +866,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -893,7 +877,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( if (type == NGTCP2_FRAME_CONNECTION_CLOSE) { ++len; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -902,13 +886,13 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( p += n; } - nreasonlen = ngtcp2_get_varint_len(p); + nreasonlen = ngtcp2_get_uvarintlen(p); len += nreasonlen - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&nreasonlen, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -918,11 +902,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( p = payload + 1; dest->type = type; - dest->error_code = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->error_code, p); if (type == NGTCP2_FRAME_CONNECTION_CLOSE) { - dest->frame_type = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->frame_type, p); } else { dest->frame_type = 0; } @@ -953,7 +935,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_data_frame(ngtcp2_max_data *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -961,8 +943,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_data_frame(ngtcp2_max_data *dest, } dest->type = NGTCP2_FRAME_MAX_DATA; - dest->max_data = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->max_data, p); assert((size_t)(p - payload) == len); @@ -981,7 +962,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_stream_data_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -990,7 +971,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_stream_data_frame( p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1000,10 +981,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_stream_data_frame( p = payload + 1; dest->type = NGTCP2_FRAME_MAX_STREAM_DATA; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->max_stream_data = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->max_stream_data, p); assert((size_t)(p - payload) == len); @@ -1023,7 +1002,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_streams_frame(ngtcp2_max_streams *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1031,8 +1010,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_streams_frame(ngtcp2_max_streams *dest, } dest->type = payload[0]; - dest->max_streams = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->max_streams, p); assert((size_t)(p - payload) == len); @@ -1062,7 +1040,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_data_blocked_frame(ngtcp2_data_blocked *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1070,8 +1048,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_data_blocked_frame(ngtcp2_data_blocked *dest, } dest->type = NGTCP2_FRAME_DATA_BLOCKED; - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->offset, p); assert((size_t)(p - payload) == len); @@ -1092,7 +1069,7 @@ ngtcp2_pkt_decode_stream_data_blocked_frame(ngtcp2_stream_data_blocked *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1101,7 +1078,7 @@ ngtcp2_pkt_decode_stream_data_blocked_frame(ngtcp2_stream_data_blocked *dest, p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1111,10 +1088,8 @@ ngtcp2_pkt_decode_stream_data_blocked_frame(ngtcp2_stream_data_blocked *dest, p = payload + 1; dest->type = NGTCP2_FRAME_STREAM_DATA_BLOCKED; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->offset, p); assert((size_t)(p - payload) == len); @@ -1133,7 +1108,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_streams_blocked_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1141,8 +1116,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_streams_blocked_frame( } dest->type = payload[0]; - dest->max_streams = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->max_streams, p); assert((size_t)(p - payload) == len); @@ -1162,7 +1136,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame( p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -1170,7 +1144,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame( p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -1191,14 +1165,13 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame( p = payload + 1; dest->type = NGTCP2_FRAME_NEW_CONNECTION_ID; - dest->seq = ngtcp2_get_varint(&n, p); - p += n; - dest->retire_prior_to = ngtcp2_get_varint(&n, p); - p += n + 1; + p = ngtcp2_get_uvarint(&dest->seq, p); + p = ngtcp2_get_uvarint(&dest->retire_prior_to, p); + ++p; ngtcp2_cid_init(&dest->cid, p, cil); p += cil; - memcpy(dest->stateless_reset_token, p, NGTCP2_STATELESS_RESET_TOKENLEN); - p += NGTCP2_STATELESS_RESET_TOKENLEN; + p = ngtcp2_get_bytes(dest->stateless_reset_token, p, + NGTCP2_STATELESS_RESET_TOKENLEN); assert((size_t)(p - payload) == len); @@ -1218,14 +1191,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_stop_sending_frame(ngtcp2_stop_sending *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } p += n; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1235,10 +1208,8 @@ ngtcp2_ssize ngtcp2_pkt_decode_stop_sending_frame(ngtcp2_stop_sending *dest, p = payload + 1; dest->type = NGTCP2_FRAME_STOP_SENDING; - dest->stream_id = (int64_t)ngtcp2_get_varint(&n, p); - p += n; - dest->app_error_code = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_varint(&dest->stream_id, p); + p = ngtcp2_get_uvarint(&dest->app_error_code, p); assert((size_t)(p - payload) == len); @@ -1287,7 +1258,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_response_frame(ngtcp2_path_response *dest, return (ngtcp2_ssize)len; } -ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, +ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_stream *dest, const uint8_t *payload, size_t payloadlen) { size_t len = 1 + 1 + 1; @@ -1303,7 +1274,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1312,14 +1283,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, p += n; - ndatalen = ngtcp2_get_varint_len(p); + ndatalen = ngtcp2_get_uvarintlen(p); len += ndatalen - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&ndatalen, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -1330,8 +1301,10 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, p = payload + 1; dest->type = NGTCP2_FRAME_CRYPTO; - dest->offset = ngtcp2_get_varint(&n, p); - p += n; + dest->flags = 0; + dest->fin = 0; + dest->stream_id = 0; + p = ngtcp2_get_uvarint(&dest->offset, p); dest->data[0].len = datalen; p += ndatalen; if (dest->data[0].len) { @@ -1363,14 +1336,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_token_frame(ngtcp2_new_token *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -1378,10 +1351,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_token_frame(ngtcp2_new_token *dest, len += datalen; dest->type = NGTCP2_FRAME_NEW_TOKEN; - dest->token.len = datalen; - p += n; - dest->token.base = (uint8_t *)p; - p += dest->token.len; + dest->tokenlen = datalen; + dest->token = (uint8_t *)p; + p += dest->tokenlen; assert((size_t)(p - payload) == len); @@ -1402,7 +1374,7 @@ ngtcp2_pkt_decode_retire_connection_id_frame(ngtcp2_retire_connection_id *dest, p = payload + 1; - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { @@ -1410,8 +1382,7 @@ ngtcp2_pkt_decode_retire_connection_id_frame(ngtcp2_retire_connection_id *dest, } dest->type = NGTCP2_FRAME_RETIRE_CONNECTION_ID; - dest->seq = ngtcp2_get_varint(&n, p); - p += n; + p = ngtcp2_get_uvarint(&dest->seq, p); assert((size_t)(p - payload) == len); @@ -1457,14 +1428,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest, return NGTCP2_ERR_FRAME_ENCODING; } - n = ngtcp2_get_varint_len(p); + n = ngtcp2_get_uvarintlen(p); len += n - 1; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; } - vi = ngtcp2_get_varint(&n, p); + p = ngtcp2_get_uvarint(&vi, p); if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } @@ -1473,8 +1444,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest, len += datalen; break; default: - assert(0); - abort(); + ngtcp2_unreachable(); } dest->type = type; @@ -1482,19 +1452,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_datagram_frame(ngtcp2_datagram *dest, if (datalen == 0) { dest->datacnt = 0; dest->data = NULL; - - if (type == NGTCP2_FRAME_DATAGRAM_LEN) { - p += n; - } } else { dest->datacnt = 1; dest->data = dest->rdata; dest->rdata[0].len = datalen; - if (type == NGTCP2_FRAME_DATAGRAM_LEN) { - p += n; - } - dest->rdata[0].base = (uint8_t *)p; p += datalen; } @@ -1551,7 +1513,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_frame(uint8_t *out, size_t outlen, return ngtcp2_pkt_encode_path_response_frame(out, outlen, &fr->path_response); case NGTCP2_FRAME_CRYPTO: - return ngtcp2_pkt_encode_crypto_frame(out, outlen, &fr->crypto); + return ngtcp2_pkt_encode_crypto_frame(out, outlen, &fr->stream); case NGTCP2_FRAME_NEW_TOKEN: return ngtcp2_pkt_encode_new_token_frame(out, outlen, &fr->new_token); case NGTCP2_FRAME_RETIRE_CONNECTION_ID: @@ -1582,16 +1544,16 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, if (fr->offset) { flags |= NGTCP2_STREAM_OFF_BIT; - len += ngtcp2_put_varint_len(fr->offset); + len += ngtcp2_put_uvarintlen(fr->offset); } - len += ngtcp2_put_varint_len((uint64_t)fr->stream_id); + len += ngtcp2_put_uvarintlen((uint64_t)fr->stream_id); for (i = 0; i < fr->datacnt; ++i) { datalen += fr->data[i].len; } - len += ngtcp2_put_varint_len(datalen); + len += ngtcp2_put_uvarintlen(datalen); len += datalen; if (outlen < len) { @@ -1604,13 +1566,13 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, fr->flags = flags; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); if (fr->offset) { - p = ngtcp2_put_varint(p, fr->offset); + p = ngtcp2_put_uvarint(p, fr->offset); } - p = ngtcp2_put_varint(p, datalen); + p = ngtcp2_put_uvarint(p, datalen); for (i = 0; i < fr->datacnt; ++i) { assert(fr->data[i].len); @@ -1625,24 +1587,24 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_ack_frame(uint8_t *out, size_t outlen, ngtcp2_ack *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->largest_ack) + - ngtcp2_put_varint_len(fr->ack_delay) + - ngtcp2_put_varint_len(fr->num_blks) + - ngtcp2_put_varint_len(fr->first_ack_blklen); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->largest_ack) + + ngtcp2_put_uvarintlen(fr->ack_delay) + + ngtcp2_put_uvarintlen(fr->rangecnt) + + ngtcp2_put_uvarintlen(fr->first_ack_range); uint8_t *p; size_t i; - const ngtcp2_ack_blk *blk; + const ngtcp2_ack_range *range; - for (i = 0; i < fr->num_blks; ++i) { - blk = &fr->blks[i]; - len += ngtcp2_put_varint_len(blk->gap); - len += ngtcp2_put_varint_len(blk->blklen); + for (i = 0; i < fr->rangecnt; ++i) { + range = &fr->ranges[i]; + len += ngtcp2_put_uvarintlen(range->gap); + len += ngtcp2_put_uvarintlen(range->len); } if (fr->type == NGTCP2_FRAME_ACK_ECN) { - len += ngtcp2_put_varint_len(fr->ecn.ect0) + - ngtcp2_put_varint_len(fr->ecn.ect1) + - ngtcp2_put_varint_len(fr->ecn.ce); + len += ngtcp2_put_uvarintlen(fr->ecn.ect0) + + ngtcp2_put_uvarintlen(fr->ecn.ect1) + + ngtcp2_put_uvarintlen(fr->ecn.ce); } if (outlen < len) { @@ -1651,22 +1613,22 @@ ngtcp2_ssize ngtcp2_pkt_encode_ack_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, (uint64_t)fr->largest_ack); - p = ngtcp2_put_varint(p, fr->ack_delay); - p = ngtcp2_put_varint(p, fr->num_blks); - p = ngtcp2_put_varint(p, fr->first_ack_blklen); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, (uint64_t)fr->largest_ack); + p = ngtcp2_put_uvarint(p, fr->ack_delay); + p = ngtcp2_put_uvarint(p, fr->rangecnt); + p = ngtcp2_put_uvarint(p, fr->first_ack_range); - for (i = 0; i < fr->num_blks; ++i) { - blk = &fr->blks[i]; - p = ngtcp2_put_varint(p, blk->gap); - p = ngtcp2_put_varint(p, blk->blklen); + for (i = 0; i < fr->rangecnt; ++i) { + range = &fr->ranges[i]; + p = ngtcp2_put_uvarint(p, range->gap); + p = ngtcp2_put_uvarint(p, range->len); } if (fr->type == NGTCP2_FRAME_ACK_ECN) { - p = ngtcp2_put_varint(p, fr->ecn.ect0); - p = ngtcp2_put_varint(p, fr->ecn.ect1); - p = ngtcp2_put_varint(p, fr->ecn.ce); + p = ngtcp2_put_uvarint(p, fr->ecn.ect0); + p = ngtcp2_put_uvarint(p, fr->ecn.ect1); + p = ngtcp2_put_uvarint(p, fr->ecn.ce); } assert((size_t)(p - out) == len); @@ -1688,9 +1650,9 @@ ngtcp2_ssize ngtcp2_pkt_encode_padding_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_reset_stream_frame(uint8_t *out, size_t outlen, const ngtcp2_reset_stream *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->app_error_code) + - ngtcp2_put_varint_len(fr->final_size); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->app_error_code) + + ngtcp2_put_uvarintlen(fr->final_size); uint8_t *p; if (outlen < len) { @@ -1700,9 +1662,9 @@ ngtcp2_pkt_encode_reset_stream_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_RESET_STREAM; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->app_error_code); - p = ngtcp2_put_varint(p, fr->final_size); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->app_error_code); + p = ngtcp2_put_uvarint(p, fr->final_size); assert((size_t)(p - out) == len); @@ -1712,11 +1674,11 @@ ngtcp2_pkt_encode_reset_stream_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_connection_close_frame(uint8_t *out, size_t outlen, const ngtcp2_connection_close *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->error_code) + + size_t len = 1 + ngtcp2_put_uvarintlen(fr->error_code) + (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE - ? ngtcp2_put_varint_len(fr->frame_type) + ? ngtcp2_put_uvarintlen(fr->frame_type) : 0) + - ngtcp2_put_varint_len(fr->reasonlen) + fr->reasonlen; + ngtcp2_put_uvarintlen(fr->reasonlen) + fr->reasonlen; uint8_t *p; if (outlen < len) { @@ -1725,12 +1687,12 @@ ngtcp2_pkt_encode_connection_close_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, fr->error_code); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, fr->error_code); if (fr->type == NGTCP2_FRAME_CONNECTION_CLOSE) { - p = ngtcp2_put_varint(p, fr->frame_type); + p = ngtcp2_put_uvarint(p, fr->frame_type); } - p = ngtcp2_put_varint(p, fr->reasonlen); + p = ngtcp2_put_uvarint(p, fr->reasonlen); if (fr->reasonlen) { p = ngtcp2_cpymem(p, fr->reason, fr->reasonlen); } @@ -1742,7 +1704,7 @@ ngtcp2_pkt_encode_connection_close_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_max_data_frame(uint8_t *out, size_t outlen, const ngtcp2_max_data *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->max_data); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->max_data); uint8_t *p; if (outlen < len) { @@ -1752,7 +1714,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_max_data_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_MAX_DATA; - p = ngtcp2_put_varint(p, fr->max_data); + p = ngtcp2_put_uvarint(p, fr->max_data); assert((size_t)(p - out) == len); @@ -1762,8 +1724,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_max_data_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_max_stream_data_frame(uint8_t *out, size_t outlen, const ngtcp2_max_stream_data *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->max_stream_data); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->max_stream_data); uint8_t *p; if (outlen < len) { @@ -1773,8 +1735,8 @@ ngtcp2_pkt_encode_max_stream_data_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_MAX_STREAM_DATA; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->max_stream_data); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->max_stream_data); assert((size_t)(p - out) == len); @@ -1783,7 +1745,7 @@ ngtcp2_pkt_encode_max_stream_data_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_max_streams_frame(uint8_t *out, size_t outlen, const ngtcp2_max_streams *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->max_streams); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->max_streams); uint8_t *p; if (outlen < len) { @@ -1792,8 +1754,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_max_streams_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, fr->max_streams); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, fr->max_streams); assert((size_t)(p - out) == len); @@ -1816,7 +1778,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_ping_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_data_blocked_frame(uint8_t *out, size_t outlen, const ngtcp2_data_blocked *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->offset); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->offset); uint8_t *p; if (outlen < len) { @@ -1826,7 +1788,7 @@ ngtcp2_pkt_encode_data_blocked_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_DATA_BLOCKED; - p = ngtcp2_put_varint(p, fr->offset); + p = ngtcp2_put_uvarint(p, fr->offset); assert((size_t)(p - out) == len); @@ -1835,8 +1797,8 @@ ngtcp2_pkt_encode_data_blocked_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_stream_data_blocked_frame( uint8_t *out, size_t outlen, const ngtcp2_stream_data_blocked *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->offset); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->offset); uint8_t *p; if (outlen < len) { @@ -1846,8 +1808,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_data_blocked_frame( p = out; *p++ = NGTCP2_FRAME_STREAM_DATA_BLOCKED; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->offset); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->offset); assert((size_t)(p - out) == len); @@ -1857,7 +1819,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_stream_data_blocked_frame( ngtcp2_ssize ngtcp2_pkt_encode_streams_blocked_frame(uint8_t *out, size_t outlen, const ngtcp2_streams_blocked *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->max_streams); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->max_streams); uint8_t *p; if (outlen < len) { @@ -1866,8 +1828,8 @@ ngtcp2_pkt_encode_streams_blocked_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; - p = ngtcp2_put_varint(p, fr->max_streams); + *p++ = (uint8_t)fr->type; + p = ngtcp2_put_uvarint(p, fr->max_streams); assert((size_t)(p - out) == len); @@ -1877,8 +1839,8 @@ ngtcp2_pkt_encode_streams_blocked_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, const ngtcp2_new_connection_id *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->seq) + - ngtcp2_put_varint_len(fr->retire_prior_to) + 1 + + size_t len = 1 + ngtcp2_put_uvarintlen(fr->seq) + + ngtcp2_put_uvarintlen(fr->retire_prior_to) + 1 + fr->cid.datalen + NGTCP2_STATELESS_RESET_TOKENLEN; uint8_t *p; @@ -1889,8 +1851,8 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_NEW_CONNECTION_ID; - p = ngtcp2_put_varint(p, fr->seq); - p = ngtcp2_put_varint(p, fr->retire_prior_to); + p = ngtcp2_put_uvarint(p, fr->seq); + p = ngtcp2_put_uvarint(p, fr->retire_prior_to); *p++ = (uint8_t)fr->cid.datalen; p = ngtcp2_cpymem(p, fr->cid.data, fr->cid.datalen); p = ngtcp2_cpymem(p, fr->stateless_reset_token, @@ -1904,8 +1866,8 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_stop_sending_frame(uint8_t *out, size_t outlen, const ngtcp2_stop_sending *fr) { - size_t len = 1 + ngtcp2_put_varint_len((uint64_t)fr->stream_id) + - ngtcp2_put_varint_len(fr->app_error_code); + size_t len = 1 + ngtcp2_put_uvarintlen((uint64_t)fr->stream_id) + + ngtcp2_put_uvarintlen(fr->app_error_code); uint8_t *p; if (outlen < len) { @@ -1915,8 +1877,8 @@ ngtcp2_pkt_encode_stop_sending_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_STOP_SENDING; - p = ngtcp2_put_varint(p, (uint64_t)fr->stream_id); - p = ngtcp2_put_varint(p, fr->app_error_code); + p = ngtcp2_put_uvarint(p, (uint64_t)fr->stream_id); + p = ngtcp2_put_uvarint(p, fr->app_error_code); assert((size_t)(p - out) == len); @@ -1964,19 +1926,19 @@ ngtcp2_pkt_encode_path_response_frame(uint8_t *out, size_t outlen, } ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, - const ngtcp2_crypto *fr) { + const ngtcp2_stream *fr) { size_t len = 1; uint8_t *p; size_t i; size_t datalen = 0; - len += ngtcp2_put_varint_len(fr->offset); + len += ngtcp2_put_uvarintlen(fr->offset); for (i = 0; i < fr->datacnt; ++i) { datalen += fr->data[i].len; } - len += ngtcp2_put_varint_len(datalen); + len += ngtcp2_put_uvarintlen(datalen); len += datalen; if (outlen < len) { @@ -1987,8 +1949,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, *p++ = NGTCP2_FRAME_CRYPTO; - p = ngtcp2_put_varint(p, fr->offset); - p = ngtcp2_put_varint(p, datalen); + p = ngtcp2_put_uvarint(p, fr->offset); + p = ngtcp2_put_uvarint(p, datalen); for (i = 0; i < fr->datacnt; ++i) { assert(fr->data[i].base); @@ -2002,10 +1964,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_new_token_frame(uint8_t *out, size_t outlen, const ngtcp2_new_token *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->token.len) + fr->token.len; + size_t len = 1 + ngtcp2_put_uvarintlen(fr->tokenlen) + fr->tokenlen; uint8_t *p; - assert(fr->token.len); + assert(fr->tokenlen); if (outlen < len) { return NGTCP2_ERR_NOBUF; @@ -2015,8 +1977,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_new_token_frame(uint8_t *out, size_t outlen, *p++ = NGTCP2_FRAME_NEW_TOKEN; - p = ngtcp2_put_varint(p, fr->token.len); - p = ngtcp2_cpymem(p, fr->token.base, fr->token.len); + p = ngtcp2_put_uvarint(p, fr->tokenlen); + p = ngtcp2_cpymem(p, fr->token, fr->tokenlen); assert((size_t)(p - out) == len); @@ -2025,7 +1987,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_new_token_frame(uint8_t *out, size_t outlen, ngtcp2_ssize ngtcp2_pkt_encode_retire_connection_id_frame( uint8_t *out, size_t outlen, const ngtcp2_retire_connection_id *fr) { - size_t len = 1 + ngtcp2_put_varint_len(fr->seq); + size_t len = 1 + ngtcp2_put_uvarintlen(fr->seq); uint8_t *p; if (outlen < len) { @@ -2036,7 +1998,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_retire_connection_id_frame( *p++ = NGTCP2_FRAME_RETIRE_CONNECTION_ID; - p = ngtcp2_put_varint(p, fr->seq); + p = ngtcp2_put_uvarint(p, fr->seq); assert((size_t)(p - out) == len); @@ -2062,7 +2024,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_datagram_frame(uint8_t *out, size_t outlen, uint64_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt); uint64_t len = 1 + - (fr->type == NGTCP2_FRAME_DATAGRAM ? 0 : ngtcp2_put_varint_len(datalen)) + + (fr->type == NGTCP2_FRAME_DATAGRAM ? 0 : ngtcp2_put_uvarintlen(datalen)) + datalen; uint8_t *p; size_t i; @@ -2076,9 +2038,9 @@ ngtcp2_ssize ngtcp2_pkt_encode_datagram_frame(uint8_t *out, size_t outlen, p = out; - *p++ = fr->type; + *p++ = (uint8_t)fr->type; if (fr->type == NGTCP2_FRAME_DATAGRAM_LEN) { - p = ngtcp2_put_varint(p, datalen); + p = ngtcp2_put_uvarint(p, datalen); } for (i = 0; i < fr->datacnt; ++i) { @@ -2109,7 +2071,7 @@ ngtcp2_ssize ngtcp2_pkt_write_version_negotiation( p = dest; - *p++ = 0x80 | unused_random; + *p++ = 0xc0 | unused_random; p = ngtcp2_put_uint32be(p, 0); *p++ = (uint8_t)dcidlen; if (dcidlen) { @@ -2136,8 +2098,8 @@ size_t ngtcp2_pkt_decode_version_negotiation(uint32_t *dest, assert((payloadlen % sizeof(uint32_t)) == 0); - for (; payload != end; payload += sizeof(uint32_t)) { - *dest++ = ngtcp2_get_uint32(payload); + for (; payload != end;) { + payload = ngtcp2_get_uint32(dest++, payload); } return payloadlen / sizeof(uint32_t); @@ -2169,9 +2131,9 @@ int ngtcp2_pkt_decode_retry(ngtcp2_pkt_retry *dest, const uint8_t *payload, return NGTCP2_ERR_INVALID_ARGUMENT; } - dest->token.base = (uint8_t *)payload; - dest->token.len = (size_t)(payloadlen - NGTCP2_RETRY_TAGLEN); - ngtcp2_cpymem(dest->tag, payload + dest->token.len, NGTCP2_RETRY_TAGLEN); + dest->token = (uint8_t *)payload; + dest->tokenlen = (size_t)(payloadlen - NGTCP2_RETRY_TAGLEN); + ngtcp2_cpymem(dest->tag, payload + dest->tokenlen, NGTCP2_RETRY_TAGLEN); return 0; } @@ -2194,28 +2156,36 @@ int64_t ngtcp2_pkt_adjust_pkt_num(int64_t max_pkt_num, int64_t pkt_num, return cand; } -int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr) { +int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr, int64_t min_pkt_num) { int64_t largest_ack = fr->largest_ack; size_t i; - if (largest_ack < (int64_t)fr->first_ack_blklen) { + if (largest_ack < (int64_t)fr->first_ack_range) { return NGTCP2_ERR_ACK_FRAME; } - largest_ack -= (int64_t)fr->first_ack_blklen; + largest_ack -= (int64_t)fr->first_ack_range; + + if (largest_ack < min_pkt_num) { + return NGTCP2_ERR_PROTO; + } - for (i = 0; i < fr->num_blks; ++i) { - if (largest_ack < (int64_t)fr->blks[i].gap + 2) { + for (i = 0; i < fr->rangecnt; ++i) { + if (largest_ack < (int64_t)fr->ranges[i].gap + 2) { return NGTCP2_ERR_ACK_FRAME; } - largest_ack -= (int64_t)fr->blks[i].gap + 2; + largest_ack -= (int64_t)fr->ranges[i].gap + 2; - if (largest_ack < (int64_t)fr->blks[i].blklen) { + if (largest_ack < (int64_t)fr->ranges[i].len) { return NGTCP2_ERR_ACK_FRAME; } - largest_ack -= (int64_t)fr->blks[i].blklen; + largest_ack -= (int64_t)fr->ranges[i].len; + + if (largest_ack < min_pkt_num) { + return NGTCP2_ERR_PROTO; + } } return 0; @@ -2285,16 +2255,14 @@ ngtcp2_ssize ngtcp2_pkt_write_retry( switch (version) { case NGTCP2_PROTO_VER_V1: + default: nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1; noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2; + noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } /* OpenSSL does not like NULL plaintext. */ @@ -2377,16 +2345,14 @@ int ngtcp2_pkt_verify_retry_tag(uint32_t version, const ngtcp2_pkt_retry *retry, switch (version) { case NGTCP2_PROTO_VER_V1: + default: nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V1; noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1; break; - case NGTCP2_PROTO_VER_V2_DRAFT: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_V2_DRAFT) - 1; + case NGTCP2_PROTO_VER_V2: + nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_V2; + noncelen = sizeof(NGTCP2_RETRY_NONCE_V2) - 1; break; - default: - nonce = (const uint8_t *)NGTCP2_RETRY_NONCE_DRAFT; - noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1; } /* OpenSSL does not like NULL plaintext. */ @@ -2405,8 +2371,8 @@ int ngtcp2_pkt_verify_retry_tag(uint32_t version, const ngtcp2_pkt_retry *retry, size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, uint64_t len, size_t left) { - size_t n = 1 /* type */ + ngtcp2_put_varint_len((uint64_t)stream_id) + - (offset ? ngtcp2_put_varint_len(offset) : 0); + size_t n = 1 /* type */ + ngtcp2_put_uvarintlen((uint64_t)stream_id) + + (offset ? ngtcp2_put_uvarintlen(offset) : 0); if (left <= n) { return (size_t)-1; @@ -2436,7 +2402,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, } size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { - size_t n = 1 /* type */ + ngtcp2_put_varint_len(offset); + size_t n = 1 /* type */ + ngtcp2_put_uvarintlen(offset); /* CRYPTO frame must contain nonzero length data. Return -1 if there is no space to write crypto data. */ @@ -2468,17 +2434,16 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { } size_t ngtcp2_pkt_datagram_framelen(size_t len) { - return 1 /* type */ + ngtcp2_put_varint_len(len) + len; + return 1 /* type */ + ngtcp2_put_uvarintlen(len) + len; } int ngtcp2_is_supported_version(uint32_t version) { switch (version) { case NGTCP2_PROTO_VER_V1: - case NGTCP2_PROTO_VER_V2_DRAFT: + case NGTCP2_PROTO_VER_V2: return 1; default: - return NGTCP2_PROTO_VER_DRAFT_MIN <= version && - version <= NGTCP2_PROTO_VER_DRAFT_MAX; + return 0; } } @@ -2491,15 +2456,15 @@ uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c) { uint8_t pkt_type = (uint8_t)((c & NGTCP2_LONG_TYPE_MASK) >> 4); switch (version) { - case NGTCP2_PROTO_VER_V2_DRAFT: + case NGTCP2_PROTO_VER_V2: switch (pkt_type) { - case NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT: + case NGTCP2_PKT_TYPE_INITIAL_V2: return NGTCP2_PKT_INITIAL; - case NGTCP2_PKT_TYPE_0RTT_V2_DRAFT: + case NGTCP2_PKT_TYPE_0RTT_V2: return NGTCP2_PKT_0RTT; - case NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT: + case NGTCP2_PKT_TYPE_HANDSHAKE_V2: return NGTCP2_PKT_HANDSHAKE; - case NGTCP2_PKT_TYPE_RETRY_V2_DRAFT: + case NGTCP2_PKT_TYPE_RETRY_V2: return NGTCP2_PKT_RETRY; default: return 0; @@ -2509,8 +2474,6 @@ uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c) { return 0; } - /* QUIC v1 and draft versions share the same numeric packet - types. */ switch (pkt_type) { case NGTCP2_PKT_TYPE_INITIAL_V1: return NGTCP2_PKT_INITIAL; @@ -2528,27 +2491,24 @@ uint8_t ngtcp2_pkt_get_type_long(uint32_t version, uint8_t c) { uint8_t ngtcp2_pkt_versioned_type(uint32_t version, uint32_t pkt_type) { switch (version) { - case NGTCP2_PROTO_VER_V2_DRAFT: + case NGTCP2_PROTO_VER_V2: switch (pkt_type) { case NGTCP2_PKT_INITIAL: - return NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT; + return NGTCP2_PKT_TYPE_INITIAL_V2; case NGTCP2_PKT_0RTT: - return NGTCP2_PKT_TYPE_0RTT_V2_DRAFT; + return NGTCP2_PKT_TYPE_0RTT_V2; case NGTCP2_PKT_HANDSHAKE: - return NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT; + return NGTCP2_PKT_TYPE_HANDSHAKE_V2; case NGTCP2_PKT_RETRY: - return NGTCP2_PKT_TYPE_RETRY_V2_DRAFT; + return NGTCP2_PKT_TYPE_RETRY_V2; default: - assert(0); - abort(); + ngtcp2_unreachable(); } default: /* Assume that unsupported versions share the numeric long packet types with QUIC v1 in order to send a packet to elicit Version Negotiation packet. */ - /* QUIC v1 and draft versions share the same numeric packet - types. */ switch (pkt_type) { case NGTCP2_PKT_INITIAL: return NGTCP2_PKT_TYPE_INITIAL_V1; @@ -2559,8 +2519,7 @@ uint8_t ngtcp2_pkt_versioned_type(uint32_t version, uint32_t pkt_type) { case NGTCP2_PKT_RETRY: return NGTCP2_PKT_TYPE_RETRY_V1; default: - assert(0); - abort(); + ngtcp2_unreachable(); } } } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h index 2f7838a08a5625..b1bec97c31a08c 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h @@ -88,9 +88,9 @@ client stream ID. */ #define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3ffffffffffffffell) -/* NGTCP2_MAX_NUM_ACK_BLK is the maximum number of Additional ACK - blocks which this library can create, or decode. */ -#define NGTCP2_MAX_ACK_BLKS 32 +/* NGTCP2_MAX_NUM_ACK_RANGES is the maximum number of Additional ACK + ranges which this library can create, or decode. */ +#define NGTCP2_MAX_ACK_RANGES 32 /* NGTCP2_MAX_PKT_NUM is the maximum packet number. */ #define NGTCP2_MAX_PKT_NUM ((int64_t)((1ll << 62) - 1)) @@ -124,62 +124,67 @@ v1. */ #define NGTCP2_PKT_TYPE_RETRY_V1 0x3 -/* NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT is Initial long header packet type - for QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_INITIAL_V2_DRAFT 0x1 -/* NGTCP2_PKT_TYPE_0RTT_V2_DRAFT is 0RTT long header packet type for - QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_0RTT_V2_DRAFT 0x2 -/* NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT is Handshake long header packet - type for QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_HANDSHAKE_V2_DRAFT 0x3 -/* NGTCP2_PKT_TYPE_RETRY_V2_DRAFT is Retry long header packet type for - QUIC v2 draft. */ -#define NGTCP2_PKT_TYPE_RETRY_V2_DRAFT 0x0 +/* NGTCP2_PKT_TYPE_INITIAL_V2 is Initial long header packet type for + QUIC v2. */ +#define NGTCP2_PKT_TYPE_INITIAL_V2 0x1 +/* NGTCP2_PKT_TYPE_0RTT_V2 is 0RTT long header packet type for QUIC + v2. */ +#define NGTCP2_PKT_TYPE_0RTT_V2 0x2 +/* NGTCP2_PKT_TYPE_HANDSHAKE_V2 is Handshake long header packet type + for QUIC v2. */ +#define NGTCP2_PKT_TYPE_HANDSHAKE_V2 0x3 +/* NGTCP2_PKT_TYPE_RETRY_V2 is Retry long header packet type for QUIC + v2. */ +#define NGTCP2_PKT_TYPE_RETRY_V2 0x0 typedef struct ngtcp2_pkt_retry { ngtcp2_cid odcid; - ngtcp2_vec token; + uint8_t *token; + size_t tokenlen; uint8_t tag[NGTCP2_RETRY_TAGLEN]; } ngtcp2_pkt_retry; -typedef enum { - NGTCP2_FRAME_PADDING = 0x00, - NGTCP2_FRAME_PING = 0x01, - NGTCP2_FRAME_ACK = 0x02, - NGTCP2_FRAME_ACK_ECN = 0x03, - NGTCP2_FRAME_RESET_STREAM = 0x04, - NGTCP2_FRAME_STOP_SENDING = 0x05, - NGTCP2_FRAME_CRYPTO = 0x06, - NGTCP2_FRAME_NEW_TOKEN = 0x07, - NGTCP2_FRAME_STREAM = 0x08, - NGTCP2_FRAME_MAX_DATA = 0x10, - NGTCP2_FRAME_MAX_STREAM_DATA = 0x11, - NGTCP2_FRAME_MAX_STREAMS_BIDI = 0x12, - NGTCP2_FRAME_MAX_STREAMS_UNI = 0x13, - NGTCP2_FRAME_DATA_BLOCKED = 0x14, - NGTCP2_FRAME_STREAM_DATA_BLOCKED = 0x15, - NGTCP2_FRAME_STREAMS_BLOCKED_BIDI = 0x16, - NGTCP2_FRAME_STREAMS_BLOCKED_UNI = 0x17, - NGTCP2_FRAME_NEW_CONNECTION_ID = 0x18, - NGTCP2_FRAME_RETIRE_CONNECTION_ID = 0x19, - NGTCP2_FRAME_PATH_CHALLENGE = 0x1a, - NGTCP2_FRAME_PATH_RESPONSE = 0x1b, - NGTCP2_FRAME_CONNECTION_CLOSE = 0x1c, - NGTCP2_FRAME_CONNECTION_CLOSE_APP = 0x1d, - NGTCP2_FRAME_HANDSHAKE_DONE = 0x1e, - NGTCP2_FRAME_DATAGRAM = 0x30, - NGTCP2_FRAME_DATAGRAM_LEN = 0x31, -} ngtcp2_frame_type; - +#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 + +/* ngtcp2_stream represents STREAM and CRYPTO frames. */ typedef struct ngtcp2_stream { - uint8_t type; + uint64_t type; /** * flags of decoded STREAM frame. This gets ignored when encoding - * STREAM frame. + * STREAM frame. CRYPTO frame does not include this field, and must + * set it to 0. */ uint8_t flags; + /* CRYPTO frame does not include this field, and must set it to + 0. */ uint8_t fin; + /* CRYPTO frame does not include this field, and must set it to + 0. */ int64_t stream_id; uint64_t offset; /* datacnt is the number of elements that data contains. Although @@ -190,13 +195,13 @@ typedef struct ngtcp2_stream { ngtcp2_vec data[1]; } ngtcp2_stream; -typedef struct ngtcp2_ack_blk { +typedef struct ngtcp2_ack_range { uint64_t gap; - uint64_t blklen; -} ngtcp2_ack_blk; + uint64_t len; +} ngtcp2_ack_range; typedef struct ngtcp2_ack { - uint8_t type; + uint64_t type; int64_t largest_ack; uint64_t ack_delay; /** @@ -209,13 +214,13 @@ typedef struct ngtcp2_ack { uint64_t ect1; uint64_t ce; } ecn; - uint64_t first_ack_blklen; - size_t num_blks; - ngtcp2_ack_blk blks[1]; + uint64_t first_ack_range; + size_t rangecnt; + ngtcp2_ack_range ranges[1]; } ngtcp2_ack; typedef struct ngtcp2_padding { - uint8_t type; + uint64_t type; /** * The length of contiguous PADDING frames. */ @@ -223,14 +228,14 @@ typedef struct ngtcp2_padding { } ngtcp2_padding; typedef struct ngtcp2_reset_stream { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t app_error_code; uint64_t final_size; } ngtcp2_reset_stream; typedef struct ngtcp2_connection_close { - uint8_t type; + uint64_t type; uint64_t error_code; uint64_t frame_type; size_t reasonlen; @@ -238,7 +243,7 @@ typedef struct ngtcp2_connection_close { } ngtcp2_connection_close; typedef struct ngtcp2_max_data { - uint8_t type; + uint64_t type; /** * max_data is Maximum Data. */ @@ -246,38 +251,38 @@ typedef struct ngtcp2_max_data { } ngtcp2_max_data; typedef struct ngtcp2_max_stream_data { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t max_stream_data; } ngtcp2_max_stream_data; typedef struct ngtcp2_max_streams { - uint8_t type; + uint64_t type; uint64_t max_streams; } ngtcp2_max_streams; typedef struct ngtcp2_ping { - uint8_t type; + uint64_t type; } ngtcp2_ping; typedef struct ngtcp2_data_blocked { - uint8_t type; + uint64_t type; uint64_t offset; } ngtcp2_data_blocked; typedef struct ngtcp2_stream_data_blocked { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t offset; } ngtcp2_stream_data_blocked; typedef struct ngtcp2_streams_blocked { - uint8_t type; + uint64_t type; uint64_t max_streams; } ngtcp2_streams_blocked; typedef struct ngtcp2_new_connection_id { - uint8_t type; + uint64_t type; uint64_t seq; uint64_t retire_prior_to; ngtcp2_cid cid; @@ -285,48 +290,38 @@ typedef struct ngtcp2_new_connection_id { } ngtcp2_new_connection_id; typedef struct ngtcp2_stop_sending { - uint8_t type; + uint64_t type; int64_t stream_id; uint64_t app_error_code; } ngtcp2_stop_sending; typedef struct ngtcp2_path_challenge { - uint8_t type; + uint64_t type; uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; } ngtcp2_path_challenge; typedef struct ngtcp2_path_response { - uint8_t type; + uint64_t type; uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; } ngtcp2_path_response; -typedef struct ngtcp2_crypto { - uint8_t type; - uint64_t offset; - /* datacnt is the number of elements that data contains. Although - the length of data is 1 in this definition, the library may - allocate extra bytes to hold more elements. */ - size_t datacnt; - /* data is the array of ngtcp2_vec which references data. */ - ngtcp2_vec data[1]; -} ngtcp2_crypto; - typedef struct ngtcp2_new_token { - uint8_t type; - ngtcp2_vec token; + uint64_t type; + uint8_t *token; + size_t tokenlen; } ngtcp2_new_token; typedef struct ngtcp2_retire_connection_id { - uint8_t type; + uint64_t type; uint64_t seq; } ngtcp2_retire_connection_id; typedef struct ngtcp2_handshake_done { - uint8_t type; + uint64_t type; } ngtcp2_handshake_done; typedef struct ngtcp2_datagram { - uint8_t type; + uint64_t type; /* dgram_id is an opaque identifier chosen by an application. */ uint64_t dgram_id; /* datacnt is the number of elements that data contains. */ @@ -341,7 +336,7 @@ typedef struct ngtcp2_datagram { } ngtcp2_datagram; typedef union ngtcp2_frame { - uint8_t type; + uint64_t type; ngtcp2_stream stream; ngtcp2_ack ack; ngtcp2_padding padding; @@ -358,7 +353,6 @@ typedef union ngtcp2_frame { ngtcp2_stop_sending stop_sending; ngtcp2_path_challenge path_challenge; ngtcp2_path_response path_response; - ngtcp2_crypto crypto; ngtcp2_new_token new_token; ngtcp2_retire_connection_id retire_connection_id; ngtcp2_handshake_done handshake_done; @@ -454,7 +448,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_hd_short(uint8_t *out, size_t outlen, * frame if it succeeds, or one of the following negative error codes: * * :enum:`NGTCP2_ERR_FRAME_ENCODING` - * Frame is badly formatted; or frame type is unknown. + * Frame is badly formatted; or frame type is unknown; or + * |payloadlen| is 0. */ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload, size_t payloadlen); @@ -554,9 +549,9 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, * This function returns the exact number of bytes read to decode * PADDING frames. */ -size_t ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, - const uint8_t *payload, - size_t payloadlen); +ngtcp2_ssize ngtcp2_pkt_decode_padding_frame(ngtcp2_padding *dest, + const uint8_t *payload, + size_t payloadlen); /* * ngtcp2_pkt_decode_reset_stream_frame decodes RESET_STREAM frame @@ -639,11 +634,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_max_streams_frame(ngtcp2_max_streams *dest, * length |payloadlen|. The result is stored in the object pointed by * |dest|. PING frame must start at payload[0]. This function * finishes when it decodes one PING frame, and returns the exact - * number of bytes read to decode a frame if it succeeds, or one of - * the following negative error codes: - * - * NGTCP2_ERR_FRAME_ENCODING - * Payload is too short to include PING frame. + * number of bytes read to decode a frame. */ ngtcp2_ssize ngtcp2_pkt_decode_ping_frame(ngtcp2_ping *dest, const uint8_t *payload, @@ -773,7 +764,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_response_frame(ngtcp2_path_response *dest, * NGTCP2_ERR_FRAME_ENCODING * Payload is too short to include CRYPTO frame. */ -ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, +ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_stream *dest, const uint8_t *payload, size_t payloadlen); @@ -814,11 +805,7 @@ ngtcp2_pkt_decode_retire_connection_id_frame(ngtcp2_retire_connection_id *dest, * object pointed by |dest|. HANDSHAKE_DONE frame must start at * payload[0]. This function finishes when it decodes one * HANDSHAKE_DONE frame, and returns the exact number of bytes read to - * decode a frame if it succeeds, or one of the following negative - * error codes: - * - * NGTCP2_ERR_FRAME_ENCODING - * Payload is too short to include HANDSHAKE_DONE frame. + * decode a frame. */ ngtcp2_ssize ngtcp2_pkt_decode_handshake_done_frame(ngtcp2_handshake_done *dest, const uint8_t *payload, @@ -1076,7 +1063,7 @@ ngtcp2_pkt_encode_path_response_frame(uint8_t *out, size_t outlen, * Buffer does not have enough capacity to write a frame. */ ngtcp2_ssize ngtcp2_pkt_encode_crypto_frame(uint8_t *out, size_t outlen, - const ngtcp2_crypto *fr); + const ngtcp2_stream *fr); /* * ngtcp2_pkt_encode_new_token_frame encodes NEW_TOKEN frame |fr| into @@ -1142,14 +1129,19 @@ int64_t ngtcp2_pkt_adjust_pkt_num(int64_t max_pkt_num, int64_t pkt_num, /* * ngtcp2_pkt_validate_ack checks that ack is malformed or not. + * |min_pkt_num| is the minimum packet number that an endpoint sends. + * It is an error to receive acknowledgements for a packet less than + * |min_pkt_num|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * NGTCP2_ERR_ACK_FRAME * ACK frame is malformed + * NGTCP2_ERR_PROTO + * |fr| contains a packet number less than |min_pkt_num|. */ -int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr); +int ngtcp2_pkt_validate_ack(ngtcp2_ack *fr, int64_t min_pkt_num); /* * ngtcp2_pkt_stream_max_datalen returns the maximum number of bytes diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h new file mode 100644 index 00000000000000..66b0ee9e6c13cf --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pktns_id.h @@ -0,0 +1,62 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 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_PKTNS_ID_H +#define NGTCP2_PKTNS_ID_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/** + * @enum + * + * :type:`ngtcp2_pktns_id` defines packet number space identifier. + */ +typedef enum ngtcp2_pktns_id { + /** + * :enum:`NGTCP2_PKTNS_ID_INITIAL` is the Initial packet number + * space. + */ + NGTCP2_PKTNS_ID_INITIAL, + /** + * :enum:`NGTCP2_PKTNS_ID_HANDSHAKE` is the Handshake packet number + * space. + */ + NGTCP2_PKTNS_ID_HANDSHAKE, + /** + * :enum:`NGTCP2_PKTNS_ID_APPLICATION` is the Application data + * packet number space. + */ + NGTCP2_PKTNS_ID_APPLICATION, + /** + * :enum:`NGTCP2_PKTNS_ID_MAX` is defined to get the number of + * packet number spaces. + */ + NGTCP2_PKTNS_ID_MAX +} ngtcp2_pktns_id; + +#endif /* NGTCP2_PKTNS_ID_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c index 26318bb1c8e38c..771ef5e026d12d 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pmtud.c @@ -41,7 +41,7 @@ static size_t mtu_probes[] = { 1492 - 48, /* PPPoE */ }; -static size_t mtu_probeslen = sizeof(mtu_probes) / sizeof(mtu_probes[0]); +#define NGTCP2_MTU_PROBESLEN ngtcp2_arraylen(mtu_probes) int ngtcp2_pmtud_new(ngtcp2_pmtud **ppmtud, size_t max_udp_payload_size, size_t hard_max_udp_payload_size, int64_t tx_pkt_num, @@ -61,7 +61,7 @@ int ngtcp2_pmtud_new(ngtcp2_pmtud **ppmtud, size_t max_udp_payload_size, pmtud->hard_max_udp_payload_size = hard_max_udp_payload_size; pmtud->min_fail_udp_payload_size = SIZE_MAX; - for (; pmtud->mtu_idx < mtu_probeslen; ++pmtud->mtu_idx) { + for (; pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN; ++pmtud->mtu_idx) { if (mtu_probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) { continue; } @@ -84,7 +84,7 @@ void ngtcp2_pmtud_del(ngtcp2_pmtud *pmtud) { } size_t ngtcp2_pmtud_probelen(ngtcp2_pmtud *pmtud) { - assert(pmtud->mtu_idx < mtu_probeslen); + assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN); return mtu_probes[pmtud->mtu_idx]; } @@ -107,13 +107,13 @@ int ngtcp2_pmtud_require_probe(ngtcp2_pmtud *pmtud) { } static void pmtud_next_probe(ngtcp2_pmtud *pmtud) { - assert(pmtud->mtu_idx < mtu_probeslen); + assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN); ++pmtud->mtu_idx; pmtud->num_pkts_sent = 0; pmtud->expiry = UINT64_MAX; - for (; pmtud->mtu_idx < mtu_probeslen; ++pmtud->mtu_idx) { + for (; pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN; ++pmtud->mtu_idx) { if (mtu_probes[pmtud->mtu_idx] <= pmtud->max_udp_payload_size || mtu_probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) { continue; @@ -129,7 +129,7 @@ void ngtcp2_pmtud_probe_success(ngtcp2_pmtud *pmtud, size_t payloadlen) { pmtud->max_udp_payload_size = ngtcp2_max(pmtud->max_udp_payload_size, payloadlen); - assert(pmtud->mtu_idx < mtu_probeslen); + assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN); if (mtu_probes[pmtud->mtu_idx] > pmtud->max_udp_payload_size) { return; @@ -156,5 +156,5 @@ void ngtcp2_pmtud_handle_expiry(ngtcp2_pmtud *pmtud, ngtcp2_tstamp ts) { } int ngtcp2_pmtud_finished(ngtcp2_pmtud *pmtud) { - return pmtud->mtu_idx >= mtu_probeslen; + return pmtud->mtu_idx >= NGTCP2_MTU_PROBESLEN; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c index 5376246bd4caa9..ffba131e02b9a5 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c @@ -55,7 +55,7 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) { ppe->len_offset = 1 + 4 + 1 + hd->dcid.datalen + 1 + hd->scid.datalen; if (hd->type == NGTCP2_PKT_INITIAL) { - ppe->len_offset += ngtcp2_put_varint_len(hd->token.len) + hd->token.len; + ppe->len_offset += ngtcp2_put_uvarintlen(hd->tokenlen) + hd->tokenlen; } ppe->pkt_num_offset = ppe->len_offset + NGTCP2_PKT_LENGTHLEN; rv = ngtcp2_pkt_encode_hd_long( @@ -115,7 +115,7 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { assert(cc->hp_mask); if (ppe->len_offset) { - ngtcp2_put_varint30( + ngtcp2_put_uvarint30( buf->begin + ppe->len_offset, (uint16_t)(payloadlen + ppe->pkt_numlen + cc->aead.max_overhead)); } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h index 293cbcaaf6e881..c9da15248a3e2b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h @@ -76,10 +76,6 @@ void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data, fallback DCID. If path validation succeeds, fallback DCID is retired if it does not equal to the current DCID. */ #define NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE 0x04u -/* NGTCP2_PV_FLAG_MTU_PROBE indicates that a validation must probe - least MTU that QUIC requires, which is 1200 bytes. If it fails, a - path is not viable. */ -#define NGTCP2_PV_FLAG_MTU_PROBE 0x08u /* NGTCP2_PV_FLAG_PREFERRED_ADDR indicates that client is migrating to server's preferred address. This flag is only used by client. */ #define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10u diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c index 69eaeb7367438d..27675347794b2a 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c @@ -30,6 +30,8 @@ #include "ngtcp2_vec.h" #include "ngtcp2_conv.h" #include "ngtcp2_net.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_conn_stat.h" void ngtcp2_qlog_init(ngtcp2_qlog *qlog, ngtcp2_qlog_write write, ngtcp2_tstamp ts, void *user_data) { @@ -284,9 +286,9 @@ static uint8_t *write_pkt_hd(uint8_t *p, const ngtcp2_pkt_hd *hd) { p = write_pair(p, "packet_type", qlog_pkt_type(hd)); *p++ = ','; p = write_pair_number(p, "packet_number", (uint64_t)hd->pkt_num); - if (hd->type == NGTCP2_PKT_INITIAL && hd->token.len) { + if (hd->type == NGTCP2_PKT_INITIAL && hd->tokenlen) { p = write_verbatim(p, ",\"token\":{"); - p = write_pair_hex(p, "data", hd->token.base, hd->token.len); + p = write_pair_hex(p, "data", hd->token, hd->tokenlen); *p++ = '}'; } /* TODO Write DCIL and DCID */ @@ -316,7 +318,7 @@ static uint8_t *write_ping_frame(uint8_t *p, const ngtcp2_ping *fr) { static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) { int64_t largest_ack, min_ack; size_t i; - const ngtcp2_ack_blk *blk; + const ngtcp2_ack_range *range; /* * {"frame_type":"ack","ack_delay":0000000000000000000,"acked_ranges":[]} @@ -336,7 +338,7 @@ static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) { p = write_verbatim(p, ",\"acked_ranges\":["); largest_ack = fr->largest_ack; - min_ack = fr->largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = fr->largest_ack - (int64_t)fr->first_ack_range; *p++ = '['; p = write_number(p, (uint64_t)min_ack); @@ -346,10 +348,10 @@ static uint8_t *write_ack_frame(uint8_t *p, const ngtcp2_ack *fr) { } *p++ = ']'; - for (i = 0; i < fr->num_blks; ++i) { - blk = &fr->blks[i]; - largest_ack = min_ack - (int64_t)blk->gap - 2; - min_ack = largest_ack - (int64_t)blk->blklen; + for (i = 0; i < fr->rangecnt; ++i) { + range = &fr->ranges[i]; + largest_ack = min_ack - (int64_t)range->gap - 2; + min_ack = largest_ack - (int64_t)range->len; *p++ = ','; *p++ = '['; p = write_number(p, (uint64_t)min_ack); @@ -410,7 +412,7 @@ static uint8_t *write_stop_sending_frame(uint8_t *p, return p; } -static uint8_t *write_crypto_frame(uint8_t *p, const ngtcp2_crypto *fr) { +static uint8_t *write_crypto_frame(uint8_t *p, const ngtcp2_stream *fr) { /* * {"frame_type":"crypto","offset":0000000000000000000,"length":0000000000000000000} */ @@ -432,9 +434,9 @@ static uint8_t *write_new_token_frame(uint8_t *p, const ngtcp2_new_token *fr) { #define NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD 75 p = write_verbatim(p, "{\"frame_type\":\"new_token\","); - p = write_pair_number(p, "length", fr->token.len); + p = write_pair_number(p, "length", fr->tokenlen); p = write_verbatim(p, ",\"token\":{"); - p = write_pair_hex(p, "data", fr->token.base, fr->token.len); + p = write_pair_hex(p, "data", fr->token, fr->tokenlen); *p++ = '}'; *p++ = '}'; @@ -513,45 +515,53 @@ static uint8_t *write_max_streams_frame(uint8_t *p, static uint8_t *write_data_blocked_frame(uint8_t *p, const ngtcp2_data_blocked *fr) { - (void)fr; - /* - * {"frame_type":"data_blocked"} + * {"frame_type":"data_blocked","limit":0000000000000000000} */ -#define NGTCP2_QLOG_DATA_BLOCKED_FRAME_OVERHEAD 29 +#define NGTCP2_QLOG_DATA_BLOCKED_FRAME_OVERHEAD 57 - /* TODO log limit */ + p = write_verbatim(p, "{\"frame_type\":\"data_blocked\","); + p = write_pair_number(p, "limit", fr->offset); + *p++ = '}'; - return write_verbatim(p, "{\"frame_type\":\"data_blocked\"}"); + return p; } static uint8_t * write_stream_data_blocked_frame(uint8_t *p, const ngtcp2_stream_data_blocked *fr) { - (void)fr; - /* - * {"frame_type":"stream_data_blocked"} + * {"frame_type":"stream_data_blocked","stream_id":0000000000000000000,"limit":0000000000000000000} */ -#define NGTCP2_QLOG_STREAM_DATA_BLOCKED_FRAME_OVERHEAD 36 +#define NGTCP2_QLOG_STREAM_DATA_BLOCKED_FRAME_OVERHEAD 96 - /* TODO log limit */ + p = write_verbatim(p, "{\"frame_type\":\"stream_data_blocked\","); + p = write_pair_number(p, "stream_id", (uint64_t)fr->stream_id); + *p++ = ','; + p = write_pair_number(p, "limit", fr->offset); + *p++ = '}'; - return write_verbatim(p, "{\"frame_type\":\"stream_data_blocked\"}"); + return p; } static uint8_t *write_streams_blocked_frame(uint8_t *p, const ngtcp2_streams_blocked *fr) { - (void)fr; - /* - * {"frame_type":"streams_blocked"} + * {"frame_type":"streams_blocked","stream_type":"unidirectional","limit":0000000000000000000} */ -#define NGTCP2_QLOG_STREAMS_BLOCKED_FRAME_OVERHEAD 32 +#define NGTCP2_QLOG_STREAMS_BLOCKED_FRAME_OVERHEAD 91 - /* TODO Log stream_type and limit */ + p = write_verbatim(p, "{\"frame_type\":\"streams_blocked\",\"stream_type\":"); + if (fr->type == NGTCP2_FRAME_STREAMS_BLOCKED_BIDI) { + p = write_string(p, "bidirectional"); + } else { + p = write_string(p, "unidirectional"); + } + *p++ = ','; + p = write_pair_number(p, "limit", fr->max_streams); + *p++ = '}'; - return write_verbatim(p, "{\"frame_type\":\"streams_blocked\"}"); + return p; } static uint8_t * @@ -715,7 +725,7 @@ static void qlog_pkt_write_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, (1 + 50 + NGTCP2_QLOG_PKT_HD_OVERHEAD) if (ngtcp2_buf_left(&qlog->buf) < - NGTCP2_QLOG_PKT_WRITE_END_OVERHEAD + hd->token.len * 2) { + NGTCP2_QLOG_PKT_WRITE_END_OVERHEAD + hd->tokenlen * 2) { return; } @@ -765,7 +775,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) { (size_t)(fr->type == NGTCP2_FRAME_ACK_ECN ? NGTCP2_QLOG_ACK_FRAME_ECN_OVERHEAD : 0) + - NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD * (1 + fr->ack.num_blks) + 1) { + NGTCP2_QLOG_ACK_FRAME_RANGE_OVERHEAD * (1 + fr->ack.rangecnt) + 1) { return; } p = write_ack_frame(p, &fr->ack); @@ -788,11 +798,11 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) { if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_CRYPTO_FRAME_OVERHEAD + 1) { return; } - p = write_crypto_frame(p, &fr->crypto); + p = write_crypto_frame(p, &fr->stream); break; case NGTCP2_FRAME_NEW_TOKEN: - if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD + - fr->new_token.token.len * 2 + 1) { + if (ngtcp2_buf_left(&qlog->buf) < + NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD + fr->new_token.tokenlen * 2 + 1) { return; } p = write_new_token_frame(p, &fr->new_token); @@ -897,7 +907,7 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) { p = write_datagram_frame(p, &fr->datagram); break; default: - assert(0); + ngtcp2_unreachable(); } *p++ = ','; @@ -929,6 +939,8 @@ void ngtcp2_qlog_parameters_set_transport_params( uint8_t buf[1024]; uint8_t *p = buf; const ngtcp2_preferred_addr *paddr; + const ngtcp2_sockaddr_in *sa_in; + const ngtcp2_sockaddr_in6 *sa_in6; if (!qlog->write) { return; @@ -996,20 +1008,33 @@ void ngtcp2_qlog_parameters_set_transport_params( *p++ = ','; p = write_pair_number(p, "initial_max_streams_uni", params->initial_max_streams_uni); - if (params->preferred_address_present) { + if (params->preferred_addr_present) { *p++ = ','; - paddr = ¶ms->preferred_address; + paddr = ¶ms->preferred_addr; p = write_string(p, "preferred_address"); *p++ = ':'; *p++ = '{'; - p = write_pair_hex(p, "ip_v4", paddr->ipv4_addr, sizeof(paddr->ipv4_addr)); - *p++ = ','; - p = write_pair_number(p, "port_v4", paddr->ipv4_port); - *p++ = ','; - p = write_pair_hex(p, "ip_v6", paddr->ipv6_addr, sizeof(paddr->ipv6_addr)); - *p++ = ','; - p = write_pair_number(p, "port_v6", paddr->ipv6_port); - *p++ = ','; + + if (paddr->ipv4_present) { + sa_in = &paddr->ipv4; + + p = write_pair_hex(p, "ip_v4", (const uint8_t *)&sa_in->sin_addr, + sizeof(sa_in->sin_addr)); + *p++ = ','; + p = write_pair_number(p, "port_v4", ngtcp2_ntohs(sa_in->sin_port)); + *p++ = ','; + } + + if (paddr->ipv6_present) { + sa_in6 = &paddr->ipv6; + + p = write_pair_hex(p, "ip_v6", (const uint8_t *)&sa_in6->sin6_addr, + sizeof(sa_in6->sin6_addr)); + *p++ = ','; + p = write_pair_number(p, "port_v6", ngtcp2_ntohs(sa_in6->sin6_port)); + *p++ = ','; + } + p = write_pair_cid(p, "connection_id", &paddr->cid); p = write_verbatim(p, ",\"stateless_reset_token\":{"); p = write_pair_hex(p, "data", paddr->stateless_reset_token, @@ -1113,16 +1138,15 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, ",\"name\":\"transport:packet_received\",\"data\":{\"header\":"); if (ngtcp2_buf_left(&buf) < - NGTCP2_QLOG_PKT_HD_OVERHEAD + hd->token.len * 2 + + NGTCP2_QLOG_PKT_HD_OVERHEAD + hd->tokenlen * 2 + sizeof(",\"retry_token\":{\"data\":\"\"}}}\n") - 1 + - retry->token.len * 2) { + retry->tokenlen * 2) { return; } buf.last = write_pkt_hd(buf.last, hd); buf.last = write_verbatim(buf.last, ",\"retry_token\":{"); - buf.last = - write_pair_hex(buf.last, "data", retry->token.base, retry->token.len); + buf.last = write_pair_hex(buf.last, "data", retry->token, retry->tokenlen); buf.last = write_verbatim(buf.last, "}}}\n"); qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf.pos, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c index 74e488bce76f24..c381c231276d34 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c @@ -31,8 +31,9 @@ #include "ngtcp2_macro.h" -#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || defined(_M_ARM64)) -unsigned int __popcnt(unsigned int x) { +#if defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_ARM) || defined(_M_ARM64)) +static unsigned int __popcnt(unsigned int x) { unsigned int c = 0; for (; x; ++c) { x &= x - 1; @@ -63,7 +64,7 @@ void ngtcp2_ringbuf_buf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size, rb->buf = buf; rb->mem = mem; - rb->nmemb = nmemb; + rb->mask = nmemb - 1; rb->size = size; rb->first = 0; rb->len = 0; @@ -78,17 +79,19 @@ void ngtcp2_ringbuf_free(ngtcp2_ringbuf *rb) { } void *ngtcp2_ringbuf_push_front(ngtcp2_ringbuf *rb) { - rb->first = (rb->first - 1) & (rb->nmemb - 1); - rb->len = ngtcp2_min(rb->nmemb, rb->len + 1); + rb->first = (rb->first - 1) & rb->mask; + if (rb->len < rb->mask + 1) { + ++rb->len; + } return (void *)&rb->buf[rb->first * rb->size]; } void *ngtcp2_ringbuf_push_back(ngtcp2_ringbuf *rb) { - size_t offset = (rb->first + rb->len) & (rb->nmemb - 1); + size_t offset = (rb->first + rb->len) & rb->mask; - if (rb->len == rb->nmemb) { - rb->first = (rb->first + 1) & (rb->nmemb - 1); + if (rb->len == rb->mask + 1) { + rb->first = (rb->first + 1) & rb->mask; } else { ++rb->len; } @@ -97,7 +100,7 @@ void *ngtcp2_ringbuf_push_back(ngtcp2_ringbuf *rb) { } void ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf *rb) { - rb->first = (rb->first + 1) & (rb->nmemb - 1); + rb->first = (rb->first + 1) & rb->mask; --rb->len; } @@ -107,14 +110,14 @@ void ngtcp2_ringbuf_pop_back(ngtcp2_ringbuf *rb) { } void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len) { - assert(len <= rb->nmemb); + assert(len <= rb->mask + 1); rb->len = len; } void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset) { assert(offset < rb->len); - offset = (rb->first + offset) & (rb->nmemb - 1); + offset = (rb->first + offset) & rb->mask; return &rb->buf[offset * rb->size]; } -int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->nmemb; } +int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->mask + 1; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h index 16635c941032c7..b28a882c4bae84 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h @@ -37,9 +37,9 @@ typedef struct ngtcp2_ringbuf { /* buf points to the underlying buffer. */ uint8_t *buf; const ngtcp2_mem *mem; - /* nmemb is the number of elements that can be stored in this ring - buffer. */ - size_t nmemb; + /* mask is the bit mask to cover all bits for the maximum number of + elements. The maximum number of elements is mask + 1. */ + size_t mask; /* size is the size of each element. */ size_t size; /* first is the offset to the first element. */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c index 9c3d75dc33ae0c..5cac383f7bb166 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.c @@ -218,7 +218,7 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, return 0; } -int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { +void ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { ngtcp2_rob_gap *g; ngtcp2_rob_data *d; ngtcp2_ksl_it it; @@ -245,13 +245,11 @@ int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { for (; !ngtcp2_ksl_it_end(&it);) { d = ngtcp2_ksl_it_get(&it); if (offset < d->range.begin + rob->chunk) { - return 0; + return; } ngtcp2_ksl_remove_hint(&rob->dataksl, &it, &it, &d->range); ngtcp2_rob_data_del(d, rob->mem); } - - return 0; } size_t ngtcp2_rob_data_at(ngtcp2_rob *rob, const uint8_t **pdest, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h index c7688df4542956..6518d56c539185 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rob.h @@ -152,14 +152,8 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, /* * ngtcp2_rob_remove_prefix removes gap up to |offset|, exclusive. It * also removes data buffer if it is completely included in |offset|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory */ -int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset); +void ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset); /* * ngtcp2_rob_data_at stores the pointer to the buffer of stream diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c index 7b50f98d41ec7b..b8587e3e9dbac8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.c @@ -29,6 +29,7 @@ #include "ngtcp2_rtb.h" #include "ngtcp2_cc.h" #include "ngtcp2_macro.h" +#include "ngtcp2_conn_stat.h" void ngtcp2_rs_init(ngtcp2_rs *rs) { rs->interval = UINT64_MAX; @@ -69,8 +70,8 @@ void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, ent->rst.lost = rst->lost; } -int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, - uint64_t pkt_delivered) { +void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, + uint64_t pkt_delivered) { ngtcp2_rs *rs = &rst->rs; uint64_t rate; @@ -84,7 +85,7 @@ int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, } if (rs->prior_ts == 0) { - return 0; + return; } rs->interval = ngtcp2_max(rs->send_elapsed, rs->ack_elapsed); @@ -94,11 +95,11 @@ int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, if (rs->interval < cstat->min_rtt) { rs->interval = UINT64_MAX; - return 0; + return; } if (!rs->interval) { - return 0; + return; } rate = rs->delivered * NGTCP2_SECONDS / rs->interval; @@ -107,8 +108,6 @@ int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, ngtcp2_window_filter_update(&rst->wf, rate, rst->round_count); cstat->delivery_rate_sec = ngtcp2_window_filter_get_best(&rst->wf); } - - return 0; } void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h index 488c65575a5589..c9e1e161b7766f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rst.h @@ -34,6 +34,7 @@ #include "ngtcp2_window_filter.h" typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry; +typedef struct ngtcp2_conn_stat ngtcp2_conn_stat; /** * @struct @@ -76,8 +77,8 @@ void ngtcp2_rst_init(ngtcp2_rst *rst); void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, const ngtcp2_conn_stat *cstat); -int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, - uint64_t pkt_delivered); +void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat, + uint64_t pkt_delivered); void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, ngtcp2_tstamp ts); void ngtcp2_rst_update_app_limited(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c index 644071400a6eb7..b9e0139bddfcac 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c @@ -34,220 +34,11 @@ #include "ngtcp2_cc.h" #include "ngtcp2_rcvry.h" #include "ngtcp2_rst.h" +#include "ngtcp2_unreachable.h" +#include "ngtcp2_tstamp.h" +#include "ngtcp2_frame_chain.h" -int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem) { - *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain)); - if (*pfrc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_frame_chain_init(*pfrc); - - return 0; -} - -int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, - ngtcp2_objalloc *objalloc) { - *pfrc = ngtcp2_objalloc_frame_chain_get(objalloc); - if (*pfrc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_frame_chain_init(*pfrc); - - return 0; -} - -int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, - const ngtcp2_mem *mem) { - *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain) + extralen); - if (*pfrc == NULL) { - return NGTCP2_ERR_NOMEM; - } - - ngtcp2_frame_chain_init(*pfrc); - - return 0; -} - -int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - size_t need, avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream); - - if (datacnt > 1) { - need = sizeof(ngtcp2_vec) * (datacnt - 1); - - if (need > avail) { - return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); - } - } - - return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); -} - -int ngtcp2_frame_chain_crypto_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - size_t need, avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_crypto); - - if (datacnt > 1) { - need = sizeof(ngtcp2_vec) * (datacnt - 1); - - if (need > avail) { - return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); - } - } - - return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); -} - -int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, - const ngtcp2_vec *token, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token); - int rv; - uint8_t *p; - ngtcp2_frame *fr; - - if (token->len > avail) { - rv = ngtcp2_frame_chain_extralen_new(pfrc, token->len - avail, mem); - } else { - rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc); - } - if (rv != 0) { - return rv; - } - - fr = &(*pfrc)->fr; - fr->type = NGTCP2_FRAME_NEW_TOKEN; - - p = (uint8_t *)fr + sizeof(ngtcp2_new_token); - memcpy(p, token->base, token->len); - - ngtcp2_vec_init(&fr->new_token.token, p, token->len); - - return 0; -} - -void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) { - ngtcp2_frame_chain_binder *binder; - - if (frc == NULL) { - return; - } - - binder = frc->binder; - if (binder && --binder->refcount == 0) { - ngtcp2_mem_free(mem, binder); - } - - ngtcp2_mem_free(mem, frc); -} - -void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - ngtcp2_frame_chain_binder *binder; - - if (frc == NULL) { - return; - } - - switch (frc->fr.type) { - case NGTCP2_FRAME_STREAM: - if (frc->fr.stream.datacnt && - sizeof(ngtcp2_vec) * (frc->fr.stream.datacnt - 1) > - sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream)) { - ngtcp2_frame_chain_del(frc, mem); - - return; - } - - break; - case NGTCP2_FRAME_CRYPTO: - if (frc->fr.crypto.datacnt && - sizeof(ngtcp2_vec) * (frc->fr.crypto.datacnt - 1) > - sizeof(ngtcp2_frame) - sizeof(ngtcp2_crypto)) { - ngtcp2_frame_chain_del(frc, mem); - - return; - } - - break; - case NGTCP2_FRAME_NEW_TOKEN: - if (frc->fr.new_token.token.len > - sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token)) { - ngtcp2_frame_chain_del(frc, mem); - - return; - } - - break; - } - - binder = frc->binder; - if (binder && --binder->refcount == 0) { - ngtcp2_mem_free(mem, binder); - } - - frc->binder = NULL; - - ngtcp2_objalloc_frame_chain_release(objalloc, frc); -} - -void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) { - frc->next = NULL; - frc->binder = NULL; -} - -void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem) { - ngtcp2_frame_chain *next; - - for (; frc; frc = next) { - next = frc->next; - - ngtcp2_frame_chain_objalloc_del(frc, objalloc, mem); - } -} - -int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, - const ngtcp2_mem *mem) { - *pbinder = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_frame_chain_binder)); - if (*pbinder == NULL) { - return NGTCP2_ERR_NOMEM; - } - - return 0; -} - -int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, - const ngtcp2_mem *mem) { - ngtcp2_frame_chain_binder *binder; - int rv; - - assert(b->binder == NULL); - - if (a->binder == NULL) { - rv = ngtcp2_frame_chain_binder_new(&binder, mem); - if (rv != 0) { - return rv; - } - - a->binder = binder; - ++a->binder->refcount; - } - - b->binder = a->binder; - ++b->binder->refcount; - - return 0; -} +ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent); static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd, ngtcp2_frame_chain *frc, ngtcp2_tstamp ts, @@ -297,7 +88,7 @@ static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, ngtcp2_strm *crypto, ngtcp2_rst *rst, ngtcp2_cc *cc, - ngtcp2_log *log, ngtcp2_qlog *qlog, + int64_t cc_pkt_num, ngtcp2_log *log, ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { rtb->rtb_entry_objalloc = rtb_entry_objalloc; @@ -315,7 +106,7 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, rtb->num_pto_eliciting = 0; rtb->probe_pkt_left = 0; rtb->pktns_id = pktns_id; - rtb->cc_pkt_num = 0; + rtb->cc_pkt_num = cc_pkt_num; rtb->cc_bytes_in_flight = 0; rtb->persistent_congestion_start_ts = UINT64_MAX; rtb->num_lost_pkts = 0; @@ -432,7 +223,6 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, ngtcp2_range gap, range; size_t num_reclaimed = 0; int rv; - int streamfrq_empty; assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE); @@ -487,7 +277,6 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data, fr->stream.datacnt); - streamfrq_empty = ngtcp2_strm_streamfrq_empty(strm); rv = ngtcp2_strm_streamfrq_push(strm, nfrc); if (rv != 0) { ngtcp2_frame_chain_objalloc_del(nfrc, rtb->frc_objalloc, rtb->mem); @@ -500,9 +289,6 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, return rv; } } - if (streamfrq_empty) { - ++conn->tx.strmq_nretrans; - } ++num_reclaimed; @@ -510,28 +296,27 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, case NGTCP2_FRAME_CRYPTO: /* Don't resend CRYPTO frame if the whole region it contains has been acknowledged */ - gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->crypto.offset); + gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->stream.offset); - range.begin = fr->crypto.offset; - range.end = fr->crypto.offset + - ngtcp2_vec_len(fr->crypto.data, fr->crypto.datacnt); + range.begin = fr->stream.offset; + range.end = fr->stream.offset + + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt); range = ngtcp2_range_intersect(&range, &gap); if (ngtcp2_range_len(&range) == 0) { continue; } - rv = ngtcp2_frame_chain_crypto_datacnt_objalloc_new( - &nfrc, fr->crypto.datacnt, rtb->frc_objalloc, rtb->mem); + rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new( + &nfrc, fr->stream.datacnt, rtb->frc_objalloc, rtb->mem); if (rv != 0) { return rv; } nfrc->fr = *fr; - ngtcp2_vec_copy(nfrc->fr.crypto.data, fr->crypto.data, - fr->crypto.datacnt); + ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data, + fr->stream.datacnt); - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - &nfrc->fr.crypto.offset, nfrc); + rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, nfrc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_objalloc_del(nfrc, rtb->frc_objalloc, rtb->mem); @@ -543,7 +328,8 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, continue; case NGTCP2_FRAME_NEW_TOKEN: rv = ngtcp2_frame_chain_new_token_objalloc_new( - &nfrc, &fr->new_token.token, rtb->frc_objalloc, rtb->mem); + &nfrc, fr->new_token.token, fr->new_token.tokenlen, rtb->frc_objalloc, + rtb->mem); if (rv != 0) { return rv; } @@ -638,7 +424,7 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " has already been reclaimed on PTO", ent->hd.pkt_num); assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)); @@ -770,6 +556,10 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, for (frc = ent->frc; frc; frc = frc->next) { if (frc->binder) { + if (frc->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK) { + continue; + } + frc->binder->flags |= NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK; } @@ -817,8 +607,8 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, case NGTCP2_FRAME_CRYPTO: prev_stream_offset = ngtcp2_strm_get_acked_offset(crypto); rv = ngtcp2_strm_ack_data( - crypto, frc->fr.crypto.offset, - ngtcp2_vec_len(frc->fr.crypto.data, frc->fr.crypto.datacnt)); + crypto, frc->fr.stream.offset, + ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt)); if (rv != 0) { return rv; } @@ -840,7 +630,7 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, pktns = &conn->pktns; break; default: - assert(0); + ngtcp2_unreachable(); } conn_ack_crypto_data(conn, pktns, datalen); @@ -851,7 +641,7 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, if (strm == NULL) { break; } - strm->flags |= NGTCP2_STRM_FLAG_RST_ACKED; + strm->flags |= NGTCP2_STRM_FLAG_RESET_STREAM_ACKED; rv = ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm); if (rv != 0) { return rv; @@ -861,6 +651,12 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, ngtcp2_conn_untrack_retired_dcid_seq(conn, frc->fr.retire_connection_id.seq); break; + case NGTCP2_FRAME_NEW_CONNECTION_ID: + assert(conn->scid.num_in_flight); + + --conn->scid.num_in_flight; + + break; case NGTCP2_FRAME_DATAGRAM: case NGTCP2_FRAME_DATAGRAM_LEN: if (!conn->callbacks.ack_datagram) { @@ -885,12 +681,14 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts); - cc->on_pkt_acked(cc, cstat, - ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, - rtb->pktns_id, ent->ts, ent->rst.lost, - ent->rst.tx_in_flight, - ent->rst.is_app_limited), - ts); + if (cc->on_pkt_acked) { + cc->on_pkt_acked(cc, cstat, + ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, + rtb->pktns_id, ent->ts, ent->rst.lost, + ent->rst.tx_in_flight, + ent->rst.is_app_limited), + ts); + } if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE) && (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { @@ -901,7 +699,7 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, const ngtcp2_ack *fr, size_t ecn_acked, - ngtcp2_tstamp largest_acked_sent_ts, + ngtcp2_tstamp largest_pkt_sent_ts, ngtcp2_tstamp ts) { if (conn->tx.ecn.state == NGTCP2_ECN_STATE_FAILED) { return; @@ -928,9 +726,9 @@ static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns, } if (fr->type == NGTCP2_FRAME_ACK_ECN) { - if (largest_acked_sent_ts != UINT64_MAX && + if (cc->congestion_event && largest_pkt_sent_ts != UINT64_MAX && fr->ecn.ce > pktns->rx.ecn.ack.ce) { - cc->congestion_event(cc, cstat, largest_acked_sent_ts, ts); + cc->congestion_event(cc, cstat, largest_pkt_sent_ts, ts); } pktns->rx.ecn.ack.ect0 = fr->ecn.ect0; @@ -954,7 +752,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ngtcp2_ksl_it it; ngtcp2_ssize num_acked = 0; ngtcp2_tstamp largest_pkt_sent_ts = UINT64_MAX; - ngtcp2_tstamp largest_acked_sent_ts = UINT64_MAX; int64_t pkt_num; ngtcp2_cc *cc = rtb->cc; ngtcp2_rtb_entry *acked_ent = NULL; @@ -987,12 +784,12 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, if (ngtcp2_ksl_it_end(&it)) { if (conn && verify_ecn) { conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, - largest_acked_sent_ts, ts); + largest_pkt_sent_ts, ts); } return 0; } - min_ack = largest_ack - (int64_t)fr->first_ack_blklen; + min_ack = largest_ack - (int64_t)fr->first_ack_range; for (; !ngtcp2_ksl_it_end(&it);) { pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it); @@ -1017,9 +814,9 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ++num_acked; } - for (i = 0; i < fr->num_blks;) { - largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2; - min_ack = largest_ack - (int64_t)fr->blks[i].blklen; + for (i = 0; i < fr->rangecnt;) { + largest_ack = min_ack - (int64_t)fr->ranges[i].gap - 2; + min_ack = largest_ack - (int64_t)fr->ranges[i].len; it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack); if (ngtcp2_ksl_it_end(&it)) { @@ -1060,11 +857,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ++ecn_acked; } - assert(largest_acked_sent_ts == UINT64_MAX || - largest_acked_sent_ts <= ent->ts); - - largest_acked_sent_ts = ent->ts; - rv = rtb_process_acked_pkt(rtb, ent, conn); if (rv != 0) { goto fail; @@ -1085,7 +877,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, if (verify_ecn) { conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, - largest_acked_sent_ts, ts); + largest_pkt_sent_ts, ts); } } else { /* For unit tests */ @@ -1113,8 +905,10 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, rtb->rst->lost += cc_ack.bytes_lost; - cc_ack.largest_acked_sent_ts = largest_acked_sent_ts; - cc->on_ack_recv(cc, cstat, &cc_ack, ts); + cc_ack.largest_pkt_sent_ts = largest_pkt_sent_ts; + if (cc->on_ack_recv) { + cc->on_ack_recv(cc, cstat, &cc_ack, ts); + } return num_acked; @@ -1133,7 +927,7 @@ static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, size_t pkt_thres, ngtcp2_tstamp ts) { ngtcp2_tstamp loss_time; - if (ent->ts + loss_delay <= ts || + if (ngtcp2_tstamp_elapsed(ent->ts, loss_delay, ts) || rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + (int64_t)pkt_thres) { return 1; } @@ -1189,7 +983,7 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, ngtcp2_cc *cc = rtb->cc; int rv; uint64_t pkt_thres = - rtb->cc_bytes_in_flight / cstat->max_udp_payload_size / 2; + rtb->cc_bytes_in_flight / cstat->max_tx_udp_payload_size / 2; size_t ecn_pkt_lost = 0; ngtcp2_tstamp start_ts; ngtcp2_duration pto = ngtcp2_conn_compute_pto(conn, pktns); @@ -1288,7 +1082,9 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, break; } - cc->congestion_event(cc, cstat, latest_ts, ts); + if (cc->congestion_event) { + cc->congestion_event(cc, cstat, latest_ts, ts); + } loss_window = latest_ts - oldest_ts; /* Persistent congestion situation is only evaluated for app @@ -1300,7 +1096,7 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, */ if (rtb->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && loss_window > 0) { if (loss_window >= congestion_period) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "persistent congestion loss_window=%" PRIu64 " congestion_period=%" PRIu64, loss_window, congestion_period); @@ -1312,7 +1108,9 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, cstat->rttvar = conn->local.settings.initial_rtt / 2; cstat->first_rtt_sample_ts = UINT64_MAX; - cc->on_persistent_congestion(cc, cstat, ts); + if (cc->on_persistent_congestion) { + cc->on_persistent_congestion(cc, cstat, ts); + } } } @@ -1349,7 +1147,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_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); --rtb->num_lost_pkts; @@ -1389,7 +1187,7 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, return; } - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); --rtb->num_lost_pkts; @@ -1435,7 +1233,6 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, ngtcp2_stream *sfr; ngtcp2_strm *strm; int rv; - int streamfrq_empty; ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags, ent->ts); @@ -1445,7 +1242,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " is a probe packet, no retransmission is necessary", ent->hd.pkt_num); @@ -1453,7 +1250,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " is a PMTUD probe packet, no retransmission is necessary", ent->hd.pkt_num); @@ -1467,7 +1264,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, --rtb->num_lost_pmtud_pkts; } - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " was declared lost and has already been retransmitted", ent->hd.pkt_num); @@ -1475,7 +1272,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, "pkn=%" PRId64 " has already been reclaimed on PTO", ent->hd.pkt_num); return 0; @@ -1505,7 +1302,6 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem); break; } - streamfrq_empty = ngtcp2_strm_streamfrq_empty(strm); rv = ngtcp2_strm_streamfrq_push(strm, frc); if (rv != 0) { ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem); @@ -1518,9 +1314,6 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, return rv; } } - if (streamfrq_empty) { - ++conn->tx.strmq_nretrans; - } break; case NGTCP2_FRAME_CRYPTO: frc = *pfrc; @@ -1528,8 +1321,7 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, *pfrc = frc->next; frc->next = NULL; - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - &frc->fr.crypto.offset, frc); + rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_objalloc_del(frc, rtb->frc_objalloc, rtb->mem); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h index a97805dbaf3bc3..a1ff208b19eac7 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h @@ -35,6 +35,7 @@ #include "ngtcp2_ksl.h" #include "ngtcp2_pq.h" #include "ngtcp2_objalloc.h" +#include "ngtcp2_pktns_id.h" typedef struct ngtcp2_conn ngtcp2_conn; typedef struct ngtcp2_pktns ngtcp2_pktns; @@ -43,156 +44,9 @@ typedef struct ngtcp2_qlog ngtcp2_qlog; typedef struct ngtcp2_strm ngtcp2_strm; typedef struct ngtcp2_rst ngtcp2_rst; typedef struct ngtcp2_cc ngtcp2_cc; - -/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is - set. */ -#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u -/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information - which a frame carries has been acknowledged. */ -#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u - -/* - * ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to - * share the acknowledgement state. In general, all - * ngtcp2_frame_chains bound to the same binder must have the same - * information. - */ -typedef struct ngtcp2_frame_chain_binder { - size_t refcount; - /* flags is bitwise OR of zero or more of - NGTCP2_FRAME_CHAIN_BINDER_FLAG_*. */ - uint32_t flags; -} ngtcp2_frame_chain_binder; - -int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, - const ngtcp2_mem *mem); - +typedef struct ngtcp2_conn_stat ngtcp2_conn_stat; typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; -/* - * ngtcp2_frame_chain chains frames in a single packet. - */ -struct ngtcp2_frame_chain { - union { - struct { - ngtcp2_frame_chain *next; - ngtcp2_frame_chain_binder *binder; - ngtcp2_frame fr; - }; - - ngtcp2_opl_entry oplent; - }; -}; - -ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent); - -/* - * ngtcp2_bind_frame_chains binds two frame chains |a| and |b| using - * new or existing ngtcp2_frame_chain_binder. |a| might have non-NULL - * a->binder. |b| must not have non-NULL b->binder. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory - */ -int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, - const ngtcp2_mem *mem); - -/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that - a ngtcp2_stream can include. */ -#define NGTCP2_MAX_STREAM_DATACNT 256 - -/* NGTCP2_MAX_CRYPTO_DATACNT is the maximum number of ngtcp2_vec that - a ngtcp2_crypto can include. */ -#define NGTCP2_MAX_CRYPTO_DATACNT 8 - -/* - * ngtcp2_frame_chain_new allocates ngtcp2_frame_chain object and - * assigns its pointer to |*pfrc|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_objalloc_new behaves like - * ngtcp2_frame_chain_new, but it uses |objalloc| to allocate the object. - */ -int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc, - ngtcp2_objalloc *objalloc); - -/* - * ngtcp2_frame_chain_extralen_new works like ngtcp2_frame_chain_new, - * but it allocates extra memory |extralen| in order to extend - * ngtcp2_frame. - */ -int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_stream_datacnt_objalloc_new works like - * ngtcp2_frame_chain_new, but it allocates enough data to store - * additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_stream - * object. If no additional space is required, - * ngtcp2_frame_chain_objalloc_new is called internally. - */ -int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_crypto_datacnt_objalloc_new works like - * ngtcp2_frame_chain_new, but it allocates enough data to store - * additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_crypto - * object. If no additional space is required, - * ngtcp2_frame_chain_objalloc_new is called internally. - */ -int ngtcp2_frame_chain_crypto_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc, - size_t datacnt, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc, - const ngtcp2_vec *token, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_del deallocates |frc|. It also deallocates the - * memory pointed by |frc|. - */ -void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse. - * It might just delete |frc| depending on the frame type and the size - * of |frc|. - */ -void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - -/* - * ngtcp2_frame_chain_init initializes |frc|. - */ -void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc); - -/* - * ngtcp2_frame_chain_list_objalloc_del adds all ngtcp2_frame_chain - * linked from |frc| to |objalloc| for reuse. Depending on the frame type - * and its size, ngtcp2_frame_chain might be deleted instead. - */ -void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc, - ngtcp2_objalloc *objalloc, - const ngtcp2_mem *mem); - /* NGTCP2_RTB_ENTRY_FLAG_NONE indicates that no flag is set. */ #define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00u /* NGTCP2_RTB_ENTRY_FLAG_PROBE indicates that the entry includes a @@ -268,7 +122,7 @@ struct ngtcp2_rtb_entry { }; }; -ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent); +ngtcp2_objalloc_decl(rtb_entry, ngtcp2_rtb_entry, oplent); /* * ngtcp2_rtb_entry_new allocates ngtcp2_rtb_entry object, and assigns @@ -347,7 +201,7 @@ typedef struct ngtcp2_rtb { */ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, ngtcp2_strm *crypto, ngtcp2_rst *rst, ngtcp2_cc *cc, - ngtcp2_log *log, ngtcp2_qlog *qlog, + int64_t cc_pkt_num, ngtcp2_log *log, ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c index c1ce64a2e57ac4..a61636d188fae5 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c @@ -38,6 +38,11 @@ uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n) { return dest + n; } +const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n) { + memcpy(dest, src, n); + return (uint8_t *)src + n; +} + #define LOWER_XDIGITS "0123456789abcdef" uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h index 04735d6dec5c63..deb75e356d70d4 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.h @@ -38,6 +38,13 @@ void *ngtcp2_cpymem(void *dest, const void *src, size_t n); * the buffer pointed by |dest|. It returns dest + n; */ uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n); + +/* + * ngtcp2_get_bytes copies |n| bytes from |src| to |dest|, and returns + * |src| + |n|. + */ +const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n); + /* * ngtcp2_encode_hex encodes |data| of length |len| in hex string. It * writes additional NULL bytes at the end of the buffer. The buffer diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c index 6f20e866ad51c0..6bbeb8f9f81fc2 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.c @@ -30,6 +30,7 @@ #include "ngtcp2_rtb.h" #include "ngtcp2_pkt.h" #include "ngtcp2_vec.h" +#include "ngtcp2_frame_chain.h" static int offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { return *(int64_t *)lhs < *(int64_t *)rhs; @@ -46,9 +47,12 @@ void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags, strm->tx.streamfrq = NULL; strm->tx.offset = 0; strm->tx.max_offset = max_tx_offset; + strm->tx.last_blocked_offset = UINT64_MAX; strm->tx.last_max_stream_data_ts = UINT64_MAX; strm->tx.loss_count = 0; strm->tx.last_lost_pkt_num = -1; + strm->tx.stop_sending_app_error_code = 0; + strm->tx.reset_stream_app_error_code = 0; strm->rx.rob = NULL; strm->rx.cont_offset = 0; strm->rx.last_offset = 0; @@ -120,7 +124,7 @@ uint64_t ngtcp2_strm_rx_offset(ngtcp2_strm *strm) { /* strm_rob_heavily_fragmented returns nonzero if the number of gaps in |rob| exceeds the limit. */ static int strm_rob_heavily_fragmented(ngtcp2_rob *rob) { - return ngtcp2_ksl_len(&rob->gapksl) >= 1000; + return ngtcp2_ksl_len(&rob->gapksl) >= 5000; } int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, @@ -134,10 +138,7 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, } if (strm->rx.cont_offset) { - rv = ngtcp2_rob_remove_prefix(strm->rx.rob, strm->rx.cont_offset); - if (rv != 0) { - return rv; - } + ngtcp2_rob_remove_prefix(strm->rx.rob, strm->rx.cont_offset); } } @@ -148,13 +149,13 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen); } -int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) { +void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) { if (strm->rx.rob == NULL) { strm->rx.cont_offset = offset; - return 0; + return; } - return ngtcp2_rob_remove_prefix(strm->rx.rob, offset); + ngtcp2_rob_remove_prefix(strm->rx.rob, offset); } void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags) { @@ -177,7 +178,8 @@ static int strm_streamfrq_init(ngtcp2_strm *strm) { int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) { int rv; - assert(frc->fr.type == NGTCP2_FRAME_STREAM); + assert(frc->fr.type == NGTCP2_FRAME_STREAM || + frc->fr.type == NGTCP2_FRAME_CRYPTO); assert(frc->next == NULL); if (strm->tx.streamfrq == NULL) { @@ -308,7 +310,7 @@ static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm, assert(nfr->data[0].len > end_base_offset); - nfr->type = NGTCP2_FRAME_STREAM; + nfr->type = fr->type; nfr->flags = 0; nfr->fin = fr->fin; nfr->stream_id = fr->stream_id; @@ -379,18 +381,16 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, fr = &frc->fr.stream; datalen = ngtcp2_vec_len(fr->data, fr->datacnt); - if (left == 0) { - /* datalen could be zero if 0 length STREAM has been sent */ - if (datalen || ngtcp2_ksl_len(strm->tx.streamfrq) > 1) { - rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc); - if (rv != 0) { - assert(ngtcp2_err_is_fatal(rv)); - ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem); - return rv; - } - *pfrc = NULL; - return 0; + /* datalen could be zero if 0 length STREAM has been sent */ + if (left == 0 && datalen) { + rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem); + return rv; } + *pfrc = NULL; + return 0; } if (datalen > left) { @@ -412,7 +412,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, } nfr = &nfrc->fr.stream; - nfr->type = NGTCP2_FRAME_STREAM; + nfr->type = fr->type; nfr->flags = 0; nfr->fin = fr->fin; nfr->stream_id = fr->stream_id; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h index 8e3cfe83543509..e8cc531f217ab1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h @@ -49,20 +49,20 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; #define NGTCP2_STRM_FLAG_SHUT_WR 0x02u #define NGTCP2_STRM_FLAG_SHUT_RDWR \ (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_SHUT_WR) -/* NGTCP2_STRM_FLAG_SENT_RST indicates that RST_STREAM is sent from - the local endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is also - set. */ -#define NGTCP2_STRM_FLAG_SENT_RST 0x04u -/* NGTCP2_STRM_FLAG_SENT_RST indicates that RST_STREAM is received - from the remote endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_RD - is also set. */ -#define NGTCP2_STRM_FLAG_RECV_RST 0x08u +/* NGTCP2_STRM_FLAG_RESET_STREAM indicates that RESET_STREAM is sent + from the local endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is + also set. */ +#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04u +/* NGTCP2_STRM_FLAG_RESET_STREAM_RECVED indicates that RESET_STREAM is + received from the remote endpoint. In this case, + NGTCP2_STRM_FLAG_SHUT_RD is also set. */ +#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08u /* NGTCP2_STRM_FLAG_STOP_SENDING indicates that STOP_SENDING is sent from the local endpoint. */ #define NGTCP2_STRM_FLAG_STOP_SENDING 0x10u -/* NGTCP2_STRM_FLAG_RST_ACKED indicates that the outgoing RST_STREAM - is acknowledged by peer. */ -#define NGTCP2_STRM_FLAG_RST_ACKED 0x20u +/* NGTCP2_STRM_FLAG_RESET_STREAM_ACKED indicates that the outgoing + RESET_STREAM is acknowledged by peer. */ +#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20u /* NGTCP2_STRM_FLAG_FIN_ACKED indicates that a STREAM with FIN bit set is acknowledged by a remote endpoint. */ #define NGTCP2_STRM_FLAG_FIN_ACKED 0x40u @@ -75,9 +75,12 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; In this case, without this flag, we are unable to distinguish assigned value from unassigned one. */ #define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100u -/* NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED is set when - stream_stop_sending callback is called. */ -#define NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED 0x200u +/* NGTCP2_STRM_FLAG_SEND_STOP_SENDING is set when STOP_SENDING frame + should be sent. */ +#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200u +/* NGTCP2_STRM_FLAG_SEND_RESET_STREAM is set when RESET_STREAM frame + should be sent. */ +#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400u typedef struct ngtcp2_strm ngtcp2_strm; @@ -96,10 +99,10 @@ struct ngtcp2_strm { remote endpoint acknowledges data in out-of-order. After that, acked_offset is used instead. */ uint64_t cont_acked_offset; - /* streamfrq contains STREAM frame for retransmission. The flow - control credits have been paid when they are transmitted first - time. There are no restriction regarding flow control for - retransmission. */ + /* streamfrq contains STREAM or CRYPTO frame for + retransmission. The flow control credits have been paid + when they are transmitted first time. There are no + restriction regarding flow control for retransmission. */ ngtcp2_ksl *streamfrq; /* offset is the next offset of outgoing data. In other words, it is the number of bytes sent in this stream without @@ -108,6 +111,9 @@ struct ngtcp2_strm { /* max_tx_offset is the maximum offset that local endpoint can send for this stream. */ uint64_t max_offset; + /* last_blocked_offset is the largest offset where the + transmission of stream data is blocked. */ + uint64_t last_blocked_offset; /* last_max_stream_data_ts is the timestamp when last MAX_STREAM_DATA frame is sent. */ ngtcp2_tstamp last_max_stream_data_ts; @@ -123,6 +129,12 @@ struct ngtcp2_strm { is counted to loss_count. It is used to avoid to count multiple STREAM frames in one lost packet. */ int64_t last_lost_pkt_num; + /* stop_sending_app_error_code is the application specific + error code that is sent along with STOP_SENDING. */ + uint64_t stop_sending_app_error_code; + /* reset_stream_app_error_code is the application specific + error code that is sent along with RESET_STREAM. */ + uint64_t reset_stream_app_error_code; } tx; struct { @@ -200,11 +212,8 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data, /* * ngtcp2_strm_update_rx_offset tells that data up to offset bytes are * received in order. - * - * NGTCP2_ERR_NOMEM - * Out of memory */ -int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset); +void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset); /* * ngtcp2_strm_shutdown shutdowns |strm|. |flags| should be diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h new file mode 100644 index 00000000000000..9a210a320dc1ca --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_tstamp.h @@ -0,0 +1,68 @@ +/* + * ngtcp2 + * + * Copyright (c) 2023 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_TSTAMP_H +#define NGTCP2_TSTAMP_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/* + * ngtcp2_tstamp_elapsed returns nonzero if at least |d| has passed + * since |base|. |ts| expresses a current time, and must not be + * UINT64_MAX. + * + * If |base| is UINT64_MAX, this function returns 0 because UINT64_MAX + * is an invalid timestamp. Otherwise, if |base| + |d| >= UINT64_MAX, + * this function returns 0. + * + * !ngtcp2_tstamp_elapsed() == ngtcp2_tstamp_not_elapsed() does not + * hold when |base| is UINT64_MAX. If you need nonzero if |base| is + * UINT64_MAX, use !ngtcp2_tstamp_elapsed. Otherwise, use + * ngtcp2_tstamp_not_elapsed. + */ +static inline int ngtcp2_tstamp_elapsed(ngtcp2_tstamp base, ngtcp2_duration d, + ngtcp2_tstamp ts) { + return base != UINT64_MAX && base < UINT64_MAX - d && base + d <= ts; +} + +/* + * ngtcp2_tstamp_not_elapsed returns nonzero if |d| has not passed + * since |base|. |ts| expresses a current time, and must not be + * UINT64_MAX. + * + * If |base| is UINT64_MAX, this function returns 0 because UINT64_MAX + * is an invalid timestamp. Otherwise, if |base| + |d| >= UINT64_MAX, + * this function returns nonzero. + */ +static inline int ngtcp2_tstamp_not_elapsed(ngtcp2_tstamp base, + ngtcp2_duration d, + ngtcp2_tstamp ts) { + return base != UINT64_MAX && (base >= UINT64_MAX - d || base + d > ts); +} + +#endif /* NGTCP2_TSTAMP_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c new file mode 100644 index 00000000000000..7c7d9ae78e914d --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.c @@ -0,0 +1,71 @@ +/* + * ngtcp2 + * + * Copyright (c) 2022 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_unreachable.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#ifdef WIN32 +# include +#endif /* WIN32 */ + +void ngtcp2_unreachable_fail(const char *file, int line, const char *func) { + char *buf; + size_t buflen; + int rv; + +#define NGTCP2_UNREACHABLE_TEMPLATE "%s:%d %s: Unreachable.\n" + + rv = snprintf(NULL, 0, NGTCP2_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + + /* here we explicitly use system malloc */ + buflen = (size_t)rv + 1; + buf = malloc(buflen); + if (buf == NULL) { + abort(); + } + + rv = snprintf(buf, buflen, NGTCP2_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + +#ifndef WIN32 + while (write(STDERR_FILENO, buf, (size_t)rv) == -1 && errno == EINTR) + ; +#else /* WIN32 */ + _write(_fileno(stderr), buf, (unsigned int)rv); +#endif /* WIN32 */ + + free(buf); + + abort(); +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h new file mode 100644 index 00000000000000..a5276fd505463f --- /dev/null +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_unreachable.h @@ -0,0 +1,52 @@ +/* + * ngtcp2 + * + * Copyright (c) 2022 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_UNREACHABLE_H +#define NGTCP2_UNREACHABLE_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#ifdef __FILE_NAME__ +# define NGTCP2_FILE_NAME __FILE_NAME__ +#else /* !__FILE_NAME__ */ +# define NGTCP2_FILE_NAME "(file)" +#endif /* !__FILE_NAME__ */ + +#define ngtcp2_unreachable() \ + ngtcp2_unreachable_fail(NGTCP2_FILE_NAME, __LINE__, __func__) + +#ifdef _MSC_VER +__declspec(noreturn) +#endif /* _MSC_VER */ + void ngtcp2_unreachable_fail(const char *file, int line, const char *func) +#ifndef _MSC_VER + __attribute__((noreturn)) +#endif /* !_MSC_VER */ + ; + +#endif /* NGTCP2_UNREACHABLE_H */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c index 257332e27a2abe..dbc7b668042695 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_vec.c @@ -145,7 +145,7 @@ ngtcp2_ssize ngtcp2_vec_split(ngtcp2_vec *src, size_t *psrccnt, ngtcp2_vec *dst, size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, size_t *psrccnt, size_t left, size_t maxcnt) { size_t orig_left = left; - size_t i; + size_t i = 0; ngtcp2_vec *a, *b; assert(maxcnt); @@ -158,12 +158,7 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, a = &dst[0]; b = &src[0]; - if (left >= b->len) { - *a = *b; - ++*pdstcnt; - left -= b->len; - i = 1; - } else { + if (left < b->len) { a->len = left; a->base = b->base; @@ -172,41 +167,43 @@ size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src, return left; } - } else { - i = 0; + + *a = *b; + ++*pdstcnt; + left -= b->len; + i = 1; } for (; left && i < *psrccnt; ++i) { a = &dst[*pdstcnt - 1]; b = &src[i]; - if (left >= b->len) { + if (left < b->len) { if (a->base + a->len == b->base) { - a->len += b->len; + a->len += left; } else if (*pdstcnt == maxcnt) { break; } else { - dst[(*pdstcnt)++] = *b; + dst[*pdstcnt].len = left; + dst[*pdstcnt].base = b->base; + ++*pdstcnt; } - left -= b->len; - continue; + + b->len -= left; + b->base += left; + left = 0; + + break; } if (a->base + a->len == b->base) { - a->len += left; + a->len += b->len; } else if (*pdstcnt == maxcnt) { break; } else { - dst[*pdstcnt].len = left; - dst[*pdstcnt].base = b->base; - ++*pdstcnt; + dst[(*pdstcnt)++] = *b; } - - b->len -= left; - b->base += left; - left = 0; - - break; + left -= b->len; } memmove(src, src + i, sizeof(ngtcp2_vec) * (*psrccnt - i));