From 6b27d07779f95c5d079d4dd4103cc6c9116c1bc6 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 22 Jun 2020 18:04:28 -0700 Subject: [PATCH] deps: update ngtcp2 PR-URL: https://github.com/nodejs/node/pull/34033 Reviewed-By: Anna Henningsen Reviewed-By: Jiawen Geng Reviewed-By: Daniel Bevenius --- .../crypto/includes/ngtcp2/ngtcp2_crypto.h | 199 +- deps/ngtcp2/crypto/openssl/openssl.c | 56 +- deps/ngtcp2/crypto/shared.c | 251 +- deps/ngtcp2/crypto/shared.h | 96 + deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h | 606 +++-- deps/ngtcp2/lib/includes/ngtcp2/version.h | 4 +- deps/ngtcp2/lib/includes/ngtcp2/version.h.in | 45 - deps/ngtcp2/lib/ngtcp2_acktr.c | 45 +- deps/ngtcp2/lib/ngtcp2_acktr.h | 6 + deps/ngtcp2/lib/ngtcp2_cc.c | 483 +++- deps/ngtcp2/lib/ngtcp2_cc.h | 117 +- deps/ngtcp2/lib/ngtcp2_conn.c | 2248 +++++++++-------- deps/ngtcp2/lib/ngtcp2_conn.h | 137 +- deps/ngtcp2/lib/ngtcp2_crypto.c | 173 +- deps/ngtcp2/lib/ngtcp2_crypto.h | 6 +- deps/ngtcp2/lib/ngtcp2_err.c | 2 + deps/ngtcp2/lib/ngtcp2_gaptr.c | 34 +- deps/ngtcp2/lib/ngtcp2_ksl.c | 177 +- deps/ngtcp2/lib/ngtcp2_ksl.h | 33 +- deps/ngtcp2/lib/ngtcp2_log.c | 93 +- deps/ngtcp2/lib/ngtcp2_log.h | 19 - deps/ngtcp2/lib/ngtcp2_net.h | 91 - deps/ngtcp2/lib/ngtcp2_pipeack.c | 155 -- deps/ngtcp2/lib/ngtcp2_pipeack.h | 89 - deps/ngtcp2/lib/ngtcp2_pkt.c | 110 +- deps/ngtcp2/lib/ngtcp2_pkt.h | 17 +- deps/ngtcp2/lib/ngtcp2_ppe.c | 2 +- deps/ngtcp2/lib/ngtcp2_psl.c | 621 ----- deps/ngtcp2/lib/ngtcp2_psl.h | 231 -- deps/ngtcp2/lib/ngtcp2_qlog.c | 61 +- deps/ngtcp2/lib/ngtcp2_qlog.h | 11 +- deps/ngtcp2/lib/ngtcp2_rcvry.h | 2 +- deps/ngtcp2/lib/ngtcp2_rob.c | 48 +- deps/ngtcp2/lib/ngtcp2_rst.c | 34 +- deps/ngtcp2/lib/ngtcp2_rst.h | 16 +- deps/ngtcp2/lib/ngtcp2_rtb.c | 249 +- deps/ngtcp2/lib/ngtcp2_rtb.h | 52 +- deps/ngtcp2/lib/ngtcp2_strm.c | 24 +- deps/ngtcp2/ngtcp2.gyp | 10 +- 39 files changed, 3290 insertions(+), 3363 deletions(-) delete mode 100644 deps/ngtcp2/lib/includes/ngtcp2/version.h.in delete mode 100644 deps/ngtcp2/lib/ngtcp2_net.h delete mode 100644 deps/ngtcp2/lib/ngtcp2_pipeack.c delete mode 100644 deps/ngtcp2/lib/ngtcp2_pipeack.h delete mode 100644 deps/ngtcp2/lib/ngtcp2_psl.c delete mode 100644 deps/ngtcp2/lib/ngtcp2_psl.h diff --git a/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h b/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h index d405e0d1336986..3197c5dcb86729 100644 --- a/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h +++ b/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h @@ -175,7 +175,7 @@ ngtcp2_crypto_packet_protection_ivlen(const ngtcp2_crypto_aead *aead); /** * @function * - * `ngtcp2_crypto_derive_packet_protection_key` dervies packet + * `ngtcp2_crypto_derive_packet_protection_key` derives packet * protection key. This function writes packet protection key into * the buffer pointed by |key|. |key| must point to the buffer which * is at least ngtcp2_crypto_aead_keylen(aead) bytes long. This @@ -237,7 +237,7 @@ 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 - - * ngtcp2_crypto_aead_taglen(aead) bytes log. |dest| must have enough + * ngtcp2_crypto_aead_taglen(aead) bytes long. |dest| must have enough * capacity to store the plaintext. It is allowed to specify the same * value to |dest| and |ciphertext|. * @@ -298,32 +298,17 @@ NGTCP2_EXTERN int ngtcp2_crypto_hp_mask_cb(uint8_t *dest, /** * @function * - * `ngtcp2_crypto_derive_and_install_key` derives the rx and tx keys - * from |rx_secret| and |tx_secret| respectively and installs new keys - * to |conn|. + * `ngtcp2_crypto_derive_and_install_rx_key` derives the rx keys from + * |secret| and installs new keys 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 |rx_key| is not NULL, the derived packet protection key for - * decryption is written to the buffer pointed by |rx_key|. If - * |rx_iv| is not NULL, the derived packet protection IV for - * decryption is written to the buffer pointed by |rx_iv|. If |rx_hp| - * is not NULL, the derived header protection key for decryption is - * written to the buffer pointed by |rx_hp|. - * - * If |tx_key| is not NULL, the derived packet protection key for - * encryption is written to the buffer pointed by |tx_key|. If - * |tx_iv| is not NULL, the derived packet protection IV for - * encryption is written to the buffer pointed by |tx_iv|. If |tx_hp| - * is not NULL, the derived header protection key for encryption is - * written to the buffer pointed by |tx_hp|. - * - * |level| specifies the encryption level. If |level| is - * NGTCP2_CRYPTO_LEVEL_EARLY, and if |side| is - * NGTCP2_CRYPTO_SIDE_CLIENT, |rx_secret| must be NULL. If |level| is - * NGTCP2_CRYPTO_LEVEL_EARLY, and if |side| is - * NGTCP2_CRYPTO_SIDE_SERVER, |tx_secret| must be NULL. Otherwise, - * |rx_secret| and |tx_secret| must not be NULL. - * - * |secretlen| specifies the length of |rx_secret| and |tx_secret|. + * |secretlen| specifies the length of |secret|. * * The length of packet protection key and header protection key is * ngtcp2_crypto_aead(ctx->aead), and the length of packet protection @@ -337,71 +322,48 @@ NGTCP2_EXTERN int ngtcp2_crypto_hp_mask_cb(uint8_t *dest, * It also calls `ngtcp2_conn_set_aead_overhead` to set AEAD tag * length. * - * If |level| is NGTCP2_CRYPTO_LEVEL_APP, this function retrieves a - * remote QUIC transport parameters extension from |tls| and sets it - * to |conn|. - * * This function returns 0 if it succeeds, or -1. */ -NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_key( - ngtcp2_conn *conn, void *tls, uint8_t *rx_key, uint8_t *rx_iv, - uint8_t *rx_hp, uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp, - ngtcp2_crypto_level level, const uint8_t *rx_secret, - const uint8_t *tx_secret, size_t secretlen, ngtcp2_crypto_side side); +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); /** * @function * - * `ngtcp2_crypto_derive_and_install_initial_key` derives initial - * keying materials and installs keys to |conn|. - * - * If |rx_secret| is not NULL, the secret for decryption is written to - * the buffer pointed by |rx_secret|. The length of secret is 32 - * bytes, and |rx_secret| must point to the buffer which has enough - * capacity. - * - * If |tx_secret| is not NULL, the secret for encryption is written to - * the buffer pointed by |tx_secret|. The length of secret is 32 - * bytes, and |tx_secret| must point to the buffer which has enough - * capacity. - * - * If |initial_secret| is not NULL, the initial secret is written to - * the buffer pointed by |initial_secret|. The length of secret is 32 - * bytes, and |initial_secret| must point to the buffer which has - * enough capacity. - * - * |client_dcid| is the destination connection ID in first Initial - * packet of client. - * - * If |rx_key| is not NULL, the derived packet protection key for - * decryption is written to the buffer pointed by |rx_key|. If - * |rx_iv| is not NULL, the derived packet protection IV for - * decryption is written to the buffer pointed by |rx_iv|. If |rx_hp| - * is not NULL, the derived header protection key for decryption is - * written to the buffer pointed by |rx_hp|. - * - * If |tx_key| is not NULL, the derived packet protection key for - * encryption is written to the buffer pointed by |tx_key|. If - * |tx_iv| is not NULL, the derived packet protection IV for - * encryption is written to the buffer pointed by |tx_iv|. If |tx_hp| - * is not NULL, the derived header protection key for encryption is - * written to the buffer pointed by |tx_hp|. - * - * The length of packet protection key and header protection key is 16 - * bytes long. The length of packet protection IV is 12 bytes long. - * - * This function calls `ngtcp2_conn_set_initial_crypto_ctx` to set - * initial AEAD and message digest algorithm. After the successful - * call of this function, application can use - * `ngtcp2_conn_get_initial_crypto_ctx` to get the object. + * `ngtcp2_crypto_derive_and_install_tx_key` derives the tx keys 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|. + * + * |secretlen| specifies the length of |secret|. + * + * The length of packet protection key and header protection key is + * ngtcp2_crypto_aead(ctx->aead), and the length of packet protection + * IV is ngtcp2_crypto_packet_protection_ivlen(ctx->aead) where ctx + * can be obtained by `ngtcp2_crypto_ctx_tls`. + * + * In the first call of this function, it calls + * `ngtcp2_conn_set_crypto_ctx` to set negotiated AEAD and message + * digest algorithm. After the successful call of this function, + * application can use `ngtcp2_conn_get_crypto_ctx` to get the object. + * It also calls `ngtcp2_conn_set_aead_overhead` to set AEAD tag + * length. + * + * If |level| is NGTCP2_CRYPTO_LEVEL_APP, this function retrieves a + * remote QUIC transport parameters extension from |tls| and sets it + * to |conn|. * * This function returns 0 if it succeeds, or -1. */ -NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_initial_key( - ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, - uint8_t *initial_secret, uint8_t *rx_key, uint8_t *rx_iv, uint8_t *rx_hp, - uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp, - const ngtcp2_cid *client_dcid, ngtcp2_crypto_side side); +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); /** * @function @@ -458,6 +420,54 @@ NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb( const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, size_t secretlen, void *user_data); +/** + * @function + * + * `ngtcp2_crypto_client_initial_cb` installs initial secrets and + * encryption keys and sets QUIC transport parameters. + * + * This function can be directly passed to client_initial field in + * ngtcp2_callbacks. It is only used by client. + * + * This function returns 0 if it succeeds, or + * :enum:`NGTCP2_ERR_CALLBACK_FAILURE`. + */ +NGTCP2_EXTERN int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, + void *user_data); + +/** + * @function + * + * `ngtcp2_crypto_recv_retry_cb` re-installs initial secrets in + * response to incoming Retry packet. + * + * This function can be directly passed to recv_retry field in + * ngtcp2_callbacks. It is only used by client. + * + * This function returns 0 if it succeeds, or + * :enum:`NGTCP2_ERR_CALLBACK_FAILURE`. + */ +NGTCP2_EXTERN int ngtcp2_crypto_recv_retry_cb(ngtcp2_conn *conn, + const ngtcp2_pkt_hd *hd, + void *user_data); + +/** + * @function + * + * `ngtcp2_crypto_recv_client_initial_cb` installs initial secrets in + * response to an incoming Initial packet from client, and sets QUIC + * transport parameters. + * + * This function can be directly passed to recv_client_initial field + * in ngtcp2_callbacks. It is only used by server. + * + * This function returns 0 if it succeeds, or + * :enum:`NGTCP2_ERR_CALLBACK_FAILURE`. + */ +NGTCP2_EXTERN int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn, + const ngtcp2_cid *dcid, + void *user_data); + /** * @function * @@ -468,10 +478,6 @@ NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb( * allowed to call this function with datalen == 0. In this case, no * additional read operation is done. * - * |tls| points to a implementation dependent TLS session object. If - * libngtcp2_crypto_openssl is linked, |tls| must be a pointer to SSL - * object. - * * 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 @@ -479,27 +485,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb( * defined in ngtcp2_crypto_openssl.h. */ NGTCP2_EXTERN int -ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, void *tls, +ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, const uint8_t *data, size_t datalen); -/** - * @function - * - * `ngtcp2_crypto_set_remote_transport_params` retrieves a remote QUIC - * transport parameters from |tls| and sets it to |conn| using - * `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 - * object. - * - * This function returns 0 if it succeeds, or -1. - */ -NGTCP2_EXTERN int -ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls, - ngtcp2_crypto_side side); - /** * @function * diff --git a/deps/ngtcp2/crypto/openssl/openssl.c b/deps/ngtcp2/crypto/openssl/openssl.c index 5e6a8493074a8e..60e7250eae9dbe 100644 --- a/deps/ngtcp2/crypto/openssl/openssl.c +++ b/deps/ngtcp2/crypto/openssl/openssl.c @@ -35,10 +35,14 @@ #include #include +#include "shared.h" + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) { ctx->aead.native_handle = (void *)EVP_aes_128_gcm(); ctx->md.native_handle = (void *)EVP_sha256(); ctx->hp.native_handle = (void *)EVP_aes_128_ctr(); + ctx->max_encryption = 0; + ctx->max_decryption_failure = 0; return ctx; } @@ -62,6 +66,34 @@ static const EVP_CIPHER *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))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_AES_256_GCM_SHA384: + return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM; + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305; + case TLS1_3_CK_AES_128_CCM_SHA256: + return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_CCM; + default: + return 0; + } +} + +static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) { + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_AES_256_GCM_SHA384: + return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM; + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305; + case TLS1_3_CK_AES_128_CCM_SHA256: + return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM; + default: + return 0; + } +} + static const EVP_CIPHER *crypto_ssl_get_hp(SSL *ssl) { switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { case TLS1_3_CK_AES_128_GCM_SHA256: @@ -95,6 +127,8 @@ ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, ctx->aead.native_handle = (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; } @@ -313,10 +347,10 @@ from_ngtcp2_level(ngtcp2_crypto_level crypto_level) { } } -int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, void *tls, +int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, const uint8_t *data, size_t datalen) { - SSL *ssl = tls; + SSL *ssl = ngtcp2_conn_get_tls_native_handle(conn); int rv; int err; @@ -365,13 +399,12 @@ int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, void *tls, return 0; } -int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls, - ngtcp2_crypto_side side) { +int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) { SSL *ssl = tls; ngtcp2_transport_params_type exttype = - side == NGTCP2_CRYPTO_SIDE_CLIENT - ? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS - : NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO; + ngtcp2_conn_is_server(conn) + ? NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO + : NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS; const uint8_t *tp; size_t tplen; ngtcp2_transport_params params; @@ -393,3 +426,12 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls, return 0; } + +int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, + size_t len) { + if (SSL_set_quic_transport_params(tls, buf, len) != 1) { + return -1; + } + + return 0; +} diff --git a/deps/ngtcp2/crypto/shared.c b/deps/ngtcp2/crypto/shared.c index 6304e59639de47..bea088e85f3745 100644 --- a/deps/ngtcp2/crypto/shared.c +++ b/deps/ngtcp2/crypto/shared.c @@ -145,37 +145,32 @@ int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, return 0; } -int ngtcp2_crypto_derive_and_install_key( - ngtcp2_conn *conn, void *tls, uint8_t *rx_key, uint8_t *rx_iv, - uint8_t *rx_hp_key, uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp_key, - ngtcp2_crypto_level level, const uint8_t *rx_secret, - const uint8_t *tx_secret, size_t secretlen, ngtcp2_crypto_side side) { +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, + const uint8_t *secret, + size_t secretlen) { const ngtcp2_crypto_ctx *ctx; const ngtcp2_crypto_aead *aead; const ngtcp2_crypto_md *md; - uint8_t rx_keybuf[64], rx_ivbuf[64], rx_hp_keybuf[64]; - uint8_t tx_keybuf[64], tx_ivbuf[64], tx_hp_keybuf[64]; + void *tls = ngtcp2_conn_get_tls_native_handle(conn); + uint8_t keybuf[64], ivbuf[64], hp_keybuf[64]; size_t keylen; size_t ivlen; int rv; - if (!rx_key) { - rx_key = rx_keybuf; - } - if (!rx_iv) { - rx_iv = rx_ivbuf; - } - if (!rx_hp_key) { - rx_hp_key = rx_hp_keybuf; + if (level == NGTCP2_CRYPTO_LEVEL_EARLY && !ngtcp2_conn_is_server(conn)) { + return 0; } - if (!tx_key) { - tx_key = tx_keybuf; + + if (!key) { + key = keybuf; } - if (!tx_iv) { - tx_iv = tx_ivbuf; + if (!iv) { + iv = ivbuf; } - if (!tx_hp_key) { - tx_hp_key = tx_hp_keybuf; + if (!hp_key) { + hp_key = hp_keybuf; } ctx = ngtcp2_conn_get_crypto_ctx(conn); @@ -193,50 +188,119 @@ int ngtcp2_crypto_derive_and_install_key( keylen = ngtcp2_crypto_aead_keylen(aead); ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); - if ((level != NGTCP2_CRYPTO_LEVEL_EARLY || - side == NGTCP2_CRYPTO_SIDE_SERVER) && - ngtcp2_crypto_derive_packet_protection_key( - rx_key, rx_iv, rx_hp_key, aead, md, rx_secret, secretlen) != 0) { - return -1; - } - - if ((level != NGTCP2_CRYPTO_LEVEL_EARLY || - side == NGTCP2_CRYPTO_SIDE_CLIENT) && - ngtcp2_crypto_derive_packet_protection_key( - tx_key, tx_iv, tx_hp_key, aead, md, tx_secret, secretlen) != 0) { + if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md, + secret, secretlen) != 0) { return -1; } switch (level) { case NGTCP2_CRYPTO_LEVEL_EARLY: - if (side == NGTCP2_CRYPTO_SIDE_CLIENT) { - rv = ngtcp2_conn_install_early_key(conn, tx_key, tx_iv, tx_hp_key, keylen, - ivlen); - } else { - rv = ngtcp2_conn_install_early_key(conn, rx_key, rx_iv, rx_hp_key, keylen, - ivlen); - } + rv = ngtcp2_conn_install_early_key(conn, key, iv, hp_key, keylen, ivlen); if (rv != 0) { return -1; } break; case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: - rv = ngtcp2_conn_install_handshake_key(conn, rx_key, rx_iv, rx_hp_key, - tx_key, tx_iv, tx_hp_key, keylen, - ivlen); + rv = ngtcp2_conn_install_rx_handshake_key(conn, key, iv, hp_key, keylen, + ivlen); if (rv != 0) { return -1; } break; case NGTCP2_CRYPTO_LEVEL_APP: - rv = ngtcp2_crypto_set_remote_transport_params(conn, tls, side); + if (!ngtcp2_conn_is_server(conn)) { + rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); + if (rv != 0) { + return -1; + } + } + + rv = ngtcp2_conn_install_rx_key(conn, secret, key, iv, hp_key, secretlen, + keylen, ivlen); if (rv != 0) { return -1; } - rv = ngtcp2_conn_install_key(conn, rx_secret, tx_secret, rx_key, rx_iv, - rx_hp_key, tx_key, tx_iv, tx_hp_key, secretlen, - keylen, ivlen); + break; + default: + return -1; + } + + return 0; +} + +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, + const uint8_t *secret, + size_t secretlen) { + const ngtcp2_crypto_ctx *ctx; + const ngtcp2_crypto_aead *aead; + const ngtcp2_crypto_md *md; + void *tls = ngtcp2_conn_get_tls_native_handle(conn); + uint8_t keybuf[64], ivbuf[64], hp_keybuf[64]; + size_t keylen; + size_t ivlen; + int rv; + + if (level == NGTCP2_CRYPTO_LEVEL_EARLY && ngtcp2_conn_is_server(conn)) { + return 0; + } + + if (!key) { + key = keybuf; + } + if (!iv) { + iv = ivbuf; + } + if (!hp_key) { + hp_key = hp_keybuf; + } + + ctx = ngtcp2_conn_get_crypto_ctx(conn); + + if (!ctx->aead.native_handle) { + ngtcp2_crypto_ctx cctx; + ngtcp2_crypto_ctx_tls(&cctx, tls); + ngtcp2_conn_set_aead_overhead(conn, ngtcp2_crypto_aead_taglen(&cctx.aead)); + ngtcp2_conn_set_crypto_ctx(conn, &cctx); + ctx = ngtcp2_conn_get_crypto_ctx(conn); + } + + aead = &ctx->aead; + md = &ctx->md; + keylen = ngtcp2_crypto_aead_keylen(aead); + ivlen = ngtcp2_crypto_packet_protection_ivlen(aead); + + if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md, + secret, secretlen) != 0) { + return -1; + } + + switch (level) { + case NGTCP2_CRYPTO_LEVEL_EARLY: + rv = ngtcp2_conn_install_early_key(conn, key, iv, hp_key, keylen, ivlen); + if (rv != 0) { + return -1; + } + break; + case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + if (ngtcp2_conn_is_server(conn)) { + rv = ngtcp2_crypto_set_remote_transport_params(conn, tls); + if (rv != 0) { + return -1; + } + } + + rv = ngtcp2_conn_install_tx_handshake_key(conn, key, iv, hp_key, keylen, + ivlen); + if (rv != 0) { + return -1; + } + break; + case NGTCP2_CRYPTO_LEVEL_APP: + rv = ngtcp2_conn_install_tx_key(conn, secret, key, iv, hp_key, secretlen, + keylen, ivlen); if (rv != 0) { return -1; } @@ -253,7 +317,7 @@ int ngtcp2_crypto_derive_and_install_initial_key( ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *initial_secret, uint8_t *rx_key, uint8_t *rx_iv, uint8_t *rx_hp_key, uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp_key, - const ngtcp2_cid *client_dcid, ngtcp2_crypto_side side) { + const ngtcp2_cid *client_dcid) { uint8_t rx_secretbuf[NGTCP2_CRYPTO_INITIAL_SECRETLEN]; uint8_t tx_secretbuf[NGTCP2_CRYPTO_INITIAL_SECRETLEN]; uint8_t initial_secretbuf[NGTCP2_CRYPTO_INITIAL_SECRETLEN]; @@ -300,8 +364,10 @@ int ngtcp2_crypto_derive_and_install_initial_key( ngtcp2_conn_set_initial_crypto_ctx(conn, &ctx); - if (ngtcp2_crypto_derive_initial_secrets(rx_secret, tx_secret, initial_secret, - client_dcid, side) != 0) { + if (ngtcp2_crypto_derive_initial_secrets( + rx_secret, tx_secret, initial_secret, client_dcid, + ngtcp2_conn_is_server(conn) ? NGTCP2_CRYPTO_SIDE_SERVER + : NGTCP2_CRYPTO_SIDE_CLIENT) != 0) { return -1; } @@ -486,3 +552,90 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, return spktlen; } + +/* + * crypto_set_local_transport_params gets local QUIC transport + * parameters from |conn| and sets it to |tls|. + * + * This function returns 0 if it succeeds, or -1. + */ +static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) { + ngtcp2_transport_params_type exttype = + ngtcp2_conn_is_server(conn) + ? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS + : NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO; + ngtcp2_transport_params params; + ngtcp2_ssize nwrite; + uint8_t buf[256]; + + ngtcp2_conn_get_local_transport_params(conn, ¶ms); + + nwrite = ngtcp2_encode_transport_params(buf, sizeof(buf), exttype, ¶ms); + if (nwrite < 0) { + return -1; + } + + if (ngtcp2_crypto_set_local_transport_params(tls, buf, (size_t)nwrite) != 0) { + return -1; + } + + return 0; +} + +/* + * crypto_setup_initial_crypto establishes the initial secrets and + * encryption keys, and prepares local QUIC transport parameters. + */ +static int crypto_setup_initial_crypto(ngtcp2_conn *conn, + const ngtcp2_cid *dcid) { + void *tls = ngtcp2_conn_get_tls_native_handle(conn); + + if (ngtcp2_crypto_derive_and_install_initial_key(conn, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + dcid) != 0) { + return -1; + } + + return crypto_set_local_transport_params(conn, tls); +} + +int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, void *user_data) { + const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(conn); + (void)user_data; + + if (crypto_setup_initial_crypto(conn, dcid) != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + if (ngtcp2_crypto_read_write_crypto_data(conn, NGTCP2_CRYPTO_LEVEL_INITIAL, + NULL, 0) != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +int ngtcp2_crypto_recv_retry_cb(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, + void *user_data) { + (void)user_data; + + if (ngtcp2_crypto_derive_and_install_initial_key(conn, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + &hd->scid) != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn, + const ngtcp2_cid *dcid, + void *user_data) { + (void)user_data; + + if (crypto_setup_initial_crypto(conn, dcid) != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} diff --git a/deps/ngtcp2/crypto/shared.h b/deps/ngtcp2/crypto/shared.h index 87f3d8928f0a2e..a904f6994fb2fa 100644 --- a/deps/ngtcp2/crypto/shared.h +++ b/deps/ngtcp2/crypto/shared.h @@ -31,6 +31,16 @@ #include +/* Maximum key usage (encryption) limits */ +#define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM (23726566ULL) +#define NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305 (1ULL << 62) +#define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_CCM (1ULL << 23) + +/* Maximum authentication failure (decryption) limits */ +#define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM (1ULL << 36) +#define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305 (1ULL << 36) +#define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM (11863283ULL) + /** * @function * @@ -69,4 +79,90 @@ int ngtcp2_crypto_update_traffic_secret(uint8_t *dest, const uint8_t *secret, size_t secretlen); +/** + * @function + * + * `ngtcp2_crypto_set_local_transport_params` sets QUIC transport + * parameter, which is encoded in wire format and stored in the buffer + * 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 + * object. + * + * This function returns 0 if it succeeds, or -1. + */ +int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf, + size_t len); + +/** + * @function + * + * `ngtcp2_crypto_set_remote_transport_params` retrieves a remote QUIC + * transport parameters from |tls| and sets it to |conn| using + * `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 + * object. + * + * This function returns 0 if it succeeds, or -1. + */ +int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls); + + +/** + * @function + * + * `ngtcp2_crypto_derive_and_install_initial_key` derives initial + * keying materials and installs keys to |conn|. + * + * If |rx_secret| is not NULL, the secret for decryption is written to + * the buffer pointed by |rx_secret|. The length of secret is 32 + * bytes, and |rx_secret| must point to the buffer which has enough + * capacity. + * + * If |tx_secret| is not NULL, the secret for encryption is written to + * the buffer pointed by |tx_secret|. The length of secret is 32 + * bytes, and |tx_secret| must point to the buffer which has enough + * capacity. + * + * If |initial_secret| is not NULL, the initial secret is written to + * the buffer pointed by |initial_secret|. The length of secret is 32 + * bytes, and |initial_secret| must point to the buffer which has + * enough capacity. + * + * |client_dcid| is the destination connection ID in first Initial + * packet of client. + * + * If |rx_key| is not NULL, the derived packet protection key for + * decryption is written to the buffer pointed by |rx_key|. If + * |rx_iv| is not NULL, the derived packet protection IV for + * decryption is written to the buffer pointed by |rx_iv|. If |rx_hp| + * is not NULL, the derived header protection key for decryption is + * written to the buffer pointed by |rx_hp|. + * + * If |tx_key| is not NULL, the derived packet protection key for + * encryption is written to the buffer pointed by |tx_key|. If + * |tx_iv| is not NULL, the derived packet protection IV for + * encryption is written to the buffer pointed by |tx_iv|. If |tx_hp| + * is not NULL, the derived header protection key for encryption is + * written to the buffer pointed by |tx_hp|. + * + * The length of packet protection key and header protection key is 16 + * bytes long. The length of packet protection IV is 12 bytes long. + * + * This function calls `ngtcp2_conn_set_initial_crypto_ctx` to set + * initial AEAD and message digest algorithm. After the successful + * call of this function, application can use + * `ngtcp2_conn_get_initial_crypto_ctx` to get the object. + * + * This function returns 0 if it succeeds, or -1. + */ +int ngtcp2_crypto_derive_and_install_initial_key( + ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, + uint8_t *initial_secret, uint8_t *rx_key, uint8_t *rx_iv, uint8_t *rx_hp, + uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp, + const ngtcp2_cid *client_dcid); + #endif /* NGTCP2_SHARED_H */ diff --git a/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h b/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h index a2f7d67a5ce2bd..29cf3e542509d2 100644 --- a/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h +++ b/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h @@ -159,16 +159,11 @@ typedef struct ngtcp2_mem { } ngtcp2_mem; /* NGTCP2_PROTO_VER is the supported QUIC protocol version. */ -#define NGTCP2_PROTO_VER 0xff00001bu +#define NGTCP2_PROTO_VER 0xff00001du /* NGTCP2_PROTO_VER_MAX is the highest QUIC version the library supports. */ #define NGTCP2_PROTO_VER_MAX NGTCP2_PROTO_VER -/* NGTCP2_ALPN_H3 is a serialized form of HTTP/3 ALPN protocol - identifier this library supports. Notice that the first byte is - the length of the following protocol identifier. */ -#define NGTCP2_ALPN_H3 "\x5h3-27" - #define NGTCP2_MAX_PKTLEN_IPV4 1252 #define NGTCP2_MAX_PKTLEN_IPV6 1232 @@ -176,6 +171,11 @@ typedef struct ngtcp2_mem { packet sent by client which contains its first Initial packet. */ #define NGTCP2_MIN_INITIAL_PKTLEN 1200 +/* NGTCP2_DEFAULT_MAX_PKTLEN is the default maximum size of UDP + datagram payload that this endpoint transmits. It is used by + congestion controller to compute congestion window. */ +#define NGTCP2_DEFAULT_MAX_PKTLEN 1200 + /* NGTCP2_STATELESS_RESET_TOKENLEN is the length of Stateless Reset Token. */ #define NGTCP2_STATELESS_RESET_TOKENLEN 16 @@ -187,8 +187,8 @@ typedef struct ngtcp2_mem { /* NGTCP2_INITIAL_SALT is a salt value which is used to derive initial secret. */ #define NGTCP2_INITIAL_SALT \ - "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7\xd2\x43\x2b\xb4\x63\x65\xbe\xf9" \ - "\xf5\x02" + "\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97\x86\xf1\x9c\x61\x11\xe0\x43\x90" \ + "\xa8\x99" /* NGTCP2_HP_MASKLEN is the length of header protection mask. */ #define NGTCP2_HP_MASKLEN 5 @@ -250,6 +250,7 @@ typedef enum ngtcp2_lib_error { NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED = -239, NGTCP2_ERR_WRITE_STREAM_MORE = -240, NGTCP2_ERR_RETRY = -241, + NGTCP2_ERR_DROP_CONN = -242, NGTCP2_ERR_FATAL = -500, NGTCP2_ERR_NOMEM = -501, NGTCP2_ERR_CALLBACK_FAILURE = -502, @@ -280,7 +281,7 @@ typedef enum ngtcp2_pkt_type { /* QUIC transport error code. */ #define NGTCP2_NO_ERROR 0x0u #define NGTCP2_INTERNAL_ERROR 0x1u -#define NGTCP2_SERVER_BUSY 0x2u +#define NGTCP2_CONNECTION_REFUSED 0x2u #define NGTCP2_FLOW_CONTROL_ERROR 0x3u #define NGTCP2_STREAM_LIMIT_ERROR 0x4u #define NGTCP2_STREAM_STATE_ERROR 0x5u @@ -290,6 +291,7 @@ typedef enum ngtcp2_pkt_type { #define NGTCP2_CONNECTION_ID_LIMIT_ERROR 0x9u #define NGTCP2_PROTOCOL_VIOLATION 0xau #define NGTCP2_INVALID_TOKEN 0xbu +#define NGTCP2_APPLICATION_ERROR 0xcu #define NGTCP2_CRYPTO_BUFFER_EXCEEDED 0xdu #define NGTCP2_KEY_UPDATE_ERROR 0xeu #define NGTCP2_CRYPTO_ERROR 0x100u @@ -304,13 +306,12 @@ typedef enum ngtcp2_path_validation_result { } ngtcp2_path_validation_result; /* - * ngtcp2_tstamp is a timestamp with NGTCP2_DURATION_TICK resolution. + * ngtcp2_tstamp is a timestamp with nanosecond resolution. */ typedef uint64_t ngtcp2_tstamp; /* - * ngtcp2_duration is a period of time in NGTCP2_DURATION_TICK - * resolution. + * ngtcp2_duration is a period of time in nanosecond resolution. */ typedef uint64_t ngtcp2_duration; @@ -319,6 +320,11 @@ typedef uint64_t ngtcp2_duration; /* NGTCP2_MIN_CIDLEN is the minimum length of Connection ID. */ #define NGTCP2_MIN_CIDLEN 1 +/* NGTCP2_MIN_INITIAL_DCIDLEN is the minimum length of Destination + Connection ID in Client Initial packet if it does not bear token + from Retry packet. */ +#define NGTCP2_MIN_INITIAL_DCIDLEN 8 + /** * @struct * @@ -358,8 +364,7 @@ typedef struct ngtcp2_pkt_hd { ngtcp2_cid dcid; ngtcp2_cid scid; int64_t pkt_num; - uint8_t *token; - size_t tokenlen; + ngtcp2_vec token; /** * pkt_numlen is the number of bytes spent to encode pkt_num. */ @@ -380,25 +385,15 @@ typedef struct ngtcp2_pkt_stateless_reset { size_t randlen; } ngtcp2_pkt_stateless_reset; -/* NGTCP2_RETRY_TAGLEN is the length of Retry packet integrity tag. */ -#define NGTCP2_RETRY_TAGLEN 16 - -typedef struct ngtcp2_pkt_retry { - ngtcp2_cid odcid; - const uint8_t *token; - size_t tokenlen; - uint8_t tag[NGTCP2_RETRY_TAGLEN]; -} ngtcp2_pkt_retry; - #if defined(__cplusplus) && __cplusplus >= 201103L -typedef enum ngtcp2_transport_param_id : uint16_t { +typedef enum ngtcp2_transport_param_id : int { #else typedef enum ngtcp2_transport_param_id { #endif - NGTCP2_TRANSPORT_PARAM_ORIGINAL_CONNECTION_ID = 0x0000, + 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_PACKET_SIZE = 0x0003, + 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, @@ -410,7 +405,8 @@ typedef enum ngtcp2_transport_param_id { NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION = 0x000c, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS = 0x000d, NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT = 0x000e, - NGTCP2_TRANSPORT_PARAM_ID_MAX = UINT16_MAX + NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID = 0x000f, + NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID = 0x0010 } ngtcp2_transport_param_id; #if defined(__cplusplus) && __cplusplus >= 201103L @@ -440,7 +436,11 @@ typedef enum ngtcp2_rand_ctx { NGTCP2_RAND_CTX_PATH_CHALLENGE } ngtcp2_rand_ctx; -#define NGTCP2_MAX_PKT_SIZE 65527 +/* + * NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE is the default value of + * max_udp_payload_size transport parameter. + */ +#define NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE 65527 /** * @macro @@ -486,11 +486,28 @@ typedef struct ngtcp2_preferred_addr { typedef struct ngtcp2_transport_params { ngtcp2_preferred_addr preferred_address; - /* original_connection_id is the client initial connection ID. - Server must specify this field and set - original_connection_id_present to nonzero if it sent Retry - packet. */ - ngtcp2_cid original_connection_id; + /* original_dcid is the Destination Connection ID field from the + first Initial packet from client. Server must specify this + field. If application specifies retry_scid_present to nonzero, + then it must also specify this field. It is expected that + application knows the original Destination Connection ID, for + example, by including it in retry token. Otherwise, application + should not specify this field. */ + ngtcp2_cid original_dcid; + /* initial_scid is the Source Connection ID field from the first + Initial packet the endpoint sends. Application should not + specify this field. */ + ngtcp2_cid initial_scid; + /* 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 + 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; /* 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 @@ -517,7 +534,7 @@ typedef struct ngtcp2_transport_params { /* max_idle_timeout is a duration during which sender allows quiescent. */ ngtcp2_duration max_idle_timeout; - uint64_t max_packet_size; + uint64_t max_udp_payload_size; /* active_connection_id_limit is the maximum number of Connection ID that sender can store. */ uint64_t active_connection_id_limit; @@ -525,11 +542,138 @@ typedef struct ngtcp2_transport_params { ngtcp2_duration max_ack_delay; uint8_t stateless_reset_token_present; uint8_t disable_active_migration; - uint8_t original_connection_id_present; + uint8_t retry_scid_present; uint8_t preferred_address_present; uint8_t stateless_reset_token[NGTCP2_STATELESS_RESET_TOKENLEN]; } ngtcp2_transport_params; +typedef struct ngtcp2_log ngtcp2_log; + +typedef enum ngtcp2_pktns_id { + /* NGTCP2_PKTNS_ID_INITIAL is the Initial packet number space. */ + NGTCP2_PKTNS_ID_INITIAL, + /* NGTCP2_PKTNS_ID_INITIAL is the Handshake packet number space. */ + NGTCP2_PKTNS_ID_HANDSHAKE, + /* NGTCP2_PKTNS_ID_INITIAL is the Application data packet number + space. */ + NGTCP2_PKTNS_ID_APP, + /* NGTCP2_PKTNS_ID_MAX is defined to get the number of packet number + spaces. */ + NGTCP2_PKTNS_ID_MAX +} ngtcp2_pktns_id; + +/** + * @struct + * + * ngtcp2_conn_stat holds various connection statistics, and computed + * data for recovery and congestion controller. + */ +typedef struct ngtcp2_conn_stat { + ngtcp2_duration latest_rtt; + ngtcp2_duration min_rtt; + ngtcp2_duration smoothed_rtt; + ngtcp2_duration rttvar; + size_t pto_count; + ngtcp2_tstamp loss_detection_timer; + /* last_tx_pkt_ts corresponds to + time_of_last_sent_ack_eliciting_packet in + draft-ietf-quic-recovery-25. */ + ngtcp2_tstamp last_tx_pkt_ts[NGTCP2_PKTNS_ID_MAX]; + ngtcp2_tstamp loss_time[NGTCP2_PKTNS_ID_MAX]; + uint64_t cwnd; + uint64_t ssthresh; + ngtcp2_tstamp congestion_recovery_start_ts; + uint64_t bytes_in_flight; + /* 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; + /* bytes_sent is the number of bytes sent in this particular + connection. It only includes data written by + `ngtcp2_conn_writev_stream()` .*/ + uint64_t bytes_sent; + /* bytes_recv is the number of bytes received in this particular + connection, including discarded packets. */ + uint64_t bytes_recv; + /* delivery_rate_sec is the current sending rate measured per + second. */ + uint64_t delivery_rate_sec; + /* recv_rate_sec is the current receiving rate of application data + measured in per second. */ + uint64_t recv_rate_sec; +} ngtcp2_conn_stat; + +typedef enum ngtcp2_cc_algo { + NGTCP2_CC_ALGO_RENO = 0x00, + NGTCP2_CC_ALGO_CUBIC = 0x01, + NGTCP2_CC_ALGO_CUSTOM = 0xff +} ngtcp2_cc_algo; + +typedef struct ngtcp2_cc_base { + ngtcp2_log *log; +} ngtcp2_cc_base; + +/* ngtcp2_cc_pkt is a convenient structure to include acked/lost/sent + packet. */ +typedef struct { + /* pkt_num is the packet number */ + int64_t pkt_num; + /* pktlen is the length of packet. */ + size_t pktlen; + /* pktns_id is the ID of packet number space which this packet + belongs to. */ + ngtcp2_pktns_id pktns_id; + /* ts_sent is the timestamp when packet is sent. */ + ngtcp2_tstamp ts_sent; +} ngtcp2_cc_pkt; + +typedef struct ngtcp2_cc ngtcp2_cc; + +typedef void (*ngtcp2_cc_on_pkt_acked)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, + ngtcp2_tstamp ts); + +typedef void (*ngtcp2_cc_congestion_event)(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts_sent, + ngtcp2_tstamp ts); + +typedef void (*ngtcp2_cc_on_persistent_congestion)(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +typedef void (*ngtcp2_cc_on_ack_recv)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +typedef void (*ngtcp2_cc_on_pkt_sent)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt); + +typedef void (*ngtcp2_cc_new_rtt_sample)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +typedef void (*ngtcp2_cc_reset)(ngtcp2_cc *cc); + +typedef enum ngtcp2_cc_event_type { + /* NGTCP2_CC_EVENT_TX_START occurs when ack-eliciting packet is sent + and no other ack-eliciting packet is present. */ + NGTCP2_CC_EVENT_TYPE_TX_START +} ngtcp2_cc_event_type; + +typedef void (*ngtcp2_cc_event)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_cc_event_type event, ngtcp2_tstamp ts); + +typedef struct ngtcp2_cc { + ngtcp2_cc_base *ccb; + ngtcp2_cc_on_pkt_acked on_pkt_acked; + ngtcp2_cc_congestion_event congestion_event; + ngtcp2_cc_on_persistent_congestion on_persistent_congestion; + ngtcp2_cc_on_ack_recv on_ack_recv; + ngtcp2_cc_on_pkt_sent on_pkt_sent; + ngtcp2_cc_new_rtt_sample new_rtt_sample; + ngtcp2_cc_reset reset; + ngtcp2_cc_event event; +} ngtcp2_cc; + /* user_data is the same object passed to ngtcp2_conn_client_new or ngtcp2_conn_server_new. */ typedef void (*ngtcp2_printf)(void *user_data, const char *format, ...); @@ -539,7 +683,8 @@ typedef void (*ngtcp2_qlog_write)(void *user_data, const void *data, typedef struct ngtcp2_qlog_settings { /* odcid is Original Destination Connection ID sent by client. It - is used as group_id and ODCID fields. */ + is used as group_id and ODCID fields. Client ignores this field + and uses dcid parameter passed to `ngtcp2_conn_client_new()`. */ ngtcp2_cid odcid; /* write is a callback function to write qlog. Setting NULL disables qlog. */ @@ -550,47 +695,33 @@ typedef struct ngtcp2_settings { /* transport_params is the QUIC transport parameters to send. */ ngtcp2_transport_params transport_params; ngtcp2_qlog_settings qlog; + ngtcp2_cc_algo cc_algo; + ngtcp2_cc *cc; /* initial_ts is an initial timestamp given to the library. */ ngtcp2_tstamp initial_ts; /* log_printf is a function that the library uses to write logs. NULL means no logging output. */ ngtcp2_printf log_printf; - /* token is a token received in Client Initial packet and - successfully validated. Only server application may specify this - field. Server then verifies that all Client Initial packets have - this token. `ngtcp2_conn_server_new` makes a copy of token. */ + /* 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. If it is set to 0, it + defaults to NGTCP2_DEFAULT_MAX_PKTLEN. */ + size_t max_udp_payload_size; + /** + * 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. + * + * 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. + */ ngtcp2_vec token; } ngtcp2_settings; -/** - * @struct - * - * ngtcp2_rcvry_stat holds various statistics, and computed data for - * recovery from packet loss. - * - * Everything is NGTCP2_DURATION_TICK resolution. - */ -typedef struct ngtcp2_rcvry_stat { - ngtcp2_duration latest_rtt; - ngtcp2_duration min_rtt; - ngtcp2_duration smoothed_rtt; - ngtcp2_duration rttvar; - size_t pto_count; - ngtcp2_tstamp loss_detection_timer; - /* last_tx_pkt_ts corresponds to - time_of_last_sent_ack_eliciting_packet in - draft-ietf-quic-recovery-25. It is indexed by - ngtcp2_crypto_level. No last_tx_pkt_ts for 0RTT packet. */ - ngtcp2_tstamp last_tx_pkt_ts[3]; -} ngtcp2_rcvry_stat; - -typedef struct ngtcp2_cc_stat { - uint64_t cwnd; - uint64_t ssthresh; - ngtcp2_tstamp congestion_recovery_start_ts; - uint64_t bytes_in_flight; -} ngtcp2_cc_stat; - /** * @struct * @@ -600,7 +731,7 @@ typedef struct ngtcp2_addr { /* addrlen is the length of addr. */ size_t addrlen; /* addr points to the buffer which contains endpoint address. It is - opaque to the ngtcp2 library. */ + opaque to the ngtcp2 library. It must not be NULL. */ uint8_t *addr; /* user_data is an arbitrary data and opaque to the library. */ void *user_data; @@ -680,6 +811,12 @@ typedef struct ngtcp2_crypto_ctx { ngtcp2_crypto_aead aead; ngtcp2_crypto_md md; ngtcp2_crypto_cipher hp; + /* max_encryption is the number of encryption which this key can be + used with. */ + uint64_t max_encryption; + /* max_decryption_failure is the number of decryption failure with + this key. */ + uint64_t max_decryption_failure; } ngtcp2_crypto_ctx; /** @@ -1055,7 +1192,6 @@ typedef int (*ngtcp2_recv_version_negotiation)(ngtcp2_conn *conn, * immediately. */ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, - const ngtcp2_pkt_retry *retry, void *user_data); /** @@ -1131,23 +1267,46 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, const uint8_t *hp_key, const uint8_t *sample); +/** + * @enum + * + * ngtcp2_stream_data_flag defines the properties of the data emitted + * via :type:`ngtcp2_recv_stream_data` callback function. + */ +typedef enum ngtcp2_stream_data_flag { + NGTCP2_STREAM_DATA_FLAG_NONE = 0x00, + /** + * NGTCP2_STREAM_DATA_FLAG_FIN indicates that this chunk of data is + * final piece of an incoming stream. + */ + NGTCP2_STREAM_DATA_FLAG_FIN = 0x01, + /** + * NGTCP2_STREAM_DATA_FLAG_0RTT indicates that this chunk of data + * contains data received in 0RTT packet and the handshake has not + * completed yet, which means that the data might be replayed. + */ + NGTCP2_STREAM_DATA_FLAG_0RTT = 0x02 +} ngtcp2_stream_data_flag; + /** * @functypedef * * :type:`ngtcp2_recv_stream_data` is invoked when stream data is - * received. The stream is specified by |stream_id|. If |fin| is - * nonzero, this portion of the data is the last data in this stream. - * |offset| is the offset where this data begins. The library ensures - * that data is passed to the application in the non-decreasing order - * of |offset|. The data is passed as |data| of length |datalen|. - * |datalen| may be 0 if and only if |fin| is nonzero. + * received. The stream is specified by |stream_id|. |flags| is the + * bitwise-OR of zero or more of ngtcp2_stream_data_flag. If |flags| + * & :enum:`NGTCP2_STREAM_DATA_FLAG_FIN` is nonzero, this portion of + * the data is the last data in this stream. |offset| is the offset + * where this data begins. The library ensures that data is passed to + * the application in the non-decreasing order of |offset|. The data + * is passed as |data| of length |datalen|. |datalen| may be 0 if and + * only if |fin| is nonzero. * * The callback function must return 0 if it succeeds, or * :enum:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the library return * immediately. */ -typedef int (*ngtcp2_recv_stream_data)(ngtcp2_conn *conn, int64_t stream_id, - int fin, uint64_t offset, +typedef int (*ngtcp2_recv_stream_data)(ngtcp2_conn *conn, uint32_t flags, + int64_t stream_id, uint64_t offset, const uint8_t *data, size_t datalen, void *user_data, void *stream_user_data); @@ -1215,11 +1374,9 @@ typedef int (*ngtcp2_stream_reset)(ngtcp2_conn *conn, int64_t stream_id, * Returning :enum:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library * call return immediately. */ -typedef int (*ngtcp2_acked_stream_data_offset)(ngtcp2_conn *conn, - int64_t stream_id, - uint64_t offset, size_t datalen, - void *user_data, - void *stream_user_data); +typedef int (*ngtcp2_acked_stream_data_offset)( + ngtcp2_conn *conn, int64_t stream_id, uint64_t offset, uint64_t datalen, + void *user_data, void *stream_user_data); /** * @functypedef @@ -1238,7 +1395,7 @@ typedef int (*ngtcp2_acked_stream_data_offset)(ngtcp2_conn *conn, */ typedef int (*ngtcp2_acked_crypto_offset)(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, - uint64_t offset, size_t datalen, + uint64_t offset, uint64_t datalen, void *user_data); /** @@ -1436,6 +1593,21 @@ typedef int (*ngtcp2_connection_id_status)(ngtcp2_conn *conn, int type, 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. + * + * |token| is the received token. + * + * The callback function must return 0 if it succeeds. Returning + * :enum:`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 struct ngtcp2_conn_callbacks { /** * client_initial is a callback function which is invoked when @@ -1617,6 +1789,11 @@ typedef struct ngtcp2_conn_callbacks { * handshake confirmation for server. */ ngtcp2_handshake_confirmed handshake_confirmed; + /** + * recv_new_token is a callback function which is invoked when new + * token is received from server. This field is ignored by server. + */ + ngtcp2_recv_new_token recv_new_token; } ngtcp2_conn_callbacks; /** @@ -1764,7 +1941,10 @@ NGTCP2_EXTERN void ngtcp2_conn_del(ngtcp2_conn *conn); * connection using `ngtcp2_conn_del`. It is undefined to call the * other library functions. If :enum:`NGTCP2_ERR_RETRY` is returned, * application must be a server and it must perform address validation - * by sending Retry packet and close the connection. + * by sending Retry packet and close the connection. If + * :enum:`NGTCP2_ERR_DROP_CONN` is returned, server application must + * drop the connection silently (without sending any CONNECTION_CLOSE + * frame) and discard connection state. */ NGTCP2_EXTERN int ngtcp2_conn_read_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, @@ -1828,13 +2008,11 @@ NGTCP2_EXTERN int ngtcp2_conn_install_initial_key( /** * @function * - * `ngtcp2_conn_install_handshake_key` installs packet protection - * keying materials for Handshake packets. |rx_key| of length - * |keylen|, IV |rx_iv| of length |rx_ivlen|, and packet header - * protection key |rx_hp_key| of length |keylen| to decrypt incoming - * Handshake packets. Similarly, |tx_key|, |tx_iv| and |tx_hp_key| - * are for encrypt outgoing packets and are the same length with the - * rx counterpart. + * `ngtcp2_conn_install_rx_handshake_key` installs packet protection + * keying materials for decrypting incoming Handshake packets. |key| + * of length |keylen|, IV |iv| of length |ivlen|, and packet header + * protection key |hp_key| of length |keylen| to decrypt incoming + * Handshake packets. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -1842,10 +2020,30 @@ NGTCP2_EXTERN int ngtcp2_conn_install_initial_key( * :enum:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int ngtcp2_conn_install_handshake_key( - ngtcp2_conn *conn, const uint8_t *rx_key, const uint8_t *rx_iv, - const uint8_t *rx_hp_key, const uint8_t *tx_key, const uint8_t *tx_iv, - const uint8_t *tx_hp_key, size_t keylen, size_t ivlen); +NGTCP2_EXTERN int +ngtcp2_conn_install_rx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, + const uint8_t *iv, const uint8_t *hp_key, + size_t keylen, size_t ivlen); + +/** + * @function + * + * `ngtcp2_conn_install_tx_handshake_key` installs packet protection + * keying materials for encrypting outgoing Handshake packets. |key| + * of length |keylen|, IV |iv| of length |ivlen|, and packet header + * protection key |hp_key| of length |keylen| to encrypt outgoing + * Handshake packets. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGTCP2_ERR_NOMEM` + * Out of memory. + */ +NGTCP2_EXTERN int +ngtcp2_conn_install_tx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, + const uint8_t *iv, const uint8_t *hp_key, + size_t keylen, size_t ivlen); /** * @function @@ -1890,14 +2088,34 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, /** * @function * - * `ngtcp2_conn_install_key` installs packet protection keying - * materials for Short packets. |rx_secret| of length |secretlen| is - * the decryption secret. |rx_key| of length |keylen|, IV |rx_iv| of - * length |rx_ivlen|, and packet header protection key |rx_hp_key| of - * length |keylen| to decrypt incoming Short packets. Similarly, - * |tx_secret| of length |secretlen| is the encryption secret. - * |tx_key|, |tx_iv| and |tx_hp_key| are used to encrypt outgoing - * packets and are the same length with the rx counterpart. + * `ngtcp2_conn_install_rx_key` installs packet protection keying + * materials for decrypting Short packets. |secret| of length + * |secretlen| is the decryption secret which is used to derive keying + * materials passed to this function. |key| of length |keylen|, IV + * |iv| of length |ivlen|, and packet header protection key |hp_key| + * of length |keylen| to decrypt incoming Short packets. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGTCP2_ERR_NOMEM` + * Out of memory. + */ +NGTCP2_EXTERN int +ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, + const uint8_t *key, const uint8_t *iv, + const uint8_t *hp_key, size_t secretlen, + size_t keylen, size_t ivlen); + +/** + * @function + * + * `ngtcp2_conn_install_tx_key` installs packet protection keying + * materials for encrypting Short packets. |secret| of length + * |secretlen| is the encryption secret which is used to derive keying + * materials passed to this function. |key| of length |keylen|, IV + * |iv| of length |ivlen|, and packet header protection key |hp_key| + * of length |keylen| to encrypt outgoing Short packets. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -1905,11 +2123,11 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, * :enum:`NGTCP2_ERR_NOMEM` * Out of memory. */ -NGTCP2_EXTERN int ngtcp2_conn_install_key( - ngtcp2_conn *conn, const uint8_t *rx_secret, const uint8_t *tx_secret, - const uint8_t *rx_key, const uint8_t *rx_iv, const uint8_t *rx_hp_key, - const uint8_t *tx_key, const uint8_t *tx_iv, const uint8_t *tx_hp_key, - size_t secretlen, size_t keylen, size_t ivlen); +NGTCP2_EXTERN int +ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, + const uint8_t *key, const uint8_t *iv, + const uint8_t *hp_key, size_t secretlen, + size_t keylen, size_t ivlen); /** * @function @@ -1986,7 +2204,7 @@ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_handle_expiry` handles expired timer. It do nothing + * `ngtcp2_conn_handle_expiry` handles expired timer. It does nothing * if timer is not expired. */ NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, @@ -2194,7 +2412,12 @@ typedef enum ngtcp2_write_stream_flag { * NGTCP2_WRITE_STREAM_FLAG_MORE indicates that more stream data may * come and should be coalesced into the same packet if possible. */ - NGTCP2_WRITE_STREAM_FLAG_MORE = 0x01 + NGTCP2_WRITE_STREAM_FLAG_MORE = 0x01, + /** + * NGTCP2_WRITE_STREAM_FLAG_FIN indicates that the passed data is + * the final part of a stream. + */ + NGTCP2_WRITE_STREAM_FLAG_FIN = 0x02 } ngtcp2_write_stream_flag; /** @@ -2206,7 +2429,7 @@ typedef enum ngtcp2_write_stream_flag { */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream( ngtcp2_conn *conn, ngtcp2_path *path, uint8_t *dest, size_t destlen, - ngtcp2_ssize *pdatalen, uint32_t flags, int64_t stream_id, int fin, + ngtcp2_ssize *pdatalen, uint32_t flags, int64_t stream_id, const uint8_t *data, size_t datalen, ngtcp2_tstamp ts); /** @@ -2226,15 +2449,16 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream( * nothing is written to |dest|. * * If the all given data is encoded as STREAM frame in |dest|, and if - * |fin| is nonzero, fin flag is set in outgoing STREAM frame. - * Otherwise, fin flag in STREAM frame is not set. + * |flags| & NGTCP2_WRITE_STREAM_FLAG_FIN is nonzero, fin flag is set + * to outgoing STREAM frame. Otherwise, fin flag in STREAM frame is + * not set. * * This packet may contain frames other than STREAM frame. The packet * might not contain STREAM frame if other frames occupy the packet. * In that case, |*pdatalen| would be -1 if |pdatalen| is not NULL. * - * If |fin| is nonzero, and 0 length STREAM frame is successfully - * serialized, |*pdatalen| would be 0. + * If |flags| & NGTCP2_WRITE_STREAM_FLAG_FIN is nonzero, and 0 length + * STREAM frame is successfully serialized, |*pdatalen| would be 0. * * 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 @@ -2257,14 +2481,15 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream( * - The function returns the written length of packet just like * without :enum:`NGTCP2_WRITE_STREAM_FLAG_MORE`. This is because * packet is nearly full and the library decided to make a complete - * packet. + * packet. In this case, |*pdatalen| == -1 is asserted. * - * - The function returns :enum:`NGTCP2_ERR_WRITE_STREAM_MORE`. This - * indicates that application can call this function with different - * stream data to pack them into the same packet. Application has - * to specify the same |conn|, |path|, |dest|, |destlen|, - * |pdatalen|, and |ts| parameters, otherwise the behaviour is - * undefined. The application can change |flags|. + * - The function returns :enum:`NGTCP2_ERR_WRITE_STREAM_MORE`. In + * this case, |*pdatalen| >= 0 is asserted. This indicates that + * application can call this function with different stream data to + * pack them into the same packet. Application has to specify the + * same |conn|, |path|, |dest|, |destlen|, |pdatalen|, and |ts| + * parameters, otherwise the behaviour is undefined. The + * application can change |flags|. * * - The function returns :enum:`NGTCP2_ERR_STREAM_DATA_BLOCKED` which * indicates that stream is blocked because of flow control. @@ -2278,7 +2503,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream( * `ngtcp2_conn_write_application_close` to handle error from this * function). Just keep calling `ngtcp2_conn_writev_stream` or * `ngtcp2_conn_write_pkt` until it returns a positive number (which - * indicates a complete packet is ready). + * indicates a complete packet is ready). If |*pdatalen| >= 0, the + * function always return :enum:`NGTCP2_ERR_WRITE_STREAM_MORE`. * * This function returns 0 if it cannot write any frame because buffer * is too small, or packet is congestion limited. Application should @@ -2316,7 +2542,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream( */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream( ngtcp2_conn *conn, ngtcp2_path *path, uint8_t *dest, size_t destlen, - ngtcp2_ssize *pdatalen, uint32_t flags, int64_t stream_id, int fin, + ngtcp2_ssize *pdatalen, uint32_t flags, int64_t stream_id, const ngtcp2_vec *datav, size_t datavcnt, ngtcp2_tstamp ts); /** @@ -2419,7 +2645,7 @@ NGTCP2_EXTERN int ngtcp2_conn_is_in_draining_period(ngtcp2_conn *conn); */ NGTCP2_EXTERN int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, - size_t datalen); + uint64_t datalen); /** * @function @@ -2428,7 +2654,7 @@ NGTCP2_EXTERN int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, * |datalen|. */ NGTCP2_EXTERN void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, - size_t datalen); + uint64_t datalen); /** * @function @@ -2459,15 +2685,6 @@ NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_bidi(ngtcp2_conn *conn, NGTCP2_EXTERN void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, size_t n); -/** - * @function - * - * `ngtcp2_conn_get_bytes_in_flight` returns the number of bytes which - * is the sum of outgoing QUIC packet length in flight. This does not - * include a packet which only includes ACK frames. - */ -NGTCP2_EXTERN size_t ngtcp2_conn_get_bytes_in_flight(ngtcp2_conn *conn); - /** * @function * @@ -2554,19 +2771,11 @@ NGTCP2_EXTERN int ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn); /** * @function * - * `ngtcp2_conn_get_rcvry_stat` returns a pointer to the object which - * stores recovery information. - */ -NGTCP2_EXTERN const ngtcp2_rcvry_stat * -ngtcp2_conn_get_rcvry_stat(ngtcp2_conn *conn); - -/** - * @function - * - * `ngtcp2_conn_get_cc_stat` returns a pointer to the object which - * stores congestion controller information. + * `ngtcp2_conn_get_conn_stat` assigns connection statistics data to + * |*cstat|. */ -NGTCP2_EXTERN const ngtcp2_cc_stat *ngtcp2_conn_get_cc_stat(ngtcp2_conn *conn); +NGTCP2_EXTERN void ngtcp2_conn_get_conn_stat(ngtcp2_conn *conn, + ngtcp2_conn_stat *cstat); /** * @function @@ -2607,6 +2816,26 @@ ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, const uint8_t *data, const size_t datalen); +/** + * @function + * + * `ngtcp2_conn_submit_new_token` submits address validation token. + * It is sent in NEW_TOKEN frame. Only server can call this function. + * |tokenlen| must not be 0. + * + * This function makes a copy of the buffer pointed by |token| of + * length |tokenlen|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGTCP2_ERR_NOMEM` + * Out of memory. + */ +NGTCP2_EXTERN int ngtcp2_conn_submit_new_token(ngtcp2_conn *conn, + const uint8_t *token, + size_t tokenlen); + /** * @function * @@ -2673,6 +2902,24 @@ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_local_streams_uni(ngtcp2_conn *conn); */ NGTCP2_EXTERN uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_streams_bidi_left` returns the number of + * bidirectional streams which the local endpoint can open without + * violating stream concurrency limit. + */ +NGTCP2_EXTERN uint64_t ngtcp2_conn_get_streams_bidi_left(ngtcp2_conn *conn); + +/** + * @function + * + * `ngtcp2_conn_get_streams_uni_left` returns the number of + * unidirectional streams which the local endpoint can open without + * violating stream concurrency limit. + */ +NGTCP2_EXTERN uint64_t ngtcp2_conn_get_streams_uni_left(ngtcp2_conn *conn); + /** * @function * @@ -2706,6 +2953,24 @@ ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn); NGTCP2_EXTERN void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn, const ngtcp2_crypto_ctx *ctx); +/** + * @function + * + * `ngtcp2_conn_get_tls_native_handle` returns TLS native handle set by + * `ngtcp2_conn_set_tls_native_handle()`. + */ +NGTCP2_EXTERN void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn); + +/** + * @function + * + * `ngtcp2_conn_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_tls_native_handle(ngtcp2_conn *conn, + void *tls_native_handle); + /** * @function * @@ -2760,6 +3025,14 @@ NGTCP2_EXTERN void ngtcp2_conn_get_connection_close_error_code( NGTCP2_EXTERN int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id); +/** + * @function + * + * `ngtcp2_conn_is_server` returns nonzero if |conn| is initialized as + * server. + */ +NGTCP2_EXTERN int ngtcp2_conn_is_server(ngtcp2_conn *conn); + /** * @function * @@ -2818,9 +3091,12 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps); * values. First this function fills |settings| with 0 and set the * default value to the following fields: * - * * max_packet_size = NGTCP2_MAX_PKT_SIZE - * * ack_delay_component = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT - * * max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY + * * cc_algo = NGTCP2_CC_ALGO_CUBIC + * * transport_params.max_udp_payload_size = NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE + * * transport_params.ack_delay_component = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT + * * transport_params.max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY + * * transport_params.active_connection_id_limit = + * NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT */ NGTCP2_EXTERN void ngtcp2_settings_default(ngtcp2_settings *settings); @@ -2882,6 +3158,30 @@ NGTCP2_EXTERN ngtcp2_info *ngtcp2_version(int least_version); */ NGTCP2_EXTERN int ngtcp2_is_bidi_stream(int64_t stream_id); +typedef enum { + NGTCP2_LOG_EVENT_NONE, + /* connection (catch-all) event */ + NGTCP2_LOG_EVENT_CON, + /* packet event */ + NGTCP2_LOG_EVENT_PKT, + /* frame event */ + NGTCP2_LOG_EVENT_FRM, + /* recovery event */ + NGTCP2_LOG_EVENT_RCV, + /* crypto event */ + NGTCP2_LOG_EVENT_CRY, + /* path validation event */ + NGTCP2_LOG_EVENT_PTV, +} ngtcp2_log_event; + +/** + * @function + * + * `ngtcp2_log_info` writes info level log. + */ +NGTCP2_EXTERN void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, + const char *fmt, ...); + #ifdef __cplusplus } #endif diff --git a/deps/ngtcp2/lib/includes/ngtcp2/version.h b/deps/ngtcp2/lib/includes/ngtcp2/version.h index 85850725bfa9e2..3782959c286a85 100644 --- a/deps/ngtcp2/lib/includes/ngtcp2/version.h +++ b/deps/ngtcp2/lib/includes/ngtcp2/version.h @@ -30,7 +30,7 @@ * * Version number of the ngtcp2 library release. */ -#define NGTCP2_VERSION "0.1.90" +#define NGTCP2_VERSION "0.1.0-DEV" /** * @macro @@ -40,6 +40,6 @@ * number, 8 bits for minor and 8 bits for patch. Version 1.2.3 * becomes 0x010203. */ -#define NGTCP2_VERSION_NUM 0x00015a +#define NGTCP2_VERSION_NUM 0x000100 #endif /* VERSION_H */ diff --git a/deps/ngtcp2/lib/includes/ngtcp2/version.h.in b/deps/ngtcp2/lib/includes/ngtcp2/version.h.in deleted file mode 100644 index fc7459636dd140..00000000000000 --- a/deps/ngtcp2/lib/includes/ngtcp2/version.h.in +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2016 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 VERSION_H -#define VERSION_H - -/** - * @macro - * - * Version number of the ngtcp2 library release. - */ -#define NGTCP2_VERSION "@PACKAGE_VERSION@" - -/** - * @macro - * - * Numerical representation of the version number of the ngtcp2 - * library release. This is a 24 bit number with 8 bits for major - * number, 8 bits for minor and 8 bits for patch. Version 1.2.3 - * becomes 0x010203. - */ -#define NGTCP2_VERSION_NUM @PACKAGE_VERSION_NUM@ - -#endif /* VERSION_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_acktr.c b/deps/ngtcp2/lib/ngtcp2_acktr.c index e27d05c787d659..85113716b1c872 100644 --- a/deps/ngtcp2/lib/ngtcp2_acktr.c +++ b/deps/ngtcp2/lib/ngtcp2_acktr.c @@ -45,7 +45,7 @@ void ngtcp2_acktr_entry_del(ngtcp2_acktr_entry *ent, const ngtcp2_mem *mem) { } static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { - return *lhs->i > *rhs->i; + return *(int64_t *)lhs > *(int64_t *)rhs; } int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log, @@ -95,11 +95,9 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack, ngtcp2_acktr_entry *ent, *prev_ent, *delent; int rv; int added = 0; - ngtcp2_ksl_key key, old_key; if (ngtcp2_ksl_len(&acktr->ents)) { - it = ngtcp2_ksl_lower_bound(&acktr->ents, - ngtcp2_ksl_key_ptr(&key, &pkt_num)); + it = ngtcp2_ksl_lower_bound(&acktr->ents, &pkt_num); if (ngtcp2_ksl_it_end(&it)) { ngtcp2_ksl_it_prev(&it); ent = ngtcp2_ksl_it_get(&it); @@ -117,9 +115,7 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack, if (ngtcp2_ksl_it_begin(&it)) { if (ent->pkt_num + 1 == pkt_num) { - ngtcp2_ksl_update_key(&acktr->ents, - ngtcp2_ksl_key_ptr(&key, &ent->pkt_num), - ngtcp2_ksl_key_ptr(&old_key, &pkt_num)); + ngtcp2_ksl_update_key(&acktr->ents, &ent->pkt_num, &pkt_num); ent->pkt_num = pkt_num; ent->tstamp = ts; ++ent->len; @@ -134,14 +130,11 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack, if (ent->pkt_num + 1 == pkt_num) { if (prev_ent->pkt_num == pkt_num + (int64_t)prev_ent->len) { prev_ent->len += ent->len + 1; - ngtcp2_ksl_remove(&acktr->ents, NULL, - ngtcp2_ksl_key_ptr(&key, &ent->pkt_num)); + ngtcp2_ksl_remove(&acktr->ents, NULL, &ent->pkt_num); ngtcp2_acktr_entry_del(ent, acktr->mem); added = 1; } else { - ngtcp2_ksl_update_key(&acktr->ents, - ngtcp2_ksl_key_ptr(&key, &ent->pkt_num), - ngtcp2_ksl_key_ptr(&old_key, &pkt_num)); + ngtcp2_ksl_update_key(&acktr->ents, &ent->pkt_num, &pkt_num); ent->pkt_num = pkt_num; ent->tstamp = ts; ++ent->len; @@ -160,8 +153,7 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack, if (rv != 0) { return rv; } - rv = ngtcp2_ksl_insert(&acktr->ents, NULL, - ngtcp2_ksl_key_ptr(&key, &ent->pkt_num), ent); + rv = ngtcp2_ksl_insert(&acktr->ents, NULL, &ent->pkt_num, ent); if (rv != 0) { ngtcp2_acktr_entry_del(ent, acktr->mem); return rv; @@ -179,8 +171,7 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack, it = ngtcp2_ksl_end(&acktr->ents); ngtcp2_ksl_it_prev(&it); delent = ngtcp2_ksl_it_get(&it); - ngtcp2_ksl_remove(&acktr->ents, NULL, - ngtcp2_ksl_key_ptr(&key, &delent->pkt_num)); + ngtcp2_ksl_remove(&acktr->ents, NULL, &delent->pkt_num); ngtcp2_acktr_entry_del(delent, acktr->mem); } @@ -189,16 +180,13 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack, void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent) { ngtcp2_ksl_it it; - ngtcp2_ksl_key key; - it = ngtcp2_ksl_lower_bound(&acktr->ents, - ngtcp2_ksl_key_ptr(&key, &ent->pkt_num)); - assert(*ngtcp2_ksl_it_key(&it).i == (int64_t)ent->pkt_num); + it = ngtcp2_ksl_lower_bound(&acktr->ents, &ent->pkt_num); + assert(*(int64_t *)ngtcp2_ksl_it_key(&it) == (int64_t)ent->pkt_num); for (; !ngtcp2_ksl_it_end(&it);) { ent = ngtcp2_ksl_it_get(&it); - ngtcp2_ksl_remove(&acktr->ents, &it, - ngtcp2_ksl_key_ptr(&key, &ent->pkt_num)); + ngtcp2_ksl_remove(&acktr->ents, &it, &ent->pkt_num); ngtcp2_acktr_entry_del(ent, acktr->mem); } } @@ -207,6 +195,11 @@ ngtcp2_ksl_it ngtcp2_acktr_get(ngtcp2_acktr *acktr) { return ngtcp2_ksl_begin(&acktr->ents); } +int ngtcp2_acktr_empty(ngtcp2_acktr *acktr) { + ngtcp2_ksl_it it = ngtcp2_ksl_begin(&acktr->ents); + return ngtcp2_ksl_it_end(&it); +} + ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr, int64_t pkt_num, int64_t largest_ack) { @@ -224,9 +217,7 @@ ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr, */ static void acktr_remove(ngtcp2_acktr *acktr, ngtcp2_ksl_it *it, ngtcp2_acktr_entry *ent) { - ngtcp2_ksl_key key; - - ngtcp2_ksl_remove(&acktr->ents, it, ngtcp2_ksl_key_ptr(&key, &ent->pkt_num)); + ngtcp2_ksl_remove(&acktr->ents, it, &ent->pkt_num); ngtcp2_acktr_entry_del(ent, acktr->mem); } @@ -235,15 +226,13 @@ static void acktr_on_ack(ngtcp2_acktr *acktr, ngtcp2_ringbuf *rb, ngtcp2_acktr_ack_entry *ack_ent; ngtcp2_acktr_entry *ent; ngtcp2_ksl_it it; - ngtcp2_ksl_key key; assert(ngtcp2_ringbuf_len(rb)); ack_ent = ngtcp2_ringbuf_get(rb, ack_ent_offset); /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */ - it = ngtcp2_ksl_lower_bound(&acktr->ents, - ngtcp2_ksl_key_ptr(&key, &ack_ent->largest_ack)); + it = ngtcp2_ksl_lower_bound(&acktr->ents, &ack_ent->largest_ack); for (; !ngtcp2_ksl_it_end(&it);) { ent = ngtcp2_ksl_it_get(&it); acktr_remove(acktr, &it, ent); diff --git a/deps/ngtcp2/lib/ngtcp2_acktr.h b/deps/ngtcp2/lib/ngtcp2_acktr.h index 0efd2156ac9117..38c1ebe2cfd3ff 100644 --- a/deps/ngtcp2/lib/ngtcp2_acktr.h +++ b/deps/ngtcp2/lib/ngtcp2_acktr.h @@ -176,6 +176,12 @@ void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent); */ ngtcp2_ksl_it ngtcp2_acktr_get(ngtcp2_acktr *acktr); +/* + * ngtcp2_acktr_empty returns nonzero if it has no packet to + * acknowledge. + */ +int ngtcp2_acktr_empty(ngtcp2_acktr *acktr); + /* * ngtcp2_acktr_add_ack records outgoing ACK frame whose largest * acknowledged packet number is |largest_ack|. |pkt_num| is the diff --git a/deps/ngtcp2/lib/ngtcp2_cc.c b/deps/ngtcp2/lib/ngtcp2_cc.c index 02864bffa0ec41..9c61a5e9564519 100644 --- a/deps/ngtcp2/lib/ngtcp2_cc.c +++ b/deps/ngtcp2/lib/ngtcp2_cc.c @@ -23,115 +23,472 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "ngtcp2_cc.h" + +#include + #include "ngtcp2_log.h" #include "ngtcp2_macro.h" -#include "ngtcp2_rst.h" +#include "ngtcp2_mem.h" +#include "ngtcp2_rcvry.h" + +uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) { + uint64_t n = 2 * max_udp_payload_size; + n = ngtcp2_max(n, 14720); + return ngtcp2_min(10 * max_udp_payload_size, n); +} ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num, - size_t pktlen, ngtcp2_tstamp ts_sent) { + size_t pktlen, ngtcp2_pktns_id pktns_id, + ngtcp2_tstamp ts_sent) { pkt->pkt_num = pkt_num; pkt->pktlen = pktlen; + pkt->pktns_id = pktns_id; pkt->ts_sent = ts_sent; return pkt; } -void ngtcp2_default_cc_init(ngtcp2_default_cc *cc, ngtcp2_cc_stat *ccs, - ngtcp2_rst *rst, ngtcp2_log *log) { - cc->log = log; - cc->ccs = ccs; - cc->rst = rst; - cc->max_delivery_rate = 0.; - cc->min_rtt = 0; - cc->min_rtt_ts = 0; +static void reno_cc_reset(ngtcp2_reno_cc *cc) { + cc->max_delivery_rate_sec = 0; cc->target_cwnd = 0; } -void ngtcp2_default_cc_free(ngtcp2_default_cc *cc) { (void)cc; } +void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log) { + cc->ccb.log = log; + reno_cc_reset(cc); +} + +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; + } -static int default_cc_in_congestion_recovery(ngtcp2_default_cc *cc, - ngtcp2_tstamp sent_time) { - return sent_time <= cc->ccs->congestion_recovery_start_ts; + 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_default_cc_on_pkt_acked(ngtcp2_default_cc *cc, - const ngtcp2_cc_pkt *pkt) { - ngtcp2_cc_stat *ccs = cc->ccs; +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); + + ngtcp2_reno_cc_free(reno_cc); + ngtcp2_mem_free(mem, reno_cc); +} + +static int in_congestion_recovery(const ngtcp2_conn_stat *cstat, + ngtcp2_tstamp sent_time) { + return sent_time <= cstat->congestion_recovery_start_ts; +} + +void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *ccx, 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); + (void)ts; - if (default_cc_in_congestion_recovery(cc, pkt->ts_sent)) { + if (in_congestion_recovery(cstat, pkt->ts_sent)) { return; } - if (cc->target_cwnd && ccs->cwnd >= cc->target_cwnd) { + if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) { return; } - if (ccs->cwnd < ccs->ssthresh) { - ccs->cwnd += pkt->pktlen; - ngtcp2_log_info(cc->log, NGTCP2_LOG_EVENT_RCV, - "pkn=%" PRId64 " acked, slow start cwnd=%lu", pkt->pkt_num, - ccs->cwnd); + if (cstat->cwnd < cstat->ssthresh) { + cstat->cwnd += pkt->pktlen; + ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + "pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64, + pkt->pkt_num, cstat->cwnd); return; } - ccs->cwnd += NGTCP2_MAX_DGRAM_SIZE * pkt->pktlen / ccs->cwnd; + cstat->cwnd += cstat->max_udp_payload_size * pkt->pktlen / cstat->cwnd; } -void ngtcp2_default_cc_congestion_event(ngtcp2_default_cc *cc, +void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts_sent, ngtcp2_tstamp ts) { - ngtcp2_cc_stat *ccs = cc->ccs; + ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + uint64_t min_cwnd; - if (default_cc_in_congestion_recovery(cc, ts_sent)) { + if (in_congestion_recovery(cstat, ts_sent)) { return; } - ccs->congestion_recovery_start_ts = ts; - ccs->cwnd >>= NGTCP2_LOSS_REDUCTION_FACTOR_BITS; - ccs->cwnd = ngtcp2_max(ccs->cwnd, NGTCP2_MIN_CWND); - ccs->ssthresh = ccs->cwnd; - ngtcp2_log_info(cc->log, NGTCP2_LOG_EVENT_RCV, - "reduce cwnd because of packet loss cwnd=%lu", ccs->cwnd); -} + cstat->congestion_recovery_start_ts = ts; + cstat->cwnd >>= NGTCP2_LOSS_REDUCTION_FACTOR_BITS; + min_cwnd = 2 * cstat->max_udp_payload_size; + cstat->cwnd = ngtcp2_max(cstat->cwnd, min_cwnd); + cstat->ssthresh = cstat->cwnd; -void ngtcp2_default_cc_handle_persistent_congestion(ngtcp2_default_cc *cc, - ngtcp2_duration loss_window, - ngtcp2_duration pto) { - ngtcp2_cc_stat *ccs = cc->ccs; - ngtcp2_duration congestion_period = - pto * NGTCP2_PERSISTENT_CONGESTION_THRESHOLD; + ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + "reduce cwnd because of packet loss cwnd=%" PRIu64, + cstat->cwnd); +} - if (loss_window >= congestion_period) { - ngtcp2_log_info(cc->log, NGTCP2_LOG_EVENT_RCV, - "persistent congestion loss_window=%" PRIu64 - " congestion_period=%" PRIu64, - loss_window, congestion_period); +void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *ccx, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + (void)ccx; + (void)ts; - ccs->cwnd = NGTCP2_MIN_CWND; - } + cstat->cwnd = 2 * cstat->max_udp_payload_size; } -void ngtcp2_default_cc_on_ack_recv(ngtcp2_default_cc *cc, - ngtcp2_duration latest_rtt, +void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { + ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + uint64_t target_cwnd, initcwnd; + (void)ts; + + /* TODO Use sliding window for min rtt measurement */ /* TODO Use sliding window */ - if (latest_rtt && (cc->min_rtt == 0 || cc->min_rtt > latest_rtt)) { - cc->min_rtt = latest_rtt; - cc->min_rtt_ts = ts; + cc->max_delivery_rate_sec = + ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec); + + 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_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + "target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64 + " min_rtt=%" PRIu64, + cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt); } +} + +void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *ccx) { + ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb); + 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->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); +} + +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_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; +} + +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); +} + +static uint64_t ngtcp2_cbrt(uint64_t n) { + int d; + uint64_t a; + int i; + + if (n == 0) { + return 0; + } + + d = __builtin_clzll(n); + a = 1ULL << ((64 - d) / 3 + 1); + + for (i = 0; a * a * a > n; ++i) { + a = (2 * a + n / a / a) / 3; + } + return a; +} + +/* HyStart++ constants */ +#define NGTCP2_HS_MIN_SSTHRESH 16 +#define NGTCP2_HS_N_RTT_SAMPLE 8 +#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, + 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; + uint64_t tx, kx, time_delta, delta; + uint64_t add, tcp_add; + + if (pkt->pktns_id == NGTCP2_PKTNS_ID_APP && cc->window_end != -1 && + cc->window_end <= pkt->pkt_num) { + cc->window_end = -1; + } + + if (in_congestion_recovery(cstat, pkt->ts_sent)) { + return; + } + + if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) { + return; + } + + if (cstat->cwnd < cstat->ssthresh) { + /* slow-start */ + cstat->cwnd += pkt->pktlen; + + ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + "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 (eta < NGTCP2_HS_MIN_ETA) { + eta = NGTCP2_HS_MIN_ETA; + } else if (eta > NGTCP2_HS_MAX_ETA) { + 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, + "HyStart++ exit slow start"); + cc->w_last_max = cstat->cwnd; + cstat->ssthresh = cstat->cwnd; + } + } + + return; + } + + /* 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; + } else { + cc->k = 0; + cc->origin_point = cstat->cwnd; + } + + cc->w_tcp = cstat->cwnd; + + ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + "cubic-ca epoch_start=%" PRIu64 " k=%" PRIu64 + " origin_point=%" PRIu64, + cc->epoch_start, cc->k, cc->origin_point); + } + + min_rtt = cstat->min_rtt == UINT64_MAX ? NGTCP2_DEFAULT_INITIAL_RTT + : cstat->min_rtt; + + t = ts + min_rtt - cc->epoch_start; + + tx = (t << 4) / NGTCP2_SECONDS; + kx = (cc->k << 4); + + if (tx > kx) { + time_delta = tx - kx; + } else { + time_delta = kx - tx; + } + + delta = cstat->max_udp_payload_size * + ((((time_delta * time_delta) >> 4) * time_delta) >> 8) * 4 / 10; + + if (tx > kx) { + target = cc->origin_point + delta; + } else { + target = cc->origin_point - delta; + } + + if (target > cstat->cwnd) { + add = cstat->max_udp_payload_size * (target - cstat->cwnd) / cstat->cwnd; + } else { + /* TODO too small, no increment at all */ + add = cstat->max_udp_payload_size / (100 * cstat->cwnd); + } + + cc->w_tcp += cstat->max_udp_payload_size * pkt->pktlen * 9 / 17 / cstat->cwnd; + + if (cc->w_tcp > cstat->cwnd) { + tcp_add = + cstat->max_udp_payload_size * (cc->w_tcp - cstat->cwnd) / cstat->cwnd; + if (tcp_add > add) { + add = tcp_add; + } + } + + cstat->cwnd += add; + + ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + "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); +} + +void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *ccx, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts_sent, + ngtcp2_tstamp ts) { + ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + uint64_t min_cwnd; + + if (in_congestion_recovery(cstat, ts_sent)) { + return; + } + + 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; + } else { + cc->w_last_max = cstat->cwnd; + } + + min_cwnd = 2 * cstat->max_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, + "reduce cwnd because of packet loss cwnd=%" PRIu64, + cstat->cwnd); +} + +void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *ccx, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + (void)ccx; + (void)ts; + + cstat->cwnd = 2 * cstat->max_udp_payload_size; +} + +void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + uint64_t target_cwnd, initcwnd; + (void)ts; + + /* TODO Use sliding window for min rtt measurement */ /* TODO Use sliding window */ - cc->max_delivery_rate = - ngtcp2_max(cc->max_delivery_rate, cc->rst->rs.delivery_rate); + cc->max_delivery_rate_sec = + ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec); + + 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_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, + "target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64 + " min_rtt=%" PRIu64, + cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt); + } +} + +void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt) { + ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + (void)cstat; + + if (pkt->pktns_id != NGTCP2_PKTNS_ID_APP || cc->window_end != -1) { + return; + } - if (cc->min_rtt && cc->max_delivery_rate > 1e-9) { - uint64_t target_cwnd = - (uint64_t)(2.89 * cc->max_delivery_rate * (double)cc->min_rtt); - cc->target_cwnd = ngtcp2_max(NGTCP2_MIN_CWND, target_cwnd); + 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; +} + +void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts) { + ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + (void)ts; + + if (cc->window_end == -1) { + return; + } + + cc->current_round_min_rtt = + ngtcp2_min(cc->current_round_min_rtt, cstat->latest_rtt); + ++cc->rtt_sample_count; +} + +void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *ccx) { + ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb); + cubic_cc_reset(cc); +} + +void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *ccx, 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_tstamp last_ts; + + if (event != NGTCP2_CC_EVENT_TYPE_TX_START || cc->epoch_start == UINT64_MAX) { + return; + } - ngtcp2_log_info(cc->log, NGTCP2_LOG_EVENT_RCV, - "target_cwnd=%lu max_delivery_rate=%.02f min_rtt=%lu", - cc->target_cwnd, cc->max_delivery_rate * 1000000000, - cc->min_rtt); + last_ts = cstat->last_tx_pkt_ts[NGTCP2_PKTNS_ID_APP]; + if (last_ts == UINT64_MAX || last_ts <= cc->epoch_start) { + return; } + + assert(ts >= last_ts); + + cc->epoch_start += ts - last_ts; } diff --git a/deps/ngtcp2/lib/ngtcp2_cc.h b/deps/ngtcp2/lib/ngtcp2_cc.h index 33f2815c78f688..c3886a6e6b41cb 100644 --- a/deps/ngtcp2/lib/ngtcp2_cc.h +++ b/deps/ngtcp2/lib/ngtcp2_cc.h @@ -31,62 +31,105 @@ #include -#define NGTCP2_MAX_DGRAM_SIZE 1200 -#define NGTCP2_MIN_CWND (2 * NGTCP2_MAX_DGRAM_SIZE) #define NGTCP2_LOSS_REDUCTION_FACTOR_BITS 1 #define NGTCP2_PERSISTENT_CONGESTION_THRESHOLD 3 struct ngtcp2_log; typedef struct ngtcp2_log ngtcp2_log; -struct ngtcp2_rst; -typedef struct ngtcp2_rst ngtcp2_rst; - -/* ngtcp2_cc_pkt is a convenient structure to include acked/lost/sent - packet. */ -typedef struct { - /* pkt_num is the packet number */ - int64_t pkt_num; - /* pktlen is the length of packet. */ - size_t pktlen; - /* ts_sent is the timestamp when packet is sent. */ - ngtcp2_tstamp ts_sent; -} ngtcp2_cc_pkt; +/* + * ngtcp2_cc_compute_initcwnd computes initial cwnd. + */ +uint64_t ngtcp2_cc_compute_initcwnd(size_t max_packet_size); ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num, - size_t pktlen, ngtcp2_tstamp ts_sent); - -/* ngtcp2_default_cc is the default congestion controller. */ -struct ngtcp2_default_cc { - ngtcp2_log *log; - ngtcp2_cc_stat *ccs; - ngtcp2_rst *rst; - double max_delivery_rate; - ngtcp2_duration min_rtt; - ngtcp2_tstamp min_rtt_ts; + size_t pktlen, ngtcp2_pktns_id pktns_id, + ngtcp2_tstamp ts_sent); + +/* ngtcp2_reno_cc is the RENO congestion controller. */ +struct ngtcp2_reno_cc { + ngtcp2_cc_base ccb; + uint64_t max_delivery_rate_sec; uint64_t target_cwnd; }; -typedef struct ngtcp2_default_cc ngtcp2_default_cc; +typedef struct ngtcp2_reno_cc ngtcp2_reno_cc; -void ngtcp2_default_cc_init(ngtcp2_default_cc *cc, ngtcp2_cc_stat *ccs, - ngtcp2_rst *rst, ngtcp2_log *log); +int ngtcp2_cc_reno_cc_init(ngtcp2_cc *cc, ngtcp2_log *log, + const ngtcp2_mem *mem); -void ngtcp2_default_cc_free(ngtcp2_default_cc *cc); +void ngtcp2_cc_reno_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem); -void ngtcp2_default_cc_on_pkt_acked(ngtcp2_default_cc *cc, - const ngtcp2_cc_pkt *pkt); +void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log); + +void ngtcp2_reno_cc_free(ngtcp2_reno_cc *cc); -void ngtcp2_default_cc_congestion_event(ngtcp2_default_cc *cc, +void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); + +void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts_sent, ngtcp2_tstamp ts); -void ngtcp2_default_cc_handle_persistent_congestion(ngtcp2_default_cc *cc, - ngtcp2_duration loss_window, - ngtcp2_duration pto); +void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); -void ngtcp2_default_cc_on_ack_recv(ngtcp2_default_cc *cc, - ngtcp2_duration latest_rtt, +void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); +void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc); + +/* ngtcp2_cubic_cc is CUBIC congestion controller. */ +typedef struct ngtcp2_cubic_cc { + ngtcp2_cc_base ccb; + uint64_t max_delivery_rate_sec; + uint64_t target_cwnd; + uint64_t w_last_max; + uint64_t w_tcp; + uint64_t origin_point; + ngtcp2_tstamp epoch_start; + uint64_t k; + /* HyStart++ variables */ + size_t rtt_sample_count; + uint64_t current_round_min_rtt; + uint64_t last_round_min_rtt; + int64_t window_end; +} ngtcp2_cubic_cc; + +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_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt, + ngtcp2_tstamp ts); + +void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts_sent, + ngtcp2_tstamp ts); + +void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *cc, + ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + const ngtcp2_cc_pkt *pkt); + +void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_tstamp ts); + +void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc); + +void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, + ngtcp2_cc_event_type event, ngtcp2_tstamp ts); + #endif /* NGTCP2_CC_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_conn.c b/deps/ngtcp2/lib/ngtcp2_conn.c index eca7f04ca33a23..41e5f4d915e3e4 100644 --- a/deps/ngtcp2/lib/ngtcp2_conn.c +++ b/deps/ngtcp2/lib/ngtcp2_conn.c @@ -81,7 +81,7 @@ static int conn_call_handshake_completed(ngtcp2_conn *conn) { } static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, - int fin, uint64_t offset, + uint32_t flags, uint64_t offset, const uint8_t *data, size_t datalen) { int rv; @@ -89,7 +89,7 @@ static int conn_call_recv_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, return 0; } - rv = conn->callbacks.recv_stream_data(conn, strm->stream_id, fin, offset, + rv = conn->callbacks.recv_stream_data(conn, flags, strm->stream_id, offset, data, datalen, conn->user_data, strm->stream_user_data); if (rv != 0) { @@ -361,11 +361,11 @@ static int conn_call_deactivate_dcid(ngtcp2_conn *conn, static int crypto_offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { - return *lhs->i < *rhs->i; + return *(int64_t *)lhs < *(int64_t *)rhs; } -static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_crypto_level crypto_level, - ngtcp2_rst *rst, ngtcp2_default_cc *cc, ngtcp2_log *log, +static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, + ngtcp2_rst *rst, ngtcp2_cc *cc, ngtcp2_log *log, ngtcp2_qlog *qlog, const ngtcp2_mem *mem) { int rv; @@ -396,7 +396,7 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_crypto_level crypto_level, goto fail_tx_frq_init; } - ngtcp2_rtb_init(&pktns->rtb, crypto_level, &pktns->crypto.strm, rst, cc, log, + ngtcp2_rtb_init(&pktns->rtb, pktns_id, &pktns->crypto.strm, rst, cc, log, qlog, mem); return 0; @@ -411,8 +411,8 @@ static int pktns_init(ngtcp2_pktns *pktns, ngtcp2_crypto_level crypto_level, return rv; } -static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_crypto_level crypto_level, - ngtcp2_rst *rst, ngtcp2_default_cc *cc, ngtcp2_log *log, +static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id, + ngtcp2_rst *rst, ngtcp2_cc *cc, ngtcp2_log *log, ngtcp2_qlog *qlog, const ngtcp2_mem *mem) { int rv; @@ -421,7 +421,7 @@ static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_crypto_level crypto_level, return NGTCP2_ERR_NOMEM; } - rv = pktns_init(*ppktns, crypto_level, rst, cc, log, qlog, mem); + rv = pktns_init(*ppktns, pktns_id, rst, cc, log, qlog, mem); if (rv != 0) { ngtcp2_mem_free(mem, *ppktns); } @@ -487,8 +487,22 @@ 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; + default: + break; + } +} + static int cid_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { - return ngtcp2_cid_less(lhs->ptr, rhs->ptr); + return ngtcp2_cid_less(lhs, rhs); } static int ts_retired_less(const ngtcp2_pq_entry *lhs, @@ -499,18 +513,68 @@ static int ts_retired_less(const ngtcp2_pq_entry *lhs, return a->ts_retired < b->ts_retired; } -static void rcvry_stat_reset(ngtcp2_rcvry_stat *rcs) { - memset(rcs, 0, sizeof(*rcs)); - rcs->min_rtt = UINT64_MAX; +static void conn_reset_conn_stat(ngtcp2_conn *conn, ngtcp2_conn_stat *cstat) { + cstat->latest_rtt = 0; + cstat->min_rtt = UINT64_MAX; + cstat->smoothed_rtt = NGTCP2_DEFAULT_INITIAL_RTT; + cstat->rttvar = NGTCP2_DEFAULT_INITIAL_RTT / 2; + cstat->pto_count = 0; + cstat->loss_detection_timer = 0; // Initializes them with UINT64_MAX. - memset(rcs->last_tx_pkt_ts, 0xff, sizeof(rcs->last_tx_pkt_ts)); + memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time)); + cstat->cwnd = + ngtcp2_cc_compute_initcwnd(conn->local.settings.max_udp_payload_size); + cstat->ssthresh = UINT64_MAX; + cstat->congestion_recovery_start_ts = 0; + cstat->bytes_in_flight = 0; + cstat->max_udp_payload_size = conn->local.settings.max_udp_payload_size; + cstat->delivery_rate_sec = 0; + cstat->recv_rate_sec = 0; +} + +static void conn_reset_rx_rate(ngtcp2_conn *conn) { + conn->rx.rate.start_ts = UINT64_MAX; + conn->rx.rate.received = 0; } -static void cc_stat_reset(ngtcp2_cc_stat *ccs) { - memset(ccs, 0, sizeof(*ccs)); - ccs->cwnd = ngtcp2_min(10 * NGTCP2_MAX_DGRAM_SIZE, - ngtcp2_max(2 * NGTCP2_MAX_DGRAM_SIZE, 14720)); - ccs->ssthresh = UINT64_MAX; +static void conn_update_recv_rate(ngtcp2_conn *conn, size_t datalen, + ngtcp2_tstamp ts) { + uint64_t bps; + ngtcp2_duration window; + + conn->rx.rate.received += datalen; + + if (conn->rx.rate.start_ts == UINT64_MAX) { + conn->rx.rate.start_ts = ts; + return; + } + + assert(conn->cstat.min_rtt); + + window = conn->cstat.min_rtt == UINT64_MAX ? NGTCP2_DEFAULT_INITIAL_RTT + : conn->cstat.min_rtt * 2; + + if (window > ts - conn->rx.rate.start_ts) { + return; + } + + bps = conn->rx.rate.received * NGTCP2_SECONDS / (ts - conn->rx.rate.start_ts); + + if (conn->cstat.recv_rate_sec == 0) { + conn->cstat.recv_rate_sec = bps; + } else { + conn->cstat.recv_rate_sec = (conn->cstat.recv_rate_sec * 3 + bps) / 4; + } + + conn_reset_rx_rate(conn); + + if (conn->cstat.min_rtt != UINT64_MAX) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, + "recv_rate_sec=%" PRIu64 " bytes/min_rtt=%" PRIu64, + conn->cstat.recv_rate_sec, + conn->cstat.recv_rate_sec * conn->cstat.min_rtt / + NGTCP2_SECONDS); + } } static void delete_scid(ngtcp2_ksl *scids, const ngtcp2_mem *mem) { @@ -529,7 +593,6 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, void *user_data, int server) { int rv; ngtcp2_scid *scident; - ngtcp2_ksl_key key; const ngtcp2_transport_params *params = &settings->transport_params; uint8_t *buf; @@ -600,34 +663,9 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ngtcp2_buf_init(&(*pconn)->qlog.buf, buf, NGTCP2_QLOG_BUFLEN); } - ngtcp2_rst_init(&(*pconn)->rst); - - ngtcp2_default_cc_init(&(*pconn)->cc, &(*pconn)->ccs, &(*pconn)->rst, - &(*pconn)->log); - - rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_CRYPTO_LEVEL_INITIAL, - &(*pconn)->rst, &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - mem); - if (rv != 0) { - goto fail_in_pktns_init; - } - - rv = pktns_new(&(*pconn)->hs_pktns, NGTCP2_CRYPTO_LEVEL_HANDSHAKE, - &(*pconn)->rst, &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, - mem); - if (rv != 0) { - goto fail_hs_pktns_init; - } - - rv = pktns_init(&(*pconn)->pktns, NGTCP2_CRYPTO_LEVEL_APP, &(*pconn)->rst, - &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, mem); - if (rv != 0) { - goto fail_pktns_init; - } - (*pconn)->local.settings = *settings; - if (server && settings->token.len) { + if (settings->token.len) { buf = ngtcp2_mem_malloc(mem, settings->token.len); if (buf == NULL) { goto fail_token; @@ -644,6 +682,64 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; } + (*pconn)->local.settings.transport_params.initial_scid = *scid; + + if (scid->datalen == 0) { + (*pconn)->local.settings.transport_params.preferred_address_present = 0; + } + + if (settings->max_udp_payload_size == 0) { + (*pconn)->local.settings.max_udp_payload_size = NGTCP2_DEFAULT_MAX_PKTLEN; + } + + conn_reset_conn_stat(*pconn, &(*pconn)->cstat); + + ngtcp2_rst_init(&(*pconn)->rst); + + (*pconn)->cc_algo = settings->cc_algo; + + 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; + } + break; + case NGTCP2_CC_ALGO_CUBIC: + rv = ngtcp2_cc_cubic_cc_init(&(*pconn)->cc, &(*pconn)->log, mem); + if (rv != 0) { + goto fail_cc_init; + } + break; + case NGTCP2_CC_ALGO_CUSTOM: + assert(settings->cc); + (*pconn)->cc = *settings->cc; + (*pconn)->cc.ccb->log = &(*pconn)->log; + break; + default: + assert(0); + } + + conn_reset_rx_rate(*pconn); + + rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_PKTNS_ID_INITIAL, &(*pconn)->rst, + &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, 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, mem); + if (rv != 0) { + goto fail_hs_pktns_init; + } + + rv = pktns_init(&(*pconn)->pktns, NGTCP2_PKTNS_ID_APP, &(*pconn)->rst, + &(*pconn)->cc, &(*pconn)->log, &(*pconn)->qlog, mem); + if (rv != 0) { + goto fail_pktns_init; + } + scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); if (scident == NULL) { rv = NGTCP2_ERR_NOMEM; @@ -655,8 +751,7 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ? params->stateless_reset_token : NULL); - rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, - ngtcp2_ksl_key_ptr(&key, &scident->cid), scident); + rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident); if (rv != 0) { goto fail_scid_set_insert; } @@ -673,8 +768,7 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ngtcp2_scid_init(scident, 1, ¶ms->preferred_address.cid, params->preferred_address.stateless_reset_token); - rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, - ngtcp2_ksl_key_ptr(&key, &scident->cid), scident); + rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident); if (rv != 0) { goto fail_scid_set_insert; } @@ -701,12 +795,11 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->idle_ts = settings->initial_ts; (*pconn)->crypto.key_update.confirmed_ts = UINT64_MAX; - rcvry_stat_reset(&(*pconn)->rcs); - cc_stat_reset(&(*pconn)->ccs); - - ngtcp2_qlog_start(&(*pconn)->qlog, &settings->qlog.odcid, server); + ngtcp2_qlog_start(&(*pconn)->qlog, server ? &settings->qlog.odcid : dcid, + server); ngtcp2_qlog_parameters_set_transport_params( &(*pconn)->qlog, &(*pconn)->local.settings.transport_params, + (*pconn)->server, /* local = */ 1); return 0; @@ -722,7 +815,8 @@ 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: - ngtcp2_default_cc_free(&(*pconn)->cc); + cc_del(&(*pconn)->cc, settings->cc_algo, mem); +fail_cc_init: ngtcp2_mem_free(mem, (*pconn)->qlog.buf.begin); fail_qlog_buf: ngtcp2_ringbuf_free(&(*pconn)->rx.path_challenge); @@ -790,6 +884,11 @@ int ngtcp2_conn_server_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, params->active_connection_id_limit = 0; } + if ((*pconn)->local.settings.token.len) { + /* Usage of token lifts amplification limit */ + (*pconn)->flags |= NGTCP2_CONN_FLAG_SADDR_VERIFIED; + } + return 0; } @@ -798,7 +897,7 @@ int ngtcp2_conn_server_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, * the given stream. Both connection and stream level flow control * credits are considered. */ -static size_t conn_fc_credits(ngtcp2_conn *conn, ngtcp2_strm *strm) { +static uint64_t conn_fc_credits(ngtcp2_conn *conn, ngtcp2_strm *strm) { return ngtcp2_min(strm->tx.max_offset - strm->tx.offset, conn->tx.max_offset - conn->tx.offset); } @@ -810,8 +909,8 @@ static size_t conn_fc_credits(ngtcp2_conn *conn, ngtcp2_strm *strm) { */ static size_t conn_enforce_flow_control(ngtcp2_conn *conn, ngtcp2_strm *strm, size_t len) { - size_t fc_credits = conn_fc_credits(conn, strm); - return ngtcp2_min(len, fc_credits); + uint64_t fc_credits = conn_fc_credits(conn, strm); + return (size_t)ngtcp2_min((uint64_t)len, fc_credits); } static int delete_strms_each(ngtcp2_map_entry *ent, void *ptr) { @@ -831,7 +930,6 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { ngtcp2_qlog_end(&conn->qlog); - ngtcp2_mem_free(conn->mem, conn->token.begin); ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_buf.base); ngtcp2_mem_free(conn->mem, conn->local.settings.token.base); @@ -845,7 +943,7 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) { pktns_del(conn->hs_pktns, conn->mem); pktns_del(conn->in_pktns, conn->mem); - ngtcp2_default_cc_free(&conn->cc); + cc_del(&conn->cc, conn->cc_algo, conn->mem); ngtcp2_mem_free(conn->mem, conn->qlog.buf.begin); @@ -908,14 +1006,8 @@ static int conn_ensure_ack_blks(ngtcp2_conn *conn, size_t n) { * ACK. */ static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) { - ngtcp2_duration initial_delay = - conn->local.settings.transport_params.max_ack_delay; - - if (conn->rcs.smoothed_rtt == 0) { - return initial_delay; - } - - return ngtcp2_min(initial_delay, conn->rcs.smoothed_rtt / 8); + return ngtcp2_min(conn->local.settings.transport_params.max_ack_delay, + conn->cstat.smoothed_rtt / 8); } /* @@ -1090,15 +1182,17 @@ static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_rtb *rtb, /* This function implements OnPacketSent, but it handles only non-ACK-only packet. */ - rv = ngtcp2_rtb_add(rtb, ent); + rv = ngtcp2_rtb_add(rtb, ent, &conn->cstat); if (rv != 0) { return rv; } if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) { - conn->rcs.last_tx_pkt_ts[rtb->crypto_level] = ent->ts; + conn->cstat.last_tx_pkt_ts[rtb->pktns_id] = ent->ts; + /* I think pseudo code is wrong; timer should be set when + ack-eliciting packet is sent. */ + ngtcp2_conn_set_loss_detection_timer(conn, ent->ts); } - ngtcp2_conn_set_loss_detection_timer(conn, ent->ts); return 0; } @@ -1133,22 +1227,17 @@ static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) { } /* - * conn_cwnd_left returns the number of bytes the local endpoint can - * sent at this time. + * 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_left(ngtcp2_conn *conn) { - uint64_t bytes_in_flight = ngtcp2_conn_get_bytes_in_flight(conn); +static uint64_t conn_cwnd_is_zero(ngtcp2_conn *conn) { + uint64_t bytes_in_flight = conn->cstat.bytes_in_flight; uint64_t cwnd = conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) - ? NGTCP2_MIN_CWND - : conn->ccs.cwnd; + ? ngtcp2_cc_compute_initcwnd(conn->cstat.max_udp_payload_size) + : conn->cstat.cwnd; - /* We might send more than bytes_in_flight if probe packets are - involved. */ - if (bytes_in_flight >= cwnd) { - return 0; - } - return cwnd - bytes_in_flight; + return bytes_in_flight >= cwnd; } /* @@ -1196,14 +1285,13 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_crypto *fr, *nfr; uint64_t offset, end_offset; size_t idx, end_idx; - size_t base_offset, end_base_offset; + uint64_t base_offset, end_base_offset; ngtcp2_ksl_it gapit; ngtcp2_range gap; ngtcp2_rtb *rtb = &pktns->rtb; ngtcp2_vec *v; int rv; ngtcp2_ksl_it it; - ngtcp2_ksl_key key; *pfrc = NULL; @@ -1211,8 +1299,7 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, frc = ngtcp2_ksl_it_get(&it); fr = &frc->fr.crypto; - ngtcp2_ksl_remove(&pktns->crypto.tx.frq, &it, - ngtcp2_ksl_key_ptr(&key, &fr->offset)); + ngtcp2_ksl_remove(&pktns->crypto.tx.frq, &it, &fr->offset); idx = 0; offset = fr->offset; @@ -1220,7 +1307,7 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, gapit = ngtcp2_gaptr_get_first_gap_after(&rtb->crypto->tx.acked_offset, offset); - gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit).ptr; + gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit); if (gap.begin < offset) { gap.begin = offset; } @@ -1269,7 +1356,7 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, fr->offset = offset + base_offset; fr->datacnt = end_idx - idx; fr->data[0].base += base_offset; - fr->data[0].len -= base_offset; + fr->data[0].len -= (size_t)base_offset; *pfrc = frc; return 0; @@ -1291,10 +1378,9 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, nfr->offset = end_offset + end_base_offset; nfr->datacnt = fr->datacnt - end_idx; nfr->data[0].base += end_base_offset; - nfr->data[0].len -= end_base_offset; + nfr->data[0].len -= (size_t)end_base_offset; - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - ngtcp2_ksl_key_ptr(&key, &nfr->offset), nfrc); + rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_del(nfrc, conn->mem); @@ -1314,10 +1400,10 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns, 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 = end_base_offset; + fr->data[fr->datacnt - 1].len = (size_t)end_base_offset; } fr->data[0].base += base_offset; - fr->data[0].len -= base_offset; + fr->data[0].len -= (size_t)base_offset; *pfrc = frc; return 0; @@ -1336,7 +1422,6 @@ static int conn_cryptofrq_pop(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, ngtcp2_vec b[NGTCP2_MAX_CRYPTO_DATACNT]; size_t acnt, bcnt; ngtcp2_ksl_it it; - ngtcp2_ksl_key key; rv = conn_cryptofrq_unacked_pop(conn, pktns, &frc); if (rv != 0) { @@ -1373,8 +1458,7 @@ static int conn_cryptofrq_pop(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, nfr->datacnt = bcnt; ngtcp2_vec_copy(nfr->data, b, bcnt); - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - ngtcp2_ksl_key_ptr(&key, &nfr->offset), nfrc); + rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_del(nfrc, conn->mem); @@ -1431,8 +1515,7 @@ static int conn_cryptofrq_pop(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, 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, - ngtcp2_ksl_key_ptr(&key, &nfr->offset), nfrc); + rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_del(nfrc, conn->mem); @@ -1452,8 +1535,7 @@ static int conn_cryptofrq_pop(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, nfr->offset += nmerged; - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - ngtcp2_ksl_key_ptr(&key, &nfr->offset), nfrc); + rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &nfr->offset, nfrc); if (rv != 0) { ngtcp2_frame_chain_del(nfrc, conn->mem); ngtcp2_frame_chain_del(frc, conn->mem); @@ -1508,13 +1590,11 @@ static int conn_cryptofrq_pop(ngtcp2_conn *conn, ngtcp2_frame_chain **pfrc, */ static int conn_verify_dcid(ngtcp2_conn *conn, int *pnew_cid_used, const ngtcp2_pkt_hd *hd) { - ngtcp2_ksl_key key; ngtcp2_ksl_it it; ngtcp2_scid *scid; int rv; - it = ngtcp2_ksl_lower_bound(&conn->scid.set, - ngtcp2_ksl_key_ptr(&key, &hd->dcid)); + it = ngtcp2_ksl_lower_bound(&conn->scid.set, &hd->dcid); if (ngtcp2_ksl_it_end(&it)) { return NGTCP2_ERR_INVALID_ARGUMENT; } @@ -1554,14 +1634,28 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, size_t early_datalen) { size_t min_payloadlen; - if (conn->server || type != NGTCP2_PKT_INITIAL) { + if (conn->server) { return 0; } - if (!conn->early.ckm || early_datalen == 0) { + if (type == NGTCP2_PKT_HANDSHAKE) { + return conn->in_pktns != NULL; + } + + if (conn->hs_pktns->crypto.tx.ckm && + (conn->hs_pktns->rtb.probe_pkt_left || + ngtcp2_ksl_len(&conn->hs_pktns->crypto.tx.frq) || + !ngtcp2_acktr_empty(&conn->hs_pktns->acktr))) { + /* If we have something to send in Handshake packet, then add + PADDING in Handshake packet. */ + min_payloadlen = 128; + } else if (!conn->early.ckm || early_datalen == 0) { return 1; + } else { + /* If we have something to send in 0RTT packet, then add PADDING + in 0RTT packet. */ + min_payloadlen = ngtcp2_min(early_datalen, 128); } - min_payloadlen = ngtcp2_min(early_datalen, 128); return left < /* TODO Assuming that pkt_num is encoded in 1 byte. */ @@ -1646,9 +1740,9 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, pktns->tx.last_pkt_num + 1, pktns_select_pkt_numlen(pktns), conn->version, 0); - if (type == NGTCP2_PKT_INITIAL && ngtcp2_buf_len(&conn->token)) { - hd.token = conn->token.pos; - hd.tokenlen = ngtcp2_buf_len(&conn->token); + if (!conn->server && type == NGTCP2_PKT_INITIAL && + conn->local.settings.token.len) { + hd.token = conn->local.settings.token; } ngtcp2_ppe_init(&ppe, dest, destlen, &cc); @@ -1663,6 +1757,25 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, return 0; } + rv = conn_create_ack_frame(conn, &ackfr, &pktns->acktr, type, ts, + /* ack_delay = */ 0, + NGTCP2_DEFAULT_ACK_DELAY_EXPONENT); + if (rv != 0) { + ngtcp2_frame_chain_list_del(frq, conn->mem); + return rv; + } + + if (ackfr) { + rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, ackfr); + if (rv != 0) { + assert(NGTCP2_ERR_NOBUF == rv); + } else { + ngtcp2_acktr_commit_ack(&pktns->acktr); + ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, ackfr->ack.largest_ack); + pkt_empty = 0; + } + } + for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) { left = ngtcp2_ppe_left(&ppe); left = ngtcp2_pkt_crypto_max_datalen( @@ -1696,25 +1809,6 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_CRYPTO_PKT; } - rv = conn_create_ack_frame(conn, &ackfr, &pktns->acktr, type, ts, - /* ack_delay = */ 0, - NGTCP2_DEFAULT_ACK_DELAY_EXPONENT); - if (rv != 0) { - ngtcp2_frame_chain_list_del(frq, conn->mem); - return rv; - } - - if (ackfr) { - rv = conn_ppe_write_frame_hd_log(conn, &ppe, &hd_logged, &hd, ackfr); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - } else { - ngtcp2_acktr_commit_ack(&pktns->acktr); - ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, ackfr->ack.largest_ack); - pkt_empty = 0; - } - } - /* Don't send any PING frame if client Initial has not been acknowledged yet. */ if (!(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) && @@ -1809,7 +1903,7 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest, --pktns->rtb.probe_pkt_left; } - ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); + ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); ++pktns->tx.last_pkt_num; @@ -1882,6 +1976,50 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, uint8_t *dest, NGTCP2_RTB_FLAG_NONE, ts); } +static void conn_discard_pktns(ngtcp2_conn *conn, ngtcp2_pktns **ppktns, + ngtcp2_tstamp ts) { + ngtcp2_pktns *pktns = *ppktns; + uint64_t bytes_in_flight; + + bytes_in_flight = pktns->rtb.cc_bytes_in_flight; + + assert(conn->cstat.bytes_in_flight >= bytes_in_flight); + + conn->cstat.bytes_in_flight -= bytes_in_flight; + conn->cstat.pto_count = 0; + conn->cstat.last_tx_pkt_ts[pktns->rtb.pktns_id] = UINT64_MAX; + conn->cstat.loss_time[pktns->rtb.pktns_id] = UINT64_MAX; + + pktns_del(pktns, conn->mem); + *ppktns = NULL; + + ngtcp2_conn_set_loss_detection_timer(conn, ts); +} + +/* + * conn_discard_initial_state discards state for Initial packet number + * space. + */ +static void conn_discard_initial_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + if (!conn->in_pktns) { + return; + } + + conn_discard_pktns(conn, &conn->in_pktns, ts); +} + +/* + * conn_discard_handshake_state discards state for Handshake packet + * number space. + */ +static void conn_discard_handshake_state(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + if (!conn->hs_pktns) { + return; + } + + conn_discard_pktns(conn, &conn->hs_pktns, ts); +} + /* * conn_write_handshake_ack_pkts writes packets which contain ACK * frame only. This function writes at most 2 packets for each @@ -1892,9 +2030,12 @@ static ngtcp2_ssize conn_write_handshake_ack_pkts(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_ssize res = 0, nwrite = 0; - /* Actullay client never send ACK for server Initial. This is + /* 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. */ + 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, dest, destlen, NGTCP2_PKT_INITIAL, ts); if (nwrite < 0) { @@ -1913,7 +2054,12 @@ static ngtcp2_ssize conn_write_handshake_ack_pkts(ngtcp2_conn *conn, assert(nwrite != NGTCP2_ERR_NOBUF); return nwrite; } + res += nwrite; + + if (!conn->server && nwrite) { + conn_discard_initial_state(conn, ts); + } } return res; @@ -1967,21 +2113,24 @@ static ngtcp2_ssize conn_write_handshake_pkts(ngtcp2_conn *conn, uint8_t *dest, ngtcp2_ssize nwrite; ngtcp2_ssize res = 0; - nwrite = conn_write_handshake_pkt(conn, dest, destlen, NGTCP2_PKT_INITIAL, - early_datalen, ts); - if (nwrite < 0) { - assert(nwrite != NGTCP2_ERR_NOBUF); - return nwrite; - } + if (!conn->server && conn->hs_pktns->crypto.tx.ckm && + !ngtcp2_acktr_empty(&conn->hs_pktns->acktr)) { + /* Discard Initial state here so that Handshake packet is not + padded. */ + conn_discard_initial_state(conn, ts); + } else { + nwrite = conn_write_handshake_pkt(conn, dest, destlen, NGTCP2_PKT_INITIAL, + early_datalen, ts); + if (nwrite < 0) { + assert(nwrite != NGTCP2_ERR_NOBUF); + return nwrite; + } - if (!conn->server && nwrite) { - return nwrite; + res += nwrite; + dest += nwrite; + destlen -= (size_t)nwrite; } - res += nwrite; - dest += nwrite; - destlen -= (size_t)nwrite; - nwrite = conn_write_handshake_pkt(conn, dest, destlen, NGTCP2_PKT_HANDSHAKE, 0, ts); if (nwrite < 0) { @@ -1991,34 +2140,11 @@ static ngtcp2_ssize conn_write_handshake_pkts(ngtcp2_conn *conn, uint8_t *dest, res += nwrite; - return res; -} - -static ngtcp2_ssize conn_write_server_handshake(ngtcp2_conn *conn, - uint8_t *dest, size_t destlen, - ngtcp2_tstamp ts) { - ngtcp2_ssize nwrite; - ngtcp2_ssize res = 0; - - nwrite = conn_write_handshake_pkts(conn, dest, destlen, 0, ts); - if (nwrite < 0) { - assert(nwrite != NGTCP2_ERR_NOBUF); - return nwrite; - } - - res += nwrite; - dest += nwrite; - destlen -= (size_t)nwrite; - - /* Acknowledge 0-RTT packet here. */ - if (conn->pktns.crypto.tx.ckm) { - nwrite = conn_write_ack_pkt(conn, dest, destlen, NGTCP2_PKT_SHORT, ts); - if (nwrite < 0) { - assert(nwrite != NGTCP2_ERR_NOBUF); - return nwrite; - } - - res += nwrite; + if (!conn->server && conn->hs_pktns->crypto.tx.ckm && nwrite) { + /* We don't need to send further Initial packet if we have + Handshake key and sent something with it. So discard initial + state here. */ + conn_discard_initial_state(conn, ts); } return res; @@ -2055,8 +2181,12 @@ static int conn_should_send_max_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm) { uint64_t win = conn_initial_stream_rx_offset(conn, strm->stream_id); uint64_t inc = strm->rx.unsent_max_offset - strm->rx.max_offset; + ngtcp2_conn_stat *cstat = &conn->cstat; - return win < 2 * inc || inc >= 10 * NGTCP2_MAX_DGRAM_SIZE; + return win < 2 * inc || + (cstat->min_rtt != UINT64_MAX && + 2 * cstat->recv_rate_sec * cstat->min_rtt / NGTCP2_SECONDS > + win - inc); } /* @@ -2065,9 +2195,12 @@ static int conn_should_send_max_stream_data(ngtcp2_conn *conn, */ static int conn_should_send_max_data(ngtcp2_conn *conn) { uint64_t inc = conn->rx.unsent_max_offset - conn->rx.max_offset; + ngtcp2_conn_stat *cstat = &conn->cstat; return conn->local.settings.transport_params.initial_max_data < 2 * inc || - inc >= 10 * NGTCP2_MAX_DGRAM_SIZE; + (cstat->min_rtt != UINT64_MAX && + 2 * cstat->recv_rate_sec * cstat->min_rtt / NGTCP2_SECONDS > + conn->local.settings.transport_params.initial_max_data - inc); } /* @@ -2076,7 +2209,8 @@ static int conn_should_send_max_data(ngtcp2_conn *conn) { * remote endpoint. */ static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { - size_t n, len = ngtcp2_ksl_len(&conn->scid.set); + uint64_t n; + size_t len = ngtcp2_ksl_len(&conn->scid.set); if (len >= NGTCP2_MAX_SCID_POOL_SIZE) { return 0; @@ -2088,7 +2222,7 @@ 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 ngtcp2_min(NGTCP2_MAX_SCID_POOL_SIZE, n) - len; + return (size_t)ngtcp2_min(NGTCP2_MAX_SCID_POOL_SIZE, n) - len; } /* @@ -2113,7 +2247,6 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { ngtcp2_frame_chain *nfrc; ngtcp2_pktns *pktns = &conn->pktns; ngtcp2_scid *scid; - ngtcp2_ksl_key key; ngtcp2_ksl_it it; for (i = 0; i < need; ++i) { @@ -2127,10 +2260,9 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { } /* Assert uniqueness */ - it = - ngtcp2_ksl_lower_bound(&conn->scid.set, ngtcp2_ksl_key_ptr(&key, &cid)); + it = ngtcp2_ksl_lower_bound(&conn->scid.set, &cid); if (!ngtcp2_ksl_it_end(&it) && - ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it).ptr, &cid)) { + ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it), &cid)) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -2143,8 +2275,7 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { ngtcp2_scid_init(scid, seq, &cid, token); - rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, - ngtcp2_ksl_key_ptr(&key, &scid->cid), scid); + rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scid->cid, scid); if (rv != 0) { ngtcp2_mem_free(conn->mem, scid); return rv; @@ -2171,21 +2302,22 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { /* * conn_compute_pto computes the current PTO. */ -static ngtcp2_duration conn_compute_pto(ngtcp2_conn *conn) { - ngtcp2_rcvry_stat *rcs = &conn->rcs; - ngtcp2_duration var = ngtcp2_max(4 * rcs->rttvar, NGTCP2_GRANULARITY); +static ngtcp2_duration conn_compute_pto(ngtcp2_conn *conn, + ngtcp2_pktns *pktns) { + ngtcp2_conn_stat *cstat = &conn->cstat; + ngtcp2_duration var = ngtcp2_max(4 * cstat->rttvar, NGTCP2_GRANULARITY); ngtcp2_duration max_ack_delay = - (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) + pktns->rtb.pktns_id == NGTCP2_PKTNS_ID_APP ? conn->remote.transport_params.max_ack_delay - : NGTCP2_DEFAULT_MAX_ACK_DELAY; - return rcs->smoothed_rtt + var + max_ack_delay; + : 0; + return cstat->smoothed_rtt + var + max_ack_delay; } /* * conn_remove_retired_connection_id removes the already retired - * connection ID. It waits RTT * 2 before actually removing a - * connection ID after it receives RETIRE_CONNECTION_ID from peer to - * catch reordered packets. + * connection ID. It waits PTO before actually removing a connection + * ID after it receives RETIRE_CONNECTION_ID from peer to catch + * reordered packets. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2197,9 +2329,8 @@ static ngtcp2_duration conn_compute_pto(ngtcp2_conn *conn) { */ static int conn_remove_retired_connection_id(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - ngtcp2_duration timeout = conn_compute_pto(conn); + ngtcp2_duration timeout = conn_compute_pto(conn, &conn->pktns); ngtcp2_scid *scid; - ngtcp2_ksl_key key; ngtcp2_dcid *dcid; int rv; @@ -2217,8 +2348,7 @@ static int conn_remove_retired_connection_id(ngtcp2_conn *conn, return rv; } - ngtcp2_ksl_remove(&conn->scid.set, NULL, - ngtcp2_ksl_key_ptr(&key, &scid->cid)); + ngtcp2_ksl_remove(&conn->scid.set, NULL, &scid->cid); ngtcp2_pq_pop(&conn->scid.used); ngtcp2_mem_free(conn->mem, scid); @@ -2322,6 +2452,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, size_t min_pktlen = conn_min_short_pktlen(conn); int padded = 0; int credit_expanded = 0; + ngtcp2_cc_pkt cc_pkt; /* Return 0 if destlen is less than minimum packet length which can trigger Stateless Reset */ @@ -2517,11 +2648,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, break; } - if ((*pfrc)->fr.type == NGTCP2_FRAME_RETIRE_CONNECTION_ID) { - assert(conn->dcid.num_retire_queued); - --conn->dcid.num_retire_queued; - } - pkt_empty = 0; rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; pfrc = &(*pfrc)->next; @@ -2789,25 +2915,27 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, if (pkt_empty) { assert(rv == 0 || NGTCP2_ERR_NOBUF == rv); - if (rv == 0 && stream_blocked) { + if (rv == 0 && stream_blocked && ngtcp2_conn_get_max_data_left(conn)) { return NGTCP2_ERR_STREAM_DATA_BLOCKED; } - return 0; - } - if (stream_more) { + if (conn->pktns.rtb.probe_pkt_left == 0) { + return 0; + } + } else if (stream_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; - if (stream_blocked) { - return NGTCP2_ERR_STREAM_DATA_BLOCKED; - } if (send_stream) { return NGTCP2_ERR_WRITE_STREAM_MORE; } + + if (ngtcp2_conn_get_max_data_left(conn) && stream_blocked) { + return NGTCP2_ERR_STREAM_DATA_BLOCKED; + } } if (!(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING)) { @@ -2818,8 +2946,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr); if (rv != 0) { assert(rv == NGTCP2_ERR_NOBUF); + /* TODO If buffer is too small, PING cannot be written if + packet is still empty. */ } else { rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING; + if (pktns->rtb.probe_pkt_left) { + rtb_entry_flags |= NGTCP2_RTB_FLAG_PROBE; + } pktns->tx.num_non_ack_pkt = 0; } } else { @@ -2852,6 +2985,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, return nwrite; } + ++cc->ckm->use_count; + ngtcp2_qlog_pkt_sent_end(&conn->qlog, hd, (size_t)nwrite); if ((rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) || padded) { @@ -2868,6 +3003,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, *pfrc = NULL; } + if ((rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) && + pktns->rtb.num_ack_eliciting == 0 && conn->cc.event) { + conn->cc.event(&conn->cc, &conn->cstat, NGTCP2_CC_EVENT_TYPE_TX_START, + ts); + } + rv = conn_on_pkt_sent(conn, &pktns->rtb, ent); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); @@ -2875,15 +3016,31 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest, return rv; } - if ((rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) && - (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE)) { - conn_restart_timer_on_write(conn, ts); + if (rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) { + if (conn->cc.on_pkt_sent) { + conn->cc.on_pkt_sent(&conn->cc, &conn->cstat, + ngtcp2_cc_pkt_init(&cc_pkt, hd->pkt_num, + (size_t)nwrite, + NGTCP2_PKTNS_ID_APP, ts)); + } + + if (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE) { + conn_restart_timer_on_write(conn, ts); + } } } conn->flags &= (uint16_t)~NGTCP2_CONN_FLAG_PPE_PENDING; - ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); + if (pktns->rtb.probe_pkt_left && + (rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING)) { + --pktns->rtb.probe_pkt_left; + + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td", + nwrite); + } + + ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); ++pktns->tx.last_pkt_num; @@ -2905,7 +3062,6 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest, uint8_t flags; ngtcp2_rtb_entry *rtbent; int padded = 0; - size_t pktlen; switch (type) { case NGTCP2_PKT_INITIAL: @@ -2971,15 +3127,6 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest, lfr.padding.len = ngtcp2_ppe_padding_hp_sample(&ppe); } if (lfr.padding.len) { - if (fr->type == NGTCP2_FRAME_ACK) { - /* If PADDING is added, the packet suddenly gets CWND - limited. */ - pktlen = ngtcp2_ppe_pktlen(&ppe); - if (pktlen > conn_cwnd_left(conn)) { - return 0; - } - } - padded = 1; ngtcp2_log_tx_fr(&conn->log, &hd, &lfr); ngtcp2_qlog_write_frame(&conn->qlog, &lfr); @@ -2990,6 +3137,8 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest, return nwrite; } + ++cc.ckm->use_count; + ngtcp2_qlog_pkt_sent_end(&conn->qlog, &hd, (size_t)nwrite); /* Do this when we are sure that there is no error. */ @@ -3017,7 +3166,7 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest, } } - ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); + ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); ++pktns->tx.last_pkt_num; @@ -3048,215 +3197,27 @@ static void conn_process_early_rtb(ngtcp2_conn *conn) { } /* - * conn_write_probe_ping writes probe packet containing PING frame - * (and optionally ACK frame) to the buffer pointed by |dest| of - * length |destlen|. Probe packet is always Short packet. This - * function might return 0 if it cannot write packet (e.g., |destlen| - * is too small). + * conn_handshake_remnants_left returns nonzero if there may be + * handshake packets the local endpoint has to send, including new + * packets and lost ones. + */ +static int conn_handshake_remnants_left(ngtcp2_conn *conn) { + ngtcp2_pktns *in_pktns = conn->in_pktns; + ngtcp2_pktns *hs_pktns = conn->hs_pktns; + + return !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) || + (in_pktns && (in_pktns->rtb.num_ack_eliciting || + ngtcp2_ksl_len(&in_pktns->crypto.tx.frq))) || + (hs_pktns && (hs_pktns->rtb.num_ack_eliciting || + ngtcp2_ksl_len(&hs_pktns->crypto.tx.frq))); +} + +/* + * conn_retire_dcid_seq retires destination connection ID denoted by + * |seq|. * - * This function returns the number of bytes written to |dest|, or one - * of the following negative error codes: - * - * NGTCP2_ERR_CALLBACK_FAILURE - * User-defined callback function failed. - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static ngtcp2_ssize conn_write_probe_ping(ngtcp2_conn *conn, uint8_t *dest, - size_t destlen, ngtcp2_tstamp ts) { - ngtcp2_ppe ppe; - ngtcp2_pkt_hd hd; - ngtcp2_pktns *pktns = &conn->pktns; - ngtcp2_crypto_cc cc; - ngtcp2_frame_chain *frc = NULL; - ngtcp2_rtb_entry *ent; - ngtcp2_frame *ackfr = NULL, lfr; - int rv; - ngtcp2_ssize nwrite; - - assert(pktns->crypto.tx.ckm); - - cc.aead_overhead = conn->crypto.aead_overhead; - cc.encrypt = conn->callbacks.encrypt; - cc.hp_mask = conn->callbacks.hp_mask; - cc.aead = pktns->crypto.ctx.aead; - cc.hp = pktns->crypto.ctx.hp; - cc.ckm = pktns->crypto.tx.ckm; - cc.hp_key = pktns->crypto.tx.hp_key; - - ngtcp2_pkt_hd_init( - &hd, - (pktns->crypto.tx.ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE) - ? NGTCP2_PKT_FLAG_KEY_PHASE - : NGTCP2_PKT_FLAG_NONE, - NGTCP2_PKT_SHORT, &conn->dcid.current.cid, NULL, - pktns->tx.last_pkt_num + 1, pktns_select_pkt_numlen(pktns), conn->version, - 0); - - ngtcp2_ppe_init(&ppe, dest, destlen, &cc); - - rv = ngtcp2_ppe_encode_hd(&ppe, &hd); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - return 0; - } - - if (!ngtcp2_ppe_ensure_hp_sample(&ppe)) { - return 0; - } - - ngtcp2_log_tx_pkt_hd(&conn->log, &hd); - ngtcp2_qlog_pkt_sent_start(&conn->qlog, &hd); - - rv = ngtcp2_frame_chain_new(&frc, conn->mem); - if (rv != 0) { - return rv; - } - - frc->fr.type = NGTCP2_FRAME_PING; - - rv = conn_ppe_write_frame(conn, &ppe, &hd, &frc->fr); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - rv = 0; - goto fail; - } - - rv = conn_create_ack_frame( - conn, &ackfr, &pktns->acktr, NGTCP2_PKT_SHORT, ts, - conn_compute_ack_delay(conn), - conn->local.settings.transport_params.ack_delay_exponent); - if (rv != 0) { - goto fail; - } - - if (ackfr) { - rv = conn_ppe_write_frame(conn, &ppe, &hd, ackfr); - if (rv != 0) { - assert(NGTCP2_ERR_NOBUF == rv); - } else { - ngtcp2_acktr_commit_ack(&pktns->acktr); - ngtcp2_acktr_add_ack(&pktns->acktr, hd.pkt_num, ackfr->ack.largest_ack); - } - } - - lfr.type = NGTCP2_FRAME_PADDING; - lfr.padding.len = ngtcp2_ppe_padding_size(&ppe, conn_min_short_pktlen(conn)); - if (lfr.padding.len) { - ngtcp2_log_tx_fr(&conn->log, &hd, &lfr); - ngtcp2_qlog_write_frame(&conn->qlog, &lfr); - } - - nwrite = ngtcp2_ppe_final(&ppe, NULL); - if (nwrite < 0) { - rv = (int)nwrite; - goto fail; - } - - ngtcp2_qlog_pkt_sent_end(&conn->qlog, &hd, (size_t)nwrite); - - rv = ngtcp2_rtb_entry_new( - &ent, &hd, frc, ts, (size_t)nwrite, - NGTCP2_RTB_FLAG_PROBE | NGTCP2_RTB_FLAG_ACK_ELICITING, conn->mem); - if (rv != 0) { - goto fail; - } - - rv = conn_on_pkt_sent(conn, &pktns->rtb, ent); - if (rv != 0) { - ngtcp2_rtb_entry_del(ent, conn->mem); - return rv; - } - - if (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE) { - conn_restart_timer_on_write(conn, ts); - } - - ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); - - ++pktns->tx.last_pkt_num; - - return nwrite; - -fail: - ngtcp2_frame_chain_del(frc, conn->mem); - - return rv; -} - -/* - * conn_write_probe_pkt writes a QUIC Short packet as probe packet. - * The packet is written to the buffer pointed by |dest| of length - * |destlen|. This function can send new stream data. In order to - * send stream data, specify the underlying stream to |strm|. If - * |fin| is set to nonzero, it signals that the given data is the - * final portion of the stream. |datav| vector of length |datavcnt| - * specify stream data to send. If no stream data to send, set |strm| - * to NULL. The number of bytes sent to the stream is assigned to - * |*pdatalen|. If 0 length STREAM data is sent, 0 is assigned to - * |*pdatalen|. The caller should initialize |*pdatalen| to -1. - * - * This function returns the number of bytes written to the buffer - * pointed by |dest|, or one of the following negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - * NGTCP2_ERR_CALLBACK_FAILURE - * User-defined callback function failed. - * NGTCP2_ERR_STREAM_DATA_BLOCKED - * Stream data could not be written because of flow control. - */ -static ngtcp2_ssize conn_write_probe_pkt(ngtcp2_conn *conn, uint8_t *dest, - size_t destlen, ngtcp2_ssize *pdatalen, - ngtcp2_strm *strm, int fin, - const ngtcp2_vec *datav, - size_t datavcnt, ngtcp2_tstamp ts) { - ngtcp2_ssize nwrite; - - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, - "transmit probe pkt left=%zu", - conn->pktns.rtb.probe_pkt_left); - - /* a probe packet is not blocked by cwnd. */ - nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT, strm, - fin, datav, datavcnt, NGTCP2_WRITE_PKT_FLAG_NONE, ts); - if (nwrite == 0 || nwrite == NGTCP2_ERR_STREAM_DATA_BLOCKED) { - nwrite = conn_write_probe_ping(conn, dest, destlen, ts); - } - if (nwrite <= 0) { - return nwrite; - } - - --conn->pktns.rtb.probe_pkt_left; - - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "probe pkt size=%td", - nwrite); - - return nwrite; -} - -/* - * conn_handshake_remnants_left returns nonzero if there may be - * handshake packets the local endpoint has to send, including new - * packets and lost ones. - */ -static int conn_handshake_remnants_left(ngtcp2_conn *conn) { - ngtcp2_pktns *in_pktns = conn->in_pktns; - ngtcp2_pktns *hs_pktns = conn->hs_pktns; - - return !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) || - (in_pktns && (ngtcp2_rtb_num_ack_eliciting(&in_pktns->rtb) || - ngtcp2_ksl_len(&in_pktns->crypto.tx.frq))) || - (hs_pktns && (ngtcp2_rtb_num_ack_eliciting(&hs_pktns->rtb) || - ngtcp2_ksl_len(&hs_pktns->crypto.tx.frq))); -} - -/* - * conn_retire_dcid_seq retires destination connection ID denoted by - * |seq|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: + * This function returns 0 if it succeeds, or one of the following + * negative error codes: * * NGTCP2_ERR_NOMEM * Out of memory. @@ -3450,11 +3411,11 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, ngtcp2_ssize ngtcp2_conn_write_pkt(ngtcp2_conn *conn, ngtcp2_path *path, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts) { - return ngtcp2_conn_writev_stream( - conn, path, dest, destlen, - /* pdatalen = */ NULL, NGTCP2_WRITE_STREAM_FLAG_NONE, - /* stream_id = */ -1, - /* fin = */ 0, /* datav = */ NULL, /* datavcnt = */ 0, ts); + return ngtcp2_conn_writev_stream(conn, path, dest, destlen, + /* pdatalen = */ NULL, + NGTCP2_WRITE_STREAM_FLAG_NONE, + /* stream_id = */ -1, + /* datav = */ NULL, /* datavcnt = */ 0, ts); } /* @@ -3481,6 +3442,7 @@ static int conn_on_version_negotiation(ngtcp2_conn *conn, uint32_t *p; int rv = 0; size_t nsv; + size_t i; if (payloadlen % sizeof(uint32_t)) { return NGTCP2_ERR_INVALID_ARGUMENT; @@ -3495,28 +3457,41 @@ static int conn_on_version_negotiation(ngtcp2_conn *conn, p = sv; } - /* TODO Just move to the terminal state for now in order not to send - CONNECTION_CLOSE frame. */ - conn->state = NGTCP2_CS_DRAINING; - nsv = ngtcp2_pkt_decode_version_negotiation(p, payload, payloadlen); ngtcp2_log_rx_vn(&conn->log, hd, p, nsv); + for (i = 0; i < nsv; ++i) { + if (p[i] == conn->version) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "ignore Version Negotiation because it contains version " + "selected by client"); + + rv = NGTCP2_ERR_INVALID_ARGUMENT; + goto fin; + } + } + if (conn->callbacks.recv_version_negotiation) { rv = conn->callbacks.recv_version_negotiation(conn, hd, p, nsv, conn->user_data); + if (rv != 0) { + rv = NGTCP2_ERR_CALLBACK_FAILURE; + } } - if (p != sv) { - ngtcp2_mem_free(conn->mem, p); + if (rv == 0) { + /* TODO Just move to the terminal state for now in order not to + send CONNECTION_CLOSE frame. */ + conn->state = NGTCP2_CS_DRAINING; } - if (rv != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; +fin: + if (p != sv) { + ngtcp2_mem_free(conn->mem, p); } - return 0; + return rv; } static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn) { @@ -3546,7 +3521,6 @@ static int conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_frame_chain *frc; ngtcp2_stream *sfr; ngtcp2_strm *strm; - ngtcp2_ksl_key key; int rv; if (*pfrc == NULL) { @@ -3587,8 +3561,7 @@ static int conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns, frc->next = NULL; rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - ngtcp2_ksl_key_ptr(&key, &frc->fr.crypto.offset), - frc); + &frc->fr.crypto.offset, frc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_del(frc, conn->mem); @@ -3628,17 +3601,19 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, size_t hdpktlen, const uint8_t *pkt, size_t pktlen) { int rv; ngtcp2_pkt_retry retry; - uint8_t *p; ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_rtb *rtb = &conn->pktns.rtb; - ngtcp2_rtb *in_rtb = &in_pktns->rtb; + ngtcp2_rtb *in_rtb; uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1]; ngtcp2_frame_chain *frc = NULL; + ngtcp2_vec *token; - if (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) { + if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) { return 0; } + in_rtb = &in_pktns->rtb; + rv = ngtcp2_pkt_decode_retry(&retry, pkt + hdpktlen, pktlen - hdpktlen); if (rv != 0) { return rv; @@ -3658,7 +3633,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.tokenlen == 0) { + if (retry.token.len == 0) { return NGTCP2_ERR_PROTO; } @@ -3669,12 +3644,13 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, /* DCID must be updated before invoking callback because client generates new initial keys there. */ conn->dcid.current.cid = hd->scid; + conn->retry_scid = hd->scid; conn->flags |= NGTCP2_CONN_FLAG_RECV_RETRY; assert(conn->callbacks.recv_retry); - rv = conn->callbacks.recv_retry(conn, hd, &retry, conn->user_data); + rv = conn->callbacks.recv_retry(conn, hd, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -3683,7 +3659,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, /* Just freeing memory is dangerous because we might free twice. */ - ngtcp2_rtb_remove_all(rtb, &frc); + ngtcp2_rtb_remove_all(rtb, &frc, &conn->cstat); rv = conn_resched_frames(conn, &conn->pktns, &frc); if (rv != 0) { @@ -3693,7 +3669,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, } frc = NULL; - ngtcp2_rtb_remove_all(in_rtb, &frc); + ngtcp2_rtb_remove_all(in_rtb, &frc, &conn->cstat); rv = conn_resched_frames(conn, in_pktns, &frc); if (rv != 0) { @@ -3702,17 +3678,19 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, return rv; } - assert(conn->token.begin == NULL); + token = &conn->local.settings.token; - p = ngtcp2_mem_malloc(conn->mem, retry.tokenlen); - if (p == NULL) { + ngtcp2_mem_free(conn->mem, token->base); + token->base = NULL; + token->len = 0; + + token->base = ngtcp2_mem_malloc(conn->mem, retry.token.len); + if (token->base == NULL) { return NGTCP2_ERR_NOMEM; } - ngtcp2_buf_init(&conn->token, p, retry.tokenlen); + token->len = retry.token.len; - ngtcp2_cpymem(conn->token.begin, retry.token, retry.tokenlen); - conn->token.pos = conn->token.begin; - conn->token.last = conn->token.pos + retry.tokenlen; + ngtcp2_cpymem(token->base, retry.token.base, retry.token.len); conn_reset_congestion_state(conn); @@ -3720,12 +3698,12 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, } int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_rcvry_stat *rcs, ngtcp2_tstamp ts) { + ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { ngtcp2_frame_chain *frc = NULL; int rv; - ngtcp2_duration pto = conn_compute_pto(conn); + ngtcp2_duration pto = conn_compute_pto(conn, pktns); - ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, &frc, rcs, pto, ts); + ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, &frc, cstat, pto, ts); rv = conn_resched_frames(conn, pktns, &frc); if (rv != 0) { @@ -3758,8 +3736,8 @@ 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_rcvry_stat *rcs = &conn->rcs; ngtcp2_ssize num_acked; + ngtcp2_conn_stat *cstat = &conn->cstat; if (pktns->tx.last_pkt_num < fr->largest_ack) { return NGTCP2_ERR_PROTO; @@ -3772,7 +3750,8 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, ngtcp2_acktr_recv_ack(&pktns->acktr, fr); - num_acked = ngtcp2_rtb_recv_ack(&pktns->rtb, fr, conn, pkt_ts, ts); + num_acked = + ngtcp2_rtb_recv_ack(&pktns->rtb, fr, &conn->cstat, conn, pkt_ts, ts); if (num_acked < 0) { /* TODO assert this */ assert(ngtcp2_err_is_fatal((int)num_acked)); @@ -3784,14 +3763,20 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, return 0; } - rv = ngtcp2_conn_detect_lost_pkt(conn, pktns, &conn->rcs, ts); + rv = ngtcp2_conn_detect_lost_pkt(conn, pktns, &conn->cstat, ts); if (rv != 0) { return rv; } - rcs->pto_count = 0; pktns->rtb.probe_pkt_left = 0; + if (cstat->pto_count && + (conn->server || (conn->flags & NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED))) { + /* Reset PTO count but no less than 2 to avoid frequent probe + packet transmission. */ + cstat->pto_count = ngtcp2_min(cstat->pto_count, 2); + } + ngtcp2_conn_set_loss_detection_timer(conn, ts); return 0; @@ -4144,13 +4129,18 @@ static void conn_recv_path_challenge(ngtcp2_conn *conn, * conn_reset_congestion_state resets congestion state. */ static void conn_reset_congestion_state(ngtcp2_conn *conn) { - rcvry_stat_reset(&conn->rcs); - cc_stat_reset(&conn->ccs); + conn_reset_conn_stat(conn, &conn->cstat); + + conn_reset_rx_rate(conn); + + conn->cc.reset(&conn->cc); if (conn->hs_pktns) { - conn->hs_pktns->rtb.cc_pkt_num = conn->hs_pktns->tx.last_pkt_num + 1; + ngtcp2_rtb_reset_cc_state(&conn->hs_pktns->rtb, + conn->hs_pktns->tx.last_pkt_num + 1); } - conn->pktns.rtb.cc_pkt_num = conn->pktns.tx.last_pkt_num + 1; + ngtcp2_rtb_reset_cc_state(&conn->pktns.rtb, conn->pktns.tx.last_pkt_num + 1); + ngtcp2_rst_init(&conn->rst); } static int conn_recv_path_response(ngtcp2_conn *conn, ngtcp2_path_response *fr, @@ -4223,7 +4213,6 @@ 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 rv; ngtcp2_ksl_it it; - ngtcp2_ksl_key key; ngtcp2_range range; if (pktns->rx.max_pkt_num + 1 != pkt_num) { @@ -4240,59 +4229,20 @@ static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num) { if (ngtcp2_ksl_len(&pktns->rx.pngap.gap) > 256) { it = ngtcp2_ksl_begin(&pktns->rx.pngap.gap); - range = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it).ptr; - ngtcp2_ksl_remove(&pktns->rx.pngap.gap, NULL, - ngtcp2_ksl_key_ptr(&key, &range)); + range = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it); + ngtcp2_ksl_remove(&pktns->rx.pngap.gap, NULL, &range); } return 0; } -static void conn_discard_pktns(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { - uint64_t bytes_in_flight; - - bytes_in_flight = ngtcp2_rtb_get_bytes_in_flight(&pktns->rtb); - - assert(conn->ccs.bytes_in_flight >= bytes_in_flight); - - conn->ccs.bytes_in_flight -= bytes_in_flight; - - pktns_del(pktns, conn->mem); -} - -/* - * conn_discard_initial_state discards state for Initial packet number - * space. - */ -static void conn_discard_initial_state(ngtcp2_conn *conn) { - if (!conn->in_pktns) { - return; - } - - conn_discard_pktns(conn, conn->in_pktns); - conn->in_pktns = NULL; -} - -/* - * conn_discard_handshake_state discards state for Handshake packet - * number space. - */ -static void conn_discard_handshake_state(ngtcp2_conn *conn) { - if (!conn->hs_pktns) { - return; - } - - conn_discard_pktns(conn, conn->hs_pktns); - conn->hs_pktns = NULL; -} - /* * 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->tokenlen && - ngtcp2_cmemeq(token->base, hd->token, token->len)) { + if (token->len == hd->token.len && + ngtcp2_cmemeq(token->base, hd->token.base, token->len)) { return 0; } return NGTCP2_ERR_PROTO; @@ -4412,12 +4362,7 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, return NGTCP2_ERR_DISCARD_PKT; } - /* TODO Do not change state here? */ - rv = conn_verify_dcid(conn, NULL, &hd); - if (rv != 0) { - if (ngtcp2_err_is_fatal(rv)) { - return rv; - } + if (!ngtcp2_cid_eq(&conn->oscid, &hd.dcid)) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet was ignored because of mismatched DCID"); return NGTCP2_ERR_DISCARD_PKT; @@ -4534,12 +4479,18 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, } } if ((conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED) == 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 + will be dropped. */ + conn->rcid = hd.dcid; + rv = conn_call_recv_client_initial(conn, &hd.dcid); if (rv != 0) { return rv; } } - } else if (hd.tokenlen != 0) { + } else if (hd.token.len != 0) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "packet was ignored because token is not empty"); return NGTCP2_ERR_DISCARD_PKT; @@ -4697,12 +4648,9 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, if (hd.type == NGTCP2_PKT_INITIAL && !(conn->flags & NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED)) { conn->flags |= NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED; - if (conn->server) { - conn->rcid = hd.dcid; - } else { + if (!conn->server) { conn->dcid.current.cid = hd.scid; } - conn->odcid = hd.scid; } ngtcp2_qlog_pkt_received_start(&conn->qlog, &hd); @@ -4726,13 +4674,13 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, switch (fr->type) { case NGTCP2_FRAME_ACK: case NGTCP2_FRAME_ACK_ECN: + if (!conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) { + conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; + } rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts); if (rv != 0) { return rv; } - if (!conn->server && hd.type == NGTCP2_PKT_HANDSHAKE) { - conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; - } break; case NGTCP2_FRAME_PADDING: break; @@ -4781,7 +4729,7 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn, conn_restart_timer_on_read(conn, ts); - ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); + ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); return conn->state == NGTCP2_CS_DRAINING ? NGTCP2_ERR_DRAINING : (ngtcp2_ssize)pktlen; @@ -4801,7 +4749,7 @@ static int conn_recv_handshake_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_tstamp ts) { ngtcp2_ssize nread; - conn->hs_recved += pktlen; + conn->cstat.bytes_recv += pktlen; while (pktlen) { nread = conn_recv_handshake_pkt(conn, path, pkt, pktlen, ts, ts); @@ -4810,19 +4758,41 @@ static int conn_recv_handshake_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path, return (int)nread; } - switch (nread) { - case NGTCP2_ERR_DISCARD_PKT: - return 0; - case NGTCP2_ERR_DRAINING: + if (nread == NGTCP2_ERR_DRAINING) { return NGTCP2_ERR_DRAINING; } - if (nread != NGTCP2_ERR_CRYPTO && (pkt[0] & NGTCP2_HEADER_FORM_BIT) && + if ((pkt[0] & NGTCP2_HEADER_FORM_BIT) && /* Not a Version Negotiation packet */ pktlen > 4 && ngtcp2_get_uint32(&pkt[1]) > 0 && ngtcp2_pkt_get_type_long(pkt[0]) == NGTCP2_PKT_INITIAL) { - break; + if (conn->server) { + /* If server discards first Initial, then drop connection + state. This is because SCID in packet might be corrupted + and the current connection state might wrongly discard + valid packet and prevent the handshake from + completing. */ + if (conn->in_pktns && conn->in_pktns->rx.max_pkt_num == -1) { + /* If this is crypto related error, then return normally + in order to send CONNECTION_CLOSE with TLS alert (e.g., + no_application_protocol). */ + if (nread == NGTCP2_ERR_CRYPTO) { + return (int)nread; + } + return NGTCP2_ERR_DROP_CONN; + } + } else if (nread == NGTCP2_ERR_CRYPTO) { + /* If client gets crypto error from TLS stack, it is + unrecoverable, therefore drop connection. */ + return (int)nread; + } + return 0; + } + + if (nread == NGTCP2_ERR_DISCARD_PKT) { + return 0; } + return (int)nread; } @@ -4913,6 +4883,8 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, const uint8_t *data; int rv; uint64_t offset; + uint32_t sdflags; + int handshake_completed = conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; for (;;) { /* Stop calling callback if application has called @@ -4931,10 +4903,16 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, offset = rx_offset; rx_offset += datalen; - rv = conn_call_recv_stream_data(conn, strm, - (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && - rx_offset == strm->rx.last_offset, - offset, data, datalen); + sdflags = NGTCP2_STREAM_DATA_FLAG_NONE; + if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && + rx_offset == strm->rx.last_offset) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; + } + if (!handshake_completed) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; + } + + rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, datalen); if (rv != 0) { return rv; } @@ -4943,6 +4921,8 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, } } +static int conn_on_crypto_timeout(ngtcp2_conn *conn, ngtcp2_pktns *pktns); + /* * conn_recv_crypto is called when CRYPTO frame |fr| is received. * |rx_offset_base| is the offset in the entire TLS handshake stream. @@ -4984,6 +4964,29 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, rx_offset = ngtcp2_strm_rx_offset(crypto); if (fr_end_offset <= rx_offset) { + if (conn->server && crypto_level == NGTCP2_CRYPTO_LEVEL_INITIAL) { + /* recovery draft: 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 + the server's CRYPTO data sent in Initial packets, or the + client's estimated RTT is too small. ... To speed up + handshake completion under these conditions, an endpoint MAY + send a packet containing unacknowledged CRYPTO data earlier + than the PTO expiry, subject to address validation limits; + ... */ + rv = conn_on_crypto_timeout(conn, conn->in_pktns); + if (rv != 0) { + return rv; + } + conn->in_pktns->rtb.probe_pkt_left = 1; + + rv = conn_on_crypto_timeout(conn, conn->hs_pktns); + if (rv != 0) { + return rv; + } + conn->hs_pktns->rtb.probe_pkt_left = 1; + } return 0; } @@ -4995,7 +4998,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, error because key is generated after consuming all data in the previous encryption level. */ if (fr->offset <= rx_offset) { - size_t ncut = rx_offset - fr->offset; + size_t ncut = (size_t)(rx_offset - fr->offset); const uint8_t *data = fr->data[0].base + ncut; size_t datalen = fr->data[0].len - ncut; uint64_t offset = rx_offset; @@ -5032,7 +5035,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level, * conn_max_data_violated returns nonzero if receiving |datalen| * violates connection flow control on local endpoint. */ -static int conn_max_data_violated(ngtcp2_conn *conn, size_t datalen) { +static int conn_max_data_violated(ngtcp2_conn *conn, uint64_t datalen) { return conn->rx.max_offset - conn->rx.offset < datalen; } @@ -5060,7 +5063,8 @@ static int conn_max_data_violated(ngtcp2_conn *conn, size_t datalen) { * STREAM frame has strictly larger end offset than it is * permitted. */ -static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { +static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr, + ngtcp2_tstamp ts) { int rv; ngtcp2_strm *strm; ngtcp2_idtr *idtr; @@ -5068,6 +5072,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { int local_stream; int bidi; size_t datalen = ngtcp2_vec_len(fr->data, fr->datacnt); + uint32_t sdflags = NGTCP2_STREAM_DATA_FLAG_NONE; local_stream = conn_local_stream(conn, fr->stream_id); bidi = bidi_stream(fr->stream_id); @@ -5139,7 +5144,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { } if (strm->rx.last_offset < fr_end_offset) { - size_t len = fr_end_offset - strm->rx.last_offset; + uint64_t len = fr_end_offset - strm->rx.last_offset; if (conn_max_data_violated(conn, len)) { return NGTCP2_ERR_FLOW_CONTROL; @@ -5179,15 +5184,6 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm, strm->app_error_code); } - - if (fr_end_offset == rx_offset) { - rv = conn_call_recv_stream_data(conn, strm, 1, rx_offset, NULL, 0); - if (rv != 0) { - return rv; - } - return ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm, - NGTCP2_NO_ERROR); - } } } else { if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && @@ -5207,8 +5203,10 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { } } + conn_update_recv_rate(conn, fr_end_offset - fr->offset, ts); + if (fr->offset <= rx_offset) { - size_t ncut = rx_offset - fr->offset; + size_t ncut = (size_t)(rx_offset - fr->offset); uint64_t offset = rx_offset; const uint8_t *data; int fin; @@ -5231,7 +5229,14 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { rx_offset == strm->rx.last_offset; if (fin || datalen) { - rv = conn_call_recv_stream_data(conn, strm, fin, offset, data, datalen); + if (fin) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; + } + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; + } + rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, + datalen); if (rv != 0) { return rv; } @@ -5323,7 +5328,13 @@ static int conn_stop_sending(ngtcp2_conn *conn, ngtcp2_strm *strm, static void handle_max_remote_streams_extension(uint64_t *punsent_max_remote_streams, size_t n) { - if (*punsent_max_remote_streams < NGTCP2_MAX_STREAMS - n) { + if ( +#if SIZE_MAX > UINT32_MAX + NGTCP2_MAX_STREAMS < n || +#endif /* SIZE_MAX > UINT32_MAX */ + *punsent_max_remote_streams > (uint64_t)(NGTCP2_MAX_STREAMS - n)) { + *punsent_max_remote_streams = NGTCP2_MAX_STREAMS; + } else { *punsent_max_remote_streams += n; } } @@ -5991,18 +6002,31 @@ static int conn_recv_retire_connection_id(ngtcp2_conn *conn, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * NGTCP2_ERR_FRAME_ENCODING: + * NGTCP2_ERR_FRAME_ENCODING * Token is empty + * NGTCP2_ERR_PROTO: + * Server received NEW_TOKEN. */ static int conn_recv_new_token(ngtcp2_conn *conn, const ngtcp2_new_token *fr) { - (void)conn; + int rv; - if (fr->tokenlen == 0) { - return NGTCP2_ERR_FRAME_ENCODING; + if (conn->server) { + return NGTCP2_ERR_PROTO; } - /* TODO Not implemented yet*/ - return 0; -} + + if (fr->token.len == 0) { + return NGTCP2_ERR_FRAME_ENCODING; + } + + if (conn->callbacks.recv_new_token) { + rv = conn->callbacks.recv_new_token(conn, &fr->token, conn->user_data); + if (rv != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + } + + return 0; +} /* * conn_select_preferred_addr asks a client application to select a @@ -6044,7 +6068,7 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) { assert(conn->pv == NULL); dcid = ngtcp2_ringbuf_get(&conn->dcid.unused, 0); - timeout = conn_compute_pto(conn); + timeout = 3 * conn_compute_pto(conn, &conn->pktns); timeout = ngtcp2_max(timeout, (ngtcp2_duration)(6ULL * NGTCP2_DEFAULT_INITIAL_RTT)); @@ -6078,7 +6102,7 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) { * NGTCP2_ERR_CALLBACK_FAILURE * User-defined callback function failed. */ -static int conn_recv_handshake_done(ngtcp2_conn *conn) { +static int conn_recv_handshake_done(ngtcp2_conn *conn, ngtcp2_tstamp ts) { int rv; if (conn->server) { @@ -6089,9 +6113,10 @@ static int conn_recv_handshake_done(ngtcp2_conn *conn) { return 0; } - conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED; + conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED | + NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; - conn_discard_handshake_state(conn); + conn_discard_handshake_state(conn, ts); if (conn->callbacks.handshake_confirmed) { rv = conn->callbacks.handshake_confirmed(conn, conn->user_data); @@ -6100,6 +6125,10 @@ static int conn_recv_handshake_done(ngtcp2_conn *conn) { } } + /* Re-arm loss detection timer after handshake has been + confirmed. */ + ngtcp2_conn_set_loss_detection_timer(conn, ts); + return 0; } @@ -6120,13 +6149,19 @@ static int conn_key_phase_changed(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) { static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { int rv; ngtcp2_tstamp confirmed_ts = conn->crypto.key_update.confirmed_ts; - ngtcp2_duration pto = conn_compute_pto(conn); + ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); ngtcp2_pktns *pktns = &conn->pktns; ngtcp2_crypto_km *rx_ckm = pktns->crypto.rx.ckm; ngtcp2_crypto_km *tx_ckm = pktns->crypto.tx.ckm; ngtcp2_crypto_km *new_rx_ckm, *new_tx_ckm; size_t secretlen, keylen, ivlen; + if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) && + (tx_ckm->use_count >= pktns->crypto.ctx.max_encryption || + rx_ckm->use_count >= pktns->crypto.ctx.max_decryption_failure)) { + ngtcp2_conn_initiate_key_update(conn, ts); + } + if ((conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) || (confirmed_ts != UINT64_MAX && confirmed_ts + pto > ts)) { return 0; @@ -6282,7 +6317,7 @@ 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"); - timeout = conn_compute_pto(conn); + timeout = 3 * conn_compute_pto(conn, &conn->pktns); timeout = ngtcp2_max(timeout, (ngtcp2_duration)(6ULL * NGTCP2_DEFAULT_INITIAL_RTT)); @@ -6396,13 +6431,13 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, switch (fr->type) { case NGTCP2_FRAME_ACK: case NGTCP2_FRAME_ACK_ECN: + if (!conn->server) { + conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; + } rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts); if (rv != 0) { return rv; } - if (!conn->server) { - conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; - } break; case NGTCP2_FRAME_PADDING: break; @@ -6438,7 +6473,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, conn_restart_timer_on_read(conn, ts); - ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); + ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); return 0; } @@ -6522,7 +6557,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, /* Quoted from spec: if subsequent packets of those types include a different Source Connection ID, they MUST be discarded. */ - if (!ngtcp2_cid_eq(&conn->odcid, &hd.scid)) { + if (!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, "packet was ignored because of mismatched SCID"); @@ -6610,48 +6645,6 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, ngtcp2_log_rx_pkt_hd(&conn->log, &hd); - if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) { - switch (hd.type) { - case NGTCP2_PKT_HANDSHAKE: - rv = conn_verify_dcid(conn, NULL, &hd); - if (rv != 0) { - if (ngtcp2_err_is_fatal(rv)) { - return rv; - } - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, - "packet was ignored because of mismatched DCID"); - return NGTCP2_ERR_DISCARD_PKT; - } - break; - case NGTCP2_PKT_0RTT: - if (!ngtcp2_cid_eq(&conn->rcid, &hd.dcid)) { - rv = conn_verify_dcid(conn, NULL, &hd); - if (rv != 0) { - if (ngtcp2_err_is_fatal(rv)) { - return rv; - } - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, - "packet was ignored because of mismatched DCID"); - return NGTCP2_ERR_DISCARD_PKT; - } - } - break; - default: - /* Unreachable */ - assert(0); - } - } else { - rv = conn_verify_dcid(conn, &new_cid_used, &hd); - if (rv != 0) { - if (ngtcp2_err_is_fatal(rv)) { - return rv; - } - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, - "packet was ignored because of mismatched DCID"); - return NGTCP2_ERR_DISCARD_PKT; - } - } - if (hd.type == NGTCP2_PKT_SHORT) { key_phase_bit_changed = conn_key_phase_changed(conn, &hd); } @@ -6705,6 +6698,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, assert(NGTCP2_ERR_TLS_DECRYPT == nwrite); + ++ckm->use_count; + if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, "could not decrypt packet payload"); @@ -6739,15 +6734,53 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, } if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM) { - if (hd.type == NGTCP2_PKT_HANDSHAKE) { + switch (hd.type) { + case NGTCP2_PKT_HANDSHAKE: + rv = conn_verify_dcid(conn, NULL, &hd); + if (rv != 0) { + if (ngtcp2_err_is_fatal(rv)) { + return rv; + } + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "packet was ignored because of mismatched DCID"); + return NGTCP2_ERR_DISCARD_PKT; + } + rv = conn_recv_delayed_handshake_pkt(conn, &hd, pktlen, payload, payloadlen, pkt_ts, ts); if (rv < 0) { return (ngtcp2_ssize)rv; } + return (ngtcp2_ssize)pktlen; + case NGTCP2_PKT_0RTT: + if (!ngtcp2_cid_eq(&conn->rcid, &hd.dcid)) { + rv = conn_verify_dcid(conn, NULL, &hd); + if (rv != 0) { + if (ngtcp2_err_is_fatal(rv)) { + return rv; + } + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "packet was ignored because of mismatched DCID"); + return NGTCP2_ERR_DISCARD_PKT; + } + } + break; + default: + /* Unreachable */ + assert(0); } } else { + rv = conn_verify_dcid(conn, &new_cid_used, &hd); + if (rv != 0) { + if (ngtcp2_err_is_fatal(rv)) { + return rv; + } + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "packet was ignored because of mismatched DCID"); + return NGTCP2_ERR_DISCARD_PKT; + } + conn->flags |= NGTCP2_CONN_FLAG_RECV_PROTECTED_PKT; } @@ -6792,6 +6825,8 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, case NGTCP2_FRAME_RETIRE_CONNECTION_ID: case NGTCP2_FRAME_PATH_CHALLENGE: case NGTCP2_FRAME_PATH_RESPONSE: + case NGTCP2_FRAME_CONNECTION_CLOSE: + case NGTCP2_FRAME_CONNECTION_CLOSE_APP: break; default: return NGTCP2_ERR_PROTO; @@ -6812,17 +6847,17 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, switch (fr->type) { case NGTCP2_FRAME_ACK: case NGTCP2_FRAME_ACK_ECN: + if (!conn->server) { + conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; + } rv = conn_recv_ack(conn, pktns, &fr->ack, pkt_ts, ts); if (rv != 0) { return rv; } - if (!conn->server) { - conn->flags |= NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED; - } non_probing_pkt = 1; break; case NGTCP2_FRAME_STREAM: - rv = conn_recv_stream(conn, &fr->stream); + rv = conn_recv_stream(conn, &fr->stream, ts); if (rv != 0) { return rv; } @@ -6908,7 +6943,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, non_probing_pkt = 1; break; case NGTCP2_FRAME_HANDSHAKE_DONE: - rv = conn_recv_handshake_done(conn); + rv = conn_recv_handshake_done(conn, ts); if (rv != 0) { return rv; } @@ -6975,7 +7010,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, conn_restart_timer_on_read(conn, ts); - ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->rcs, &conn->ccs); + ngtcp2_qlog_metrics_updated(&conn->qlog, &conn->cstat); return conn->state == NGTCP2_CS_DRAINING ? NGTCP2_ERR_DRAINING : (ngtcp2_ssize)pktlen; @@ -7122,6 +7157,8 @@ static int conn_recv_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path, const uint8_t *origpkt = pkt; size_t origpktlen = pktlen; + conn->cstat.bytes_recv += pktlen; + while (pktlen) { nread = conn_recv_pkt(conn, path, pkt, pktlen, ts, ts); if (nread < 0) { @@ -7174,79 +7211,6 @@ static int conn_is_retired_path(ngtcp2_conn *conn, const ngtcp2_path *path) { return 0; } -int ngtcp2_conn_read_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, - const uint8_t *pkt, size_t pktlen, ngtcp2_tstamp ts) { - int rv = 0; - - conn->log.last_ts = ts; - conn->qlog.last_ts = ts; - - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu", - pktlen); - - if (pktlen == 0) { - return NGTCP2_ERR_INVALID_ARGUMENT; - } - - /* client does not expect a packet from unknown path. */ - if (!conn->server && !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) && - (!conn->pv || !ngtcp2_path_eq(&conn->pv->dcid.ps.path, path)) && - !conn_is_retired_path(conn, path)) { - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, - "ignore packet from unknown path"); - return 0; - } - - switch (conn->state) { - case NGTCP2_CS_CLIENT_INITIAL: - case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: - case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: - case NGTCP2_CS_SERVER_INITIAL: - case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: - case NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED: - return ngtcp2_conn_read_handshake(conn, path, pkt, pktlen, ts); - case NGTCP2_CS_CLOSING: - return NGTCP2_ERR_CLOSING; - case NGTCP2_CS_DRAINING: - return NGTCP2_ERR_DRAINING; - case NGTCP2_CS_POST_HANDSHAKE: - rv = conn_prepare_key_update(conn, ts); - if (rv != 0) { - return rv; - } - return conn_recv_cpkt(conn, path, pkt, pktlen, ts); - default: - assert(0); - } -} - -/* - * conn_check_pkt_num_exhausted returns nonzero if packet number is - * exhausted in at least one of packet number space. - */ -static int conn_check_pkt_num_exhausted(ngtcp2_conn *conn) { - ngtcp2_pktns *in_pktns = conn->in_pktns; - ngtcp2_pktns *hs_pktns = conn->hs_pktns; - - return (in_pktns && in_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) || - (hs_pktns && hs_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) || - conn->pktns.tx.last_pkt_num == NGTCP2_MAX_PKT_NUM; -} - -/* - * conn_server_hs_tx_left returns the maximum number of bytes that - * server is allowed to send during handshake. - */ -static size_t conn_server_hs_tx_left(ngtcp2_conn *conn) { - if (conn->flags & NGTCP2_CONN_FLAG_SADDR_VERIFIED) { - return SIZE_MAX; - } - /* From QUIC spec: Prior to validating the client address, servers - MUST NOT send more than three times as many bytes as the number - of bytes they have received. */ - return conn->hs_recved * 3 - conn->hs_sent; -} - /* * conn_enqueue_handshake_done enqueues HANDSHAKE_DONE frame for * transmission. @@ -7270,7 +7234,17 @@ static int conn_enqueue_handshake_done(ngtcp2_conn *conn) { return 0; } -int ngtcp2_conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, +/** + * @function + * + * `conn_read_handshake` performs QUIC cryptographic handshake by + * reading given data. |pkt| points to the buffer to read and + * |pktlen| is the length of the buffer. |path| is the network path. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: (TBD). + */ +static int conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, const uint8_t *pkt, size_t pktlen, ngtcp2_tstamp ts) { int rv; @@ -7297,8 +7271,6 @@ int ngtcp2_conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, if (rv != 0) { return rv; } - - conn_discard_initial_state(conn); } return 0; @@ -7358,10 +7330,32 @@ int ngtcp2_conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, } if (conn->hs_pktns->rx.max_pkt_num != -1) { - conn_discard_initial_state(conn); + conn_discard_initial_state(conn, ts); } if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { + /* 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 + ack-eliciting Initial or Handshake packets, it should resend + it if timer fired but timer is not armed in this case. So + instead of resending Initial/Handshake packets, if server has + 1RTT data to send, it might send them and then might hit + amplification limit again until it hits stream data limit. + Initial/Handshake data is not resent. In order to avoid this + situation, try to arm loss detection and check the expiry + here so that on next write call, we can resend + Initial/Handshake first. */ + if (!conn->cstat.loss_detection_timer) { + ngtcp2_conn_set_loss_detection_timer(conn, ts); + if (ngtcp2_conn_loss_detection_expiry(conn) <= ts) { + rv = ngtcp2_conn_on_loss_detection_timer(conn, ts); + if (rv != 0) { + return rv; + } + } + } + return 0; } @@ -7369,8 +7363,6 @@ int ngtcp2_conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM; } - conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED; - rv = conn_handshake_completed(conn); if (rv != 0) { return rv; @@ -7387,13 +7379,17 @@ int ngtcp2_conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, return rv; } - conn_discard_handshake_state(conn); + conn_discard_handshake_state(conn, ts); rv = conn_enqueue_handshake_done(conn); if (rv != 0) { return rv; } + /* Re-arm loss detection timer here after handshake has been + confirmed. */ + ngtcp2_conn_set_loss_detection_timer(conn, ts); + return 0; case NGTCP2_CS_CLOSING: return NGTCP2_ERR_CLOSING; @@ -7404,6 +7400,81 @@ int ngtcp2_conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, } } +int ngtcp2_conn_read_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, + const uint8_t *pkt, size_t pktlen, ngtcp2_tstamp ts) { + int rv = 0; + + conn->log.last_ts = ts; + conn->qlog.last_ts = ts; + + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "recv packet len=%zu", + pktlen); + + if (pktlen == 0) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } + + /* client does not expect a packet from unknown path. */ + if (!conn->server && !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) && + (!conn->pv || !ngtcp2_path_eq(&conn->pv->dcid.ps.path, path)) && + !conn_is_retired_path(conn, path)) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, + "ignore packet from unknown path"); + return 0; + } + + switch (conn->state) { + case NGTCP2_CS_CLIENT_INITIAL: + case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: + case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: + case NGTCP2_CS_SERVER_INITIAL: + case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: + case NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED: + return conn_read_handshake(conn, path, pkt, pktlen, ts); + case NGTCP2_CS_CLOSING: + return NGTCP2_ERR_CLOSING; + case NGTCP2_CS_DRAINING: + return NGTCP2_ERR_DRAINING; + case NGTCP2_CS_POST_HANDSHAKE: + rv = conn_prepare_key_update(conn, ts); + if (rv != 0) { + return rv; + } + return conn_recv_cpkt(conn, path, pkt, pktlen, ts); + default: + assert(0); + } +} + +/* + * conn_check_pkt_num_exhausted returns nonzero if packet number is + * exhausted in at least one of packet number space. + */ +static int conn_check_pkt_num_exhausted(ngtcp2_conn *conn) { + ngtcp2_pktns *in_pktns = conn->in_pktns; + ngtcp2_pktns *hs_pktns = conn->hs_pktns; + + return (in_pktns && in_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) || + (hs_pktns && hs_pktns->tx.last_pkt_num == NGTCP2_MAX_PKT_NUM) || + conn->pktns.tx.last_pkt_num == NGTCP2_MAX_PKT_NUM; +} + +/* + * conn_server_hs_tx_left returns the maximum number of bytes that + * server is allowed to send during handshake. + */ +static size_t conn_server_hs_tx_left(ngtcp2_conn *conn) { + if (conn->flags & NGTCP2_CONN_FLAG_SADDR_VERIFIED) { + return SIZE_MAX; + } + /* From QUIC spec: Prior to validating the client address, servers + MUST NOT send more than three times as many bytes as the number + of bytes they have received. */ + assert(conn->cstat.bytes_recv * 3 >= conn->cstat.bytes_sent); + + return conn->cstat.bytes_recv * 3 - conn->cstat.bytes_sent; +} + /* * conn_retransmit_retry_early retransmits 0RTT packet after Retry is * received from server. @@ -7415,6 +7486,16 @@ static ngtcp2_ssize conn_retransmit_retry_early(ngtcp2_conn *conn, NULL, 0, NGTCP2_WRITE_PKT_FLAG_NONE, ts); } +/* + * conn_handshake_probe_left returns nonzero if there are probe + * packets to be sent for Initial or Handshake packet number space + * left. + */ +static int conn_handshake_probe_left(ngtcp2_conn *conn) { + return (conn->in_pktns && conn->in_pktns->rtb.probe_pkt_left) || + conn->hs_pktns->rtb.probe_pkt_left; +} + /* * conn_write_handshake writes QUIC handshake packets to the buffer * pointed by |dest| of length |destlen|. |early_datalen| specifies @@ -7443,17 +7524,13 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, ngtcp2_tstamp ts) { int rv; ngtcp2_ssize res = 0, nwrite = 0, early_spktlen = 0; - uint64_t cwnd; size_t origlen = destlen; size_t server_hs_tx_left; - ngtcp2_rcvry_stat *rcs = &conn->rcs; + ngtcp2_conn_stat *cstat = &conn->cstat; size_t pending_early_datalen; ngtcp2_dcid *dcid; ngtcp2_preferred_addr *paddr; - cwnd = conn_cwnd_left(conn); - destlen = ngtcp2_min(destlen, cwnd); - switch (conn->state) { case NGTCP2_CS_CLIENT_INITIAL: pending_early_datalen = conn_retry_early_payloadlen(conn); @@ -7487,32 +7564,32 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, conn->state = NGTCP2_CS_CLIENT_WAIT_HANDSHAKE; - return nwrite + early_spktlen; + res = nwrite + early_spktlen; + cstat->bytes_sent += (size_t)res; + + return res; case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: - if ((conn->in_pktns && conn->in_pktns->rtb.probe_pkt_left) || - conn->hs_pktns->rtb.probe_pkt_left) { - nwrite = conn_write_handshake_pkts(conn, dest, origlen, 0, ts); - if (nwrite) { - return nwrite; + if (!conn_handshake_probe_left(conn) && conn_cwnd_is_zero(conn)) { + destlen = 0; + } else { + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { + pending_early_datalen = conn_retry_early_payloadlen(conn); + if (pending_early_datalen) { + early_datalen = pending_early_datalen; + } } - } - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED)) { - pending_early_datalen = conn_retry_early_payloadlen(conn); - if (pending_early_datalen) { - early_datalen = pending_early_datalen; + nwrite = + conn_write_handshake_pkts(conn, dest, destlen, early_datalen, ts); + if (nwrite < 0) { + return nwrite; } - } - nwrite = conn_write_handshake_pkts(conn, dest, destlen, early_datalen, ts); - if (nwrite < 0) { - return nwrite; + res += nwrite; + dest += nwrite; + destlen -= (size_t)nwrite; } - res += nwrite; - dest += nwrite; - destlen -= (size_t)nwrite; - if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { nwrite = conn_retransmit_retry_early(conn, dest, destlen, ts); if (nwrite < 0) { @@ -7528,6 +7605,9 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, } res = nwrite; } + + cstat->bytes_sent += (size_t)res; + return res; } @@ -7576,16 +7656,19 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, } } + cstat->bytes_sent += (size_t)res; + return res; case NGTCP2_CS_SERVER_INITIAL: - nwrite = conn_write_server_handshake(conn, dest, destlen, ts); + nwrite = conn_write_handshake_pkts(conn, dest, destlen, + /* early_datalen = */ 0, ts); if (nwrite < 0) { return nwrite; } if (nwrite) { conn->state = NGTCP2_CS_SERVER_WAIT_HANDSHAKE; - conn->hs_sent += (size_t)nwrite; + cstat->bytes_sent += (size_t)nwrite; } return nwrite; @@ -7593,56 +7676,39 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { server_hs_tx_left = conn_server_hs_tx_left(conn); if (server_hs_tx_left == 0) { - if (rcs->loss_detection_timer) { + if (cstat->loss_detection_timer) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "loss detection timer canceled"); - rcs->loss_detection_timer = 0; + cstat->loss_detection_timer = 0; + cstat->pto_count = 0; } return 0; } - destlen = ngtcp2_min(destlen, server_hs_tx_left); - origlen = ngtcp2_min(origlen, server_hs_tx_left); - - if ((conn->in_pktns && conn->in_pktns->rtb.probe_pkt_left) || - conn->hs_pktns->rtb.probe_pkt_left) { - nwrite = conn_write_handshake_pkts(conn, dest, origlen, 0, ts); + if (conn_handshake_probe_left(conn) || !conn_cwnd_is_zero(conn)) { + nwrite = conn_write_handshake_pkts(conn, dest, destlen, + /* early_datalen = */ 0, ts); if (nwrite < 0) { return nwrite; } - /* Coalesce packets, because server might send Initial as - probe, and Handshake as non-probe. */ res += nwrite; dest += nwrite; - if (destlen <= (size_t)nwrite) { - goto server_wait_handshake_done; - } destlen -= (size_t)nwrite; - origlen -= (size_t)nwrite; - } - - nwrite = conn_write_server_handshake(conn, dest, destlen, ts); - if (nwrite < 0) { - return nwrite; } - /* TODO Write 1RTT ACK packet if we have received 0RTT packet */ - - res += nwrite; - dest += nwrite; - destlen -= (size_t)nwrite; - origlen -= (size_t)nwrite; + if (res == 0) { + nwrite = conn_write_handshake_ack_pkts(conn, dest, origlen, ts); + if (nwrite < 0) { + return nwrite; + } - nwrite = conn_write_handshake_ack_pkts(conn, dest, origlen, ts); - if (nwrite < 0) { - return nwrite; + res += nwrite; + dest += nwrite; + origlen -= (size_t)nwrite; } - res += nwrite; - - server_wait_handshake_done: - conn->hs_sent += (size_t)res; + cstat->bytes_sent += (size_t)res; return res; } @@ -7656,19 +7722,37 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, } } -ngtcp2_ssize ngtcp2_conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, - size_t destlen, ngtcp2_tstamp ts) { - return conn_write_handshake(conn, dest, destlen, 0, ts); -} - -ngtcp2_ssize ngtcp2_conn_client_write_handshake( - ngtcp2_conn *conn, uint8_t *dest, size_t destlen, ngtcp2_ssize *pdatalen, - uint32_t flags, int64_t stream_id, int fin, const ngtcp2_vec *datav, - size_t datavcnt, ngtcp2_tstamp ts) { +/** + * @function + * + * `conn_client_write_handshake` writes client side handshake data and + * 0RTT packet. + * + * |stream_id|, |fin|, |datav|, and |datavcnt| are stream identifier + * to which 0-RTT data is sent, whether it is a last data chunk in + * this stream, a vector of 0-RTT data, and its number of elements + * respectively. If there is no 0RTT data to send, pass negative + * integer to |stream_id|. The amount of 0RTT data sent is assigned + * to |*pdatalen|. If no data is sent, -1 is assigned. Note that 0 + * length STREAM frame is allowed in QUIC, so 0 might be assigned to + * |*pdatalen|. + * + * This function returns 0 if it cannot write any frame because buffer + * is too small, or packet is congestion limited. Application should + * keep reading and wait for congestion window to grow. + * + * This function returns the number of bytes written to the buffer + * pointed by |dest| if it succeeds, or one of the following negative + * error codes: (TBD). + */ +static ngtcp2_ssize +conn_client_write_handshake(ngtcp2_conn *conn, uint8_t *dest, size_t destlen, + ngtcp2_ssize *pdatalen, uint32_t flags, + int64_t stream_id, int fin, const ngtcp2_vec *datav, + size_t datavcnt, ngtcp2_tstamp ts) { ngtcp2_strm *strm = NULL; int send_stream = 0; ngtcp2_ssize spktlen, early_spktlen; - uint64_t cwnd; int was_client_initial; size_t datalen = ngtcp2_vec_len(datav, datavcnt); size_t early_datalen = 0; @@ -7696,10 +7780,11 @@ ngtcp2_ssize ngtcp2_conn_client_write_handshake( (datalen > 0 && (strm->tx.max_offset - strm->tx.offset) && (conn->tx.max_offset - conn->tx.offset))); if (send_stream) { + early_datalen = (size_t)ngtcp2_min((uint64_t)datalen, + strm->tx.max_offset - strm->tx.offset); early_datalen = - ngtcp2_min(datalen, strm->tx.max_offset - strm->tx.offset); - early_datalen = - ngtcp2_min(early_datalen, conn->tx.max_offset - conn->tx.offset) + + (size_t)ngtcp2_min((uint64_t)early_datalen, + conn->tx.max_offset - conn->tx.offset) + NGTCP2_STREAM_OVERHEAD; if (flags & NGTCP2_WRITE_STREAM_FLAG_MORE) { @@ -7736,11 +7821,12 @@ ngtcp2_ssize ngtcp2_conn_client_write_handshake( wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING; } - cwnd = conn_cwnd_left(conn); - dest += spktlen; destlen -= (size_t)spktlen; - destlen = ngtcp2_min(destlen, cwnd); + + if (conn_cwnd_is_zero(conn)) { + return spktlen; + } early_spktlen = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_0RTT, strm, fin, datav, datavcnt, wflags, ts); @@ -7757,11 +7843,16 @@ ngtcp2_ssize ngtcp2_conn_client_write_handshake( return early_spktlen; } + conn->cstat.bytes_sent += (size_t)early_spktlen; + return spktlen + early_spktlen; } void ngtcp2_conn_handshake_completed(ngtcp2_conn *conn) { conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED; + if (conn->server) { + conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED; + } } int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn) { @@ -7807,7 +7898,7 @@ int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t pktlen) { if (pktlen < NGTCP2_MIN_INITIAL_PKTLEN) { return -1; } - if (p->tokenlen == 0 && p->dcid.datalen < 8) { + if (p->token.len == 0 && p->dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN) { return -1; } break; @@ -7885,37 +7976,44 @@ int ngtcp2_conn_install_initial_key(ngtcp2_conn *conn, const uint8_t *rx_key, return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, tx_hp_key, keylen, conn->mem); } -int ngtcp2_conn_install_handshake_key( - ngtcp2_conn *conn, const uint8_t *rx_key, const uint8_t *rx_iv, - const uint8_t *rx_hp_key, const uint8_t *tx_key, const uint8_t *tx_iv, - const uint8_t *tx_hp_key, size_t keylen, size_t ivlen) { +int ngtcp2_conn_install_rx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, + const uint8_t *iv, + const uint8_t *hp_key, size_t keylen, + size_t ivlen) { ngtcp2_pktns *pktns = conn->hs_pktns; int rv; assert(pktns); assert(!pktns->crypto.rx.hp_key); assert(!pktns->crypto.rx.ckm); - assert(!pktns->crypto.tx.hp_key); - assert(!pktns->crypto.tx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, rx_key, keylen, - rx_iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, key, keylen, iv, + ivlen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, rx_hp_key, keylen, conn->mem); - if (rv != 0) { - return rv; - } + return ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem); +} - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, tx_key, keylen, - tx_iv, ivlen, conn->mem); +int ngtcp2_conn_install_tx_handshake_key(ngtcp2_conn *conn, const uint8_t *key, + const uint8_t *iv, + const uint8_t *hp_key, size_t keylen, + size_t ivlen) { + ngtcp2_pktns *pktns = conn->hs_pktns; + int rv; + + assert(pktns); + assert(!pktns->crypto.tx.hp_key); + assert(!pktns->crypto.tx.ckm); + + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, key, keylen, iv, + ivlen, conn->mem); if (rv != 0) { return rv; } - return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, tx_hp_key, keylen, conn->mem); + return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem); } int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, const uint8_t *key, @@ -7935,38 +8033,47 @@ int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, const uint8_t *key, return ngtcp2_vec_new(&conn->early.hp_key, hp_key, keylen, conn->mem); } -int ngtcp2_conn_install_key(ngtcp2_conn *conn, const uint8_t *rx_secret, - const uint8_t *tx_secret, const uint8_t *rx_key, - const uint8_t *rx_iv, const uint8_t *rx_hp_key, - const uint8_t *tx_key, const uint8_t *tx_iv, - const uint8_t *tx_hp_key, size_t secretlen, - size_t keylen, size_t ivlen) { +int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, + const uint8_t *key, const uint8_t *iv, + const uint8_t *hp_key, size_t secretlen, + size_t keylen, size_t ivlen) { ngtcp2_pktns *pktns = &conn->pktns; int rv; assert(!pktns->crypto.rx.hp_key); assert(!pktns->crypto.rx.ckm); - assert(!pktns->crypto.tx.hp_key); - assert(!pktns->crypto.tx.ckm); - rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, rx_secret, secretlen, rx_key, - keylen, rx_iv, ivlen, conn->mem); + rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, key, + keylen, iv, ivlen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, rx_hp_key, keylen, conn->mem); + rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, tx_secret, secretlen, tx_key, - keylen, tx_iv, ivlen, conn->mem); + return 0; +} + +int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, + const uint8_t *key, const uint8_t *iv, + const uint8_t *hp_key, size_t secretlen, + size_t keylen, size_t ivlen) { + ngtcp2_pktns *pktns = &conn->pktns; + int rv; + + assert(!pktns->crypto.tx.hp_key); + assert(!pktns->crypto.tx.ckm); + + rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, key, + keylen, iv, ivlen, conn->mem); if (rv != 0) { return rv; } - rv = ngtcp2_vec_new(&pktns->crypto.tx.hp_key, tx_hp_key, keylen, conn->mem); + rv = ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem); if (rv != 0) { return rv; } @@ -7980,7 +8087,7 @@ int ngtcp2_conn_install_key(ngtcp2_conn *conn, const uint8_t *rx_secret, int ngtcp2_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); + ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); assert(conn->state == NGTCP2_CS_POST_HANDSHAKE); @@ -7998,15 +8105,15 @@ int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(ngtcp2_conn *conn) { - if (conn->rcs.loss_detection_timer) { - return conn->rcs.loss_detection_timer; + if (conn->cstat.loss_detection_timer) { + return conn->cstat.loss_detection_timer; } return UINT64_MAX; } ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn) { ngtcp2_tstamp res = UINT64_MAX; - ngtcp2_duration pto = conn_compute_pto(conn); + ngtcp2_duration pto = conn_compute_pto(conn, &conn->pktns); ngtcp2_scid *scid; ngtcp2_dcid *dcid; @@ -8088,20 +8195,33 @@ void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn, * This function returns 0 if it succeeds, or one of the following * negative error codes: * + * NGTCP2_ERR_PROTO + * Validation against either of original_dcid and retry_scid is + * failed. * NGTCP2_ERR_TRANSPORT_PARAM - * Transport parameters are invalid. + * params contains preferred address but server chose zero-length + * connection ID. */ static int conn_client_validate_transport_params(ngtcp2_conn *conn, const ngtcp2_transport_params *params) { + if (!ngtcp2_cid_eq(&conn->rcid, ¶ms->original_dcid)) { + return NGTCP2_ERR_TRANSPORT_PARAM; + } + if (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) { - if (!params->original_connection_id_present) { + if (!params->retry_scid_present) { return NGTCP2_ERR_TRANSPORT_PARAM; } - if (!ngtcp2_cid_eq(&conn->rcid, ¶ms->original_connection_id)) { + if (!ngtcp2_cid_eq(&conn->retry_scid, ¶ms->retry_scid)) { return NGTCP2_ERR_TRANSPORT_PARAM; } - } else if (params->original_connection_id_present) { + } else if (params->retry_scid_present) { + return NGTCP2_ERR_TRANSPORT_PARAM; + } + + if (params->preferred_address_present && + conn->dcid.current.cid.datalen == 0) { return NGTCP2_ERR_TRANSPORT_PARAM; } @@ -8121,6 +8241,13 @@ int ngtcp2_conn_set_remote_transport_params( return NGTCP2_ERR_TRANSPORT_PARAM; } + /* We assume that conn->dcid.current.cid is still the initial one. + This requires that transport parameter must be fed into + ngtcp2_conn as early as possible. */ + if (!ngtcp2_cid_eq(&conn->dcid.current.cid, ¶ms->initial_scid)) { + return NGTCP2_ERR_TRANSPORT_PARAM; + } + if (!conn->server) { rv = conn_client_validate_transport_params(conn, params); if (rv != 0) { @@ -8134,10 +8261,10 @@ int ngtcp2_conn_set_remote_transport_params( : NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, params); - ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, + ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server, /* local = */ 0); - if (conn->pktns.crypto.rx.ckm) { + if (conn->pktns.crypto.tx.ckm) { conn->remote.transport_params = *params; conn_sync_stream_id_limit(conn); conn->tx.max_offset = conn->remote.transport_params.initial_max_data; @@ -8180,13 +8307,21 @@ void ngtcp2_conn_set_early_remote_transport_params( conn->tx.max_offset = p->initial_max_data; - ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, p, + ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, p, conn->server, /* local = */ 0); } void ngtcp2_conn_get_local_transport_params(ngtcp2_conn *conn, ngtcp2_transport_params *params) { *params = conn->local.settings.transport_params; + + /* If params->retry_scid_present is set by application then it + should also specify original_dcid because the destination + connection ID from client after Retry is not what we want + here. */ + if (conn->server && !params->retry_scid_present) { + params->original_dcid = conn->rcid; + } } int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, @@ -8194,8 +8329,7 @@ int ngtcp2_conn_open_bidi_stream(ngtcp2_conn *conn, int64_t *pstream_id, int rv; ngtcp2_strm *strm; - if (ngtcp2_ord_stream_id(conn->local.bidi.next_stream_id) > - conn->local.bidi.max_streams) { + if (ngtcp2_conn_get_streams_bidi_left(conn) == 0) { return NGTCP2_ERR_STREAM_ID_BLOCKED; } @@ -8222,8 +8356,7 @@ int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, int64_t *pstream_id, int rv; ngtcp2_strm *strm; - if (ngtcp2_ord_stream_id(conn->local.uni.next_stream_id) > - conn->local.uni.max_streams) { + if (ngtcp2_conn_get_streams_uni_left(conn) == 0) { return NGTCP2_ERR_STREAM_ID_BLOCKED; } @@ -8260,33 +8393,33 @@ ngtcp2_strm *ngtcp2_conn_find_stream(ngtcp2_conn *conn, int64_t stream_id) { ngtcp2_ssize ngtcp2_conn_write_stream(ngtcp2_conn *conn, ngtcp2_path *path, uint8_t *dest, size_t destlen, ngtcp2_ssize *pdatalen, uint32_t flags, - int64_t stream_id, int fin, - const uint8_t *data, size_t datalen, - ngtcp2_tstamp ts) { + int64_t stream_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_stream(conn, path, dest, destlen, pdatalen, flags, - stream_id, fin, &datav, 1, ts); + stream_id, &datav, 1, ts); } ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, uint8_t *dest, size_t destlen, ngtcp2_ssize *pdatalen, uint32_t flags, - int64_t stream_id, int fin, + int64_t stream_id, const ngtcp2_vec *datav, size_t datavcnt, ngtcp2_tstamp ts) { ngtcp2_strm *strm = NULL; ngtcp2_ssize nwrite; - uint64_t cwnd; ngtcp2_pktns *pktns = &conn->pktns; size_t origlen = destlen; int rv; uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE; int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0; ngtcp2_ssize res = 0; + size_t server_hs_tx_left; + int fin = flags & NGTCP2_WRITE_STREAM_FLAG_FIN; conn->log.last_ts = ts; conn->qlog.last_ts = ts; @@ -8303,9 +8436,8 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, case NGTCP2_CS_CLIENT_INITIAL: case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: case NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED: - nwrite = - ngtcp2_conn_client_write_handshake(conn, dest, destlen, pdatalen, flags, - stream_id, fin, datav, datavcnt, ts); + nwrite = conn_client_write_handshake(conn, dest, destlen, pdatalen, flags, + stream_id, fin, datav, datavcnt, ts); if (nwrite < 0 || conn->state != NGTCP2_CS_POST_HANDSHAKE) { return nwrite; } @@ -8318,14 +8450,27 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: case NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED: if (!ppe_pending) { - nwrite = ngtcp2_conn_write_handshake(conn, dest, destlen, ts); - if (nwrite) { + server_hs_tx_left = conn_server_hs_tx_left(conn); + destlen = ngtcp2_min(destlen, server_hs_tx_left); + + nwrite = conn_write_handshake(conn, dest, destlen, 0, ts); + if (nwrite < 0) { return nwrite; } + + if (conn->flags & NGTCP2_CONN_FLAG_SADDR_VERIFIED) { + destlen = origlen; + } else { + origlen = destlen; + } + + res = nwrite; + dest += nwrite; + destlen -= (size_t)nwrite; } if (conn->state != NGTCP2_CS_POST_HANDSHAKE && conn->pktns.crypto.tx.ckm == NULL) { - return 0; + return res; } break; case NGTCP2_CS_POST_HANDSHAKE: @@ -8344,13 +8489,6 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, return NGTCP2_ERR_PKT_NUM_EXHAUSTED; } - if (conn->state == NGTCP2_CS_POST_HANDSHAKE) { - rv = conn_prepare_key_update(conn, ts); - if (rv != 0) { - return rv; - } - } - rv = conn_remove_retired_connection_id(conn, ts); if (rv != 0) { return rv; @@ -8371,9 +8509,6 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, } } - cwnd = conn_cwnd_left(conn); - destlen = ngtcp2_min(destlen, cwnd); - if (ppe_pending) { res = conn->pkt.hs_spktlen; conn->pkt.hs_spktlen = 0; @@ -8382,40 +8517,49 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT, strm, fin, datav, datavcnt, wflags, ts); goto fin; - } + } else { + if (conn->state == NGTCP2_CS_POST_HANDSHAKE) { + rv = conn_prepare_key_update(conn, ts); + if (rv != 0) { + return rv; + } + } - if (conn->pv) { - nwrite = conn_write_path_challenge(conn, path, dest, origlen, ts); - if (nwrite) { - goto fin; + if (!conn->pktns.rtb.probe_pkt_left && conn_cwnd_is_zero(conn)) { + destlen = 0; + } else if (conn->pv) { + nwrite = conn_write_path_challenge(conn, path, dest, destlen, ts); + if (nwrite) { + goto fin; + } } } if (res == 0) { if (conn_handshake_remnants_left(conn)) { - if ((conn->in_pktns && conn->in_pktns->rtb.probe_pkt_left) || - conn->hs_pktns->rtb.probe_pkt_left) { - nwrite = conn_write_handshake_pkts(conn, dest, origlen, 0, ts); - if (nwrite) { - return nwrite; - } - } else { - nwrite = conn_write_handshake_pkts(conn, dest, destlen, 0, ts); - if (nwrite < 0) { - return nwrite; - } - if (nwrite > 0) { - res = nwrite; - dest += nwrite; - destlen -= (size_t)nwrite; - } + if (conn_handshake_probe_left(conn)) { + destlen = origlen; + } + nwrite = conn_write_handshake_pkts(conn, dest, destlen, 0, ts); + if (nwrite < 0) { + return nwrite; + } + if (nwrite > 0) { + res = nwrite; + dest += nwrite; + destlen -= (size_t)nwrite; } } } if (conn->pktns.rtb.probe_pkt_left) { - nwrite = conn_write_probe_pkt(conn, dest, origlen, pdatalen, strm, fin, - datav, datavcnt, ts); + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, + "transmit probe pkt left=%zu", + conn->pktns.rtb.probe_pkt_left); + + nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT, + strm, fin, datav, datavcnt, wflags, ts); + goto fin; } @@ -8427,13 +8571,14 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path, } if (res == 0) { - return conn_write_ack_pkt(conn, dest, origlen, NGTCP2_PKT_SHORT, ts); + nwrite = conn_write_ack_pkt(conn, dest, origlen, NGTCP2_PKT_SHORT, ts); } fin: conn->pkt.hs_spktlen = 0; if (nwrite >= 0) { + conn->cstat.bytes_sent += (size_t)nwrite; return res + nwrite; } /* NGTCP2_CONN_FLAG_PPE_PENDING is set in conn_write_pkt above. @@ -8455,8 +8600,6 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn, ngtcp2_ssize res = 0, nwrite; ngtcp2_frame fr; uint8_t pkt_type; - int bundle = 0; - uint8_t bundle_pkt_type; conn->log.last_ts = ts; conn->qlog.last_ts = ts; @@ -8466,6 +8609,7 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn, } switch (conn->state) { + case NGTCP2_CS_CLIENT_INITIAL: case NGTCP2_CS_CLOSING: case NGTCP2_CS_DRAINING: return NGTCP2_ERR_INVALID_STATE; @@ -8495,29 +8639,39 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn, return NGTCP2_ERR_INVALID_STATE; } - if (conn->server && pkt_type == NGTCP2_PKT_HANDSHAKE && in_pktns) { - bundle = 1; - bundle_pkt_type = NGTCP2_PKT_INITIAL; - } else if (pkt_type == NGTCP2_PKT_SHORT && hs_pktns && - !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)) { - bundle = 1; - bundle_pkt_type = NGTCP2_PKT_HANDSHAKE; - } + if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) && + pkt_type != NGTCP2_PKT_INITIAL) { + if (in_pktns && conn->server) { + nwrite = ngtcp2_conn_write_single_frame_pkt( + conn, dest, destlen, NGTCP2_PKT_INITIAL, &conn->dcid.current.cid, &fr, + NGTCP2_RTB_FLAG_NONE, ts); + if (nwrite < 0) { + return nwrite; + } - if (bundle) { - nwrite = ngtcp2_conn_write_single_frame_pkt( - conn, dest, destlen, bundle_pkt_type, &conn->dcid.current.cid, &fr, - NGTCP2_RTB_FLAG_NONE, ts); - if (nwrite < 0) { - return nwrite; + dest += nwrite; + destlen -= (size_t)nwrite; + res += nwrite; } - res += nwrite; + if (pkt_type != NGTCP2_PKT_HANDSHAKE && hs_pktns && + hs_pktns->crypto.tx.ckm) { + nwrite = ngtcp2_conn_write_single_frame_pkt( + conn, dest, destlen, NGTCP2_PKT_HANDSHAKE, &conn->dcid.current.cid, + &fr, NGTCP2_RTB_FLAG_NONE, ts); + if (nwrite < 0) { + return nwrite; + } + + dest += nwrite; + destlen -= (size_t)nwrite; + res += nwrite; + } } - nwrite = ngtcp2_conn_write_single_frame_pkt( - conn, dest + res, destlen - (size_t)res, pkt_type, - &conn->dcid.current.cid, &fr, NGTCP2_RTB_FLAG_NONE, ts); + nwrite = ngtcp2_conn_write_single_frame_pkt(conn, dest, destlen, pkt_type, + &conn->dcid.current.cid, &fr, + NGTCP2_RTB_FLAG_NONE, ts); if (nwrite < 0) { return nwrite; @@ -8754,10 +8908,11 @@ int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, int64_t stream_id, * Out of memory. */ static int conn_extend_max_stream_offset(ngtcp2_conn *conn, ngtcp2_strm *strm, - size_t datalen) { + uint64_t datalen) { ngtcp2_strm *top; - if (strm->rx.unsent_max_offset > NGTCP2_MAX_VARINT - datalen) { + if (datalen > NGTCP2_MAX_VARINT || + strm->rx.unsent_max_offset > NGTCP2_MAX_VARINT - datalen) { strm->rx.unsent_max_offset = NGTCP2_MAX_VARINT; } else { strm->rx.unsent_max_offset += datalen; @@ -8779,7 +8934,7 @@ static int conn_extend_max_stream_offset(ngtcp2_conn *conn, ngtcp2_strm *strm, } int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, - size_t datalen) { + uint64_t datalen) { ngtcp2_strm *strm; strm = ngtcp2_conn_find_stream(conn, stream_id); @@ -8790,8 +8945,8 @@ int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, return conn_extend_max_stream_offset(conn, strm, datalen); } -void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, size_t datalen) { - if (NGTCP2_MAX_VARINT < (uint64_t)datalen || +void ngtcp2_conn_extend_max_offset(ngtcp2_conn *conn, uint64_t datalen) { + if (NGTCP2_MAX_VARINT < datalen || conn->rx.unsent_max_offset > NGTCP2_MAX_VARINT - datalen) { conn->rx.unsent_max_offset = NGTCP2_MAX_VARINT; return; @@ -8808,10 +8963,6 @@ void ngtcp2_conn_extend_max_streams_uni(ngtcp2_conn *conn, size_t n) { handle_max_remote_streams_extension(&conn->remote.uni.unsent_max_streams, n); } -size_t ngtcp2_conn_get_bytes_in_flight(ngtcp2_conn *conn) { - return conn->ccs.bytes_in_flight; -} - const ngtcp2_cid *ngtcp2_conn_get_dcid(ngtcp2_conn *conn) { return &conn->dcid.current.cid; } @@ -8828,7 +8979,7 @@ int ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn) { conn->flags |= NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED; - ngtcp2_rtb_remove_all(rtb, &frc); + ngtcp2_rtb_remove_all(rtb, &frc, &conn->cstat); rv = conn_resched_frames(conn, pktns, &frc); if (rv != 0) { @@ -8842,167 +8993,147 @@ int ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn) { void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, ngtcp2_duration ack_delay) { - ngtcp2_rcvry_stat *rcs = &conn->rcs; + ngtcp2_conn_stat *cstat = &conn->cstat; - rcs->latest_rtt = rtt; - - if (rcs->smoothed_rtt == 0) { - rcs->min_rtt = rtt; - rcs->smoothed_rtt = rtt; - rcs->rttvar = rtt / 2; - return; - } + rtt = ngtcp2_max(rtt, NGTCP2_GRANULARITY); - rcs->min_rtt = ngtcp2_min(rcs->min_rtt, rtt); - if (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) { - ack_delay = - ngtcp2_min(ack_delay, conn->remote.transport_params.max_ack_delay); + if (cstat->min_rtt == UINT64_MAX) { + cstat->latest_rtt = rtt; + cstat->min_rtt = rtt; + cstat->smoothed_rtt = rtt; + cstat->rttvar = rtt / 2; } else { - ack_delay = ngtcp2_min(ack_delay, NGTCP2_DEFAULT_MAX_ACK_DELAY); - } - if (rtt > rcs->min_rtt + ack_delay) { - rtt -= ack_delay; - } + cstat->min_rtt = ngtcp2_min(cstat->min_rtt, rtt); + if (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) { + ack_delay = + ngtcp2_min(ack_delay, conn->remote.transport_params.max_ack_delay); + } else { + ack_delay = ngtcp2_min(ack_delay, NGTCP2_DEFAULT_MAX_ACK_DELAY); + } + if (rtt > cstat->min_rtt + ack_delay) { + rtt -= ack_delay; + } - rcs->rttvar = - (rcs->rttvar * 3 + (rcs->smoothed_rtt < rtt ? rtt - rcs->smoothed_rtt - : rcs->smoothed_rtt - rtt)) / - 4; - rcs->smoothed_rtt = (rcs->smoothed_rtt * 7 + rtt) / 8; + cstat->latest_rtt = rtt; + + cstat->rttvar = (cstat->rttvar * 3 + (cstat->smoothed_rtt < rtt + ? rtt - cstat->smoothed_rtt + : cstat->smoothed_rtt - rtt)) / + 4; + cstat->smoothed_rtt = (cstat->smoothed_rtt * 7 + rtt) / 8; + } ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " smoothed_rtt=%" PRIu64 " rttvar=%" PRIu64 " ack_delay=%" PRIu64, - (uint64_t)(rcs->latest_rtt / NGTCP2_MILLISECONDS), - (uint64_t)(rcs->min_rtt / NGTCP2_MILLISECONDS), - rcs->smoothed_rtt / NGTCP2_MILLISECONDS, - rcs->rttvar / NGTCP2_MILLISECONDS, + (uint64_t)(cstat->latest_rtt / NGTCP2_MILLISECONDS), + (uint64_t)(cstat->min_rtt / NGTCP2_MILLISECONDS), + cstat->smoothed_rtt / NGTCP2_MILLISECONDS, + cstat->rttvar / NGTCP2_MILLISECONDS, (uint64_t)(ack_delay / NGTCP2_MILLISECONDS)); } -const ngtcp2_rcvry_stat *ngtcp2_conn_get_rcvry_stat(ngtcp2_conn *conn) { - return &conn->rcs; +void ngtcp2_conn_get_conn_stat(ngtcp2_conn *conn, ngtcp2_conn_stat *cstat) { + *cstat = conn->cstat; } -const ngtcp2_cc_stat *ngtcp2_conn_get_cc_stat(ngtcp2_conn *conn) { - return &conn->ccs; -} - -static ngtcp2_pktns *conn_get_earliest_loss_time_pktns(ngtcp2_conn *conn) { - ngtcp2_pktns *in_pktns = conn->in_pktns; - ngtcp2_pktns *hs_pktns = conn->hs_pktns; - ngtcp2_pktns *pktns = &conn->pktns; - ngtcp2_pktns *res = in_pktns; - - if (hs_pktns && hs_pktns->rtb.loss_time != UINT64_MAX && - (res == NULL || hs_pktns->rtb.loss_time < res->rtb.loss_time)) { - res = hs_pktns; - } - if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) && - pktns->rtb.loss_time != UINT64_MAX && - (res == NULL || pktns->rtb.loss_time < res->rtb.loss_time)) { - res = pktns; - } - - return res; -} - -static ngtcp2_tstamp conn_get_earliest_last_tx_pkt_ts(ngtcp2_conn *conn) { +static ngtcp2_pktns *conn_get_earliest_pktns(ngtcp2_conn *conn, + ngtcp2_tstamp *pts, + const ngtcp2_tstamp *times) { ngtcp2_pktns *ns[] = {conn->in_pktns, conn->hs_pktns, &conn->pktns}; - ngtcp2_rcvry_stat *rcs = &conn->rcs; - ngtcp2_tstamp earliest_ts = rcs->last_tx_pkt_ts[NGTCP2_CRYPTO_LEVEL_INITIAL]; - ngtcp2_pktns *pktns = ns[0]; + ngtcp2_pktns *res = ns[0]; size_t i; - - for (i = NGTCP2_CRYPTO_LEVEL_HANDSHAKE; i <= NGTCP2_CRYPTO_LEVEL_APP; ++i) { - if (rcs->last_tx_pkt_ts[i] != UINT64_MAX && - (!pktns || rcs->last_tx_pkt_ts[i] < earliest_ts) && - (i != NGTCP2_CRYPTO_LEVEL_APP || - (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED))) { - earliest_ts = rcs->last_tx_pkt_ts[i]; - pktns = ns[i]; + ngtcp2_tstamp earliest_ts = times[NGTCP2_PKTNS_ID_INITIAL]; + + for (i = NGTCP2_PKTNS_ID_HANDSHAKE; i < NGTCP2_PKTNS_ID_MAX; ++i) { + if (ns[i] == NULL || ns[i]->rtb.num_ack_eliciting == 0 || + (times[i] == UINT64_MAX || + (earliest_ts != UINT64_MAX && times[i] >= earliest_ts) || + (i == NGTCP2_PKTNS_ID_APP && + !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) { + continue; } - } - return earliest_ts; -} + earliest_ts = times[i]; + res = ns[i]; + } -static ngtcp2_pktns * -conn_get_earliest_non_null_last_tx_pktns(ngtcp2_conn *conn) { - ngtcp2_pktns *ns[] = {conn->in_pktns, conn->hs_pktns, &conn->pktns}; - ngtcp2_pktns *res = ns[0]; - ngtcp2_rcvry_stat *rcs = &conn->rcs; - size_t i, earliest_ts = rcs->last_tx_pkt_ts[NGTCP2_CRYPTO_LEVEL_INITIAL]; + if (res == NULL && !conn->server) { + earliest_ts = UINT64_MAX; - for (i = NGTCP2_CRYPTO_LEVEL_HANDSHAKE; i <= NGTCP2_CRYPTO_LEVEL_APP; ++i) { - if (res == NULL || - (rcs->last_tx_pkt_ts[i] != UINT64_MAX && - (earliest_ts == UINT64_MAX || rcs->last_tx_pkt_ts[i] < earliest_ts) && - (i != NGTCP2_CRYPTO_LEVEL_APP || - (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)))) { - earliest_ts = rcs->last_tx_pkt_ts[i]; - res = ns[i]; + if (conn->hs_pktns && conn->hs_pktns->crypto.tx.ckm) { + res = conn->hs_pktns; + } else { + res = conn->in_pktns; } } + if (pts) { + *pts = earliest_ts; + } return res; } void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - ngtcp2_rcvry_stat *rcs = &conn->rcs; + ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_duration timeout; ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_pktns *hs_pktns = conn->hs_pktns; ngtcp2_pktns *pktns = &conn->pktns; - ngtcp2_pktns *earliest_pktns = conn_get_earliest_loss_time_pktns(conn); + ngtcp2_pktns *earliest_pktns; + ngtcp2_tstamp earliest_loss_time; ngtcp2_tstamp last_tx_pkt_ts; - if (earliest_pktns && earliest_pktns->rtb.loss_time != UINT64_MAX) { - rcs->loss_detection_timer = earliest_pktns->rtb.loss_time; + conn_get_earliest_pktns(conn, &earliest_loss_time, cstat->loss_time); + + if (earliest_loss_time != UINT64_MAX) { + cstat->loss_detection_timer = earliest_loss_time; ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "loss_detection_timer=%" PRIu64 " nonzero crypto loss time", - rcs->loss_detection_timer); + cstat->loss_detection_timer); return; } - if ((!in_pktns || ngtcp2_rtb_num_ack_eliciting(&in_pktns->rtb) == 0) && - (!hs_pktns || ngtcp2_rtb_num_ack_eliciting(&hs_pktns->rtb) == 0) && - ngtcp2_rtb_num_ack_eliciting(&pktns->rtb) == 0 && - (conn->server || (conn->flags & NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED))) { - if (rcs->loss_detection_timer) { + if ((!in_pktns || in_pktns->rtb.num_ack_eliciting == 0) && + (!hs_pktns || hs_pktns->rtb.num_ack_eliciting == 0) && + (pktns->rtb.num_ack_eliciting == 0 || + !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) && + (conn->server || + (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED | + NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) { + if (cstat->loss_detection_timer) { ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "loss detection timer canceled"); - rcs->loss_detection_timer = 0; + cstat->loss_detection_timer = 0; + cstat->pto_count = 0; } return; } - if (rcs->smoothed_rtt == 0) { - timeout = 2 * NGTCP2_DEFAULT_INITIAL_RTT; - } else { - timeout = conn_compute_pto(conn); - } - timeout *= 1ULL << rcs->pto_count; + earliest_pktns = + conn_get_earliest_pktns(conn, &last_tx_pkt_ts, cstat->last_tx_pkt_ts); - last_tx_pkt_ts = conn_get_earliest_last_tx_pkt_ts(conn); + assert(earliest_pktns); if (last_tx_pkt_ts == UINT64_MAX) { last_tx_pkt_ts = ts; } - rcs->loss_detection_timer = last_tx_pkt_ts + timeout; + timeout = conn_compute_pto(conn, earliest_pktns) * (1ULL << cstat->pto_count); + + cstat->loss_detection_timer = last_tx_pkt_ts + timeout; ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "loss_detection_timer=%" PRIu64 " last_tx_pkt_ts=%" PRIu64 " timeout=%" PRIu64, - rcs->loss_detection_timer, last_tx_pkt_ts, + cstat->loss_detection_timer, last_tx_pkt_ts, (uint64_t)(timeout / NGTCP2_MILLISECONDS)); } /* - * conn_handshake_pkt_lost is called when handshake packets which + * conn_on_crypto_timeout is called when handshake packets which * belong to |pktns| are lost. * * This function returns 0 if it succeeds, or one of the following @@ -9015,7 +9146,7 @@ static int conn_on_crypto_timeout(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { ngtcp2_frame_chain *frc = NULL; int rv; - rv = ngtcp2_rtb_on_crypto_timeout(&pktns->rtb, &frc); + rv = ngtcp2_rtb_on_crypto_timeout(&pktns->rtb, &frc, &conn->cstat); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_list_del(frc, conn->mem); @@ -9032,11 +9163,13 @@ static int conn_on_crypto_timeout(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { } int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - ngtcp2_rcvry_stat *rcs = &conn->rcs; + ngtcp2_conn_stat *cstat = &conn->cstat; int rv; ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_pktns *hs_pktns = conn->hs_pktns; - ngtcp2_pktns *loss_pktns = conn_get_earliest_loss_time_pktns(conn); + ngtcp2_tstamp earliest_loss_time; + ngtcp2_pktns *loss_pktns = + conn_get_earliest_pktns(conn, &earliest_loss_time, cstat->loss_time); ngtcp2_pktns *earliest_pktns; conn->log.last_ts = ts; @@ -9045,21 +9178,22 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { switch (conn->state) { case NGTCP2_CS_CLOSING: case NGTCP2_CS_DRAINING: - rcs->loss_detection_timer = 0; + cstat->loss_detection_timer = 0; + cstat->pto_count = 0; return 0; default: break; } - if (!rcs->loss_detection_timer) { + if (!cstat->loss_detection_timer) { return 0; } ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "loss detection timer fired"); - if (loss_pktns && loss_pktns->rtb.loss_time != UINT64_MAX) { - rv = ngtcp2_conn_detect_lost_pkt(conn, loss_pktns, rcs, ts); + if (earliest_loss_time != UINT64_MAX) { + rv = ngtcp2_conn_detect_lost_pkt(conn, loss_pktns, cstat, ts); if (rv != 0) { return rv; } @@ -9069,18 +9203,25 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { if (!conn->server && !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) { if (hs_pktns->crypto.tx.ckm) { + rv = conn_on_crypto_timeout(conn, hs_pktns); + if (rv != 0) { + return rv; + } hs_pktns->rtb.probe_pkt_left = 1; } else { - conn_on_crypto_timeout(conn, in_pktns); + rv = conn_on_crypto_timeout(conn, in_pktns); + if (rv != 0) { + return rv; + } in_pktns->rtb.probe_pkt_left = 1; } } else { - earliest_pktns = conn_get_earliest_non_null_last_tx_pktns(conn); + earliest_pktns = conn_get_earliest_pktns(conn, NULL, cstat->last_tx_pkt_ts); assert(earliest_pktns); - switch (earliest_pktns->rtb.crypto_level) { - case NGTCP2_CRYPTO_LEVEL_INITIAL: + switch (earliest_pktns->rtb.pktns_id) { + case NGTCP2_PKTNS_ID_INITIAL: assert(in_pktns); rv = conn_on_crypto_timeout(conn, in_pktns); if (rv != 0) { @@ -9092,7 +9233,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } /* fall through for server so that it can coalesce packets. */ /* fall through */ - case NGTCP2_CRYPTO_LEVEL_HANDSHAKE: + case NGTCP2_PKTNS_ID_HANDSHAKE: assert(hs_pktns); rv = conn_on_crypto_timeout(conn, hs_pktns); if (rv != 0) { @@ -9100,7 +9241,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } hs_pktns->rtb.probe_pkt_left = 1; break; - case NGTCP2_CRYPTO_LEVEL_APP: + case NGTCP2_PKTNS_ID_APP: conn->pktns.rtb.probe_pkt_left = 2; break; default: @@ -9108,10 +9249,10 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { } } - ++rcs->pto_count; + ++cstat->pto_count; ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "pto_count=%zu", - rcs->pto_count); + cstat->pto_count); ngtcp2_conn_set_loss_detection_timer(conn, ts); @@ -9124,7 +9265,6 @@ int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, ngtcp2_pktns *pktns; ngtcp2_frame_chain *frc; ngtcp2_crypto *fr; - ngtcp2_ksl_key key; int rv; if (datalen == 0) { @@ -9160,8 +9300,7 @@ int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, fr->data[0].len = datalen; fr->data[0].base = (uint8_t *)data; - rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, - ngtcp2_ksl_key_ptr(&key, &fr->offset), frc); + rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL, &fr->offset, frc); if (rv != 0) { ngtcp2_frame_chain_del(frc, conn->mem); return rv; @@ -9173,6 +9312,34 @@ int ngtcp2_conn_submit_crypto_data(ngtcp2_conn *conn, return 0; } +int ngtcp2_conn_submit_new_token(ngtcp2_conn *conn, const uint8_t *token, + size_t tokenlen) { + int rv; + ngtcp2_frame_chain *nfrc; + uint8_t *p; + + assert(conn->server); + assert(token); + assert(tokenlen); + + rv = ngtcp2_frame_chain_extralen_new(&nfrc, tokenlen, conn->mem); + if (rv != 0) { + return rv; + } + + nfrc->fr.type = NGTCP2_FRAME_NEW_TOKEN; + + p = (uint8_t *)nfrc + sizeof(*nfrc); + memcpy(p, token, tokenlen); + + ngtcp2_vec_init(&nfrc->fr.new_token.token, p, tokenlen); + + nfrc->next = conn->pktns.tx.frq; + conn->pktns.tx.frq = nfrc; + + return 0; +} + ngtcp2_strm *ngtcp2_conn_tx_strmq_top(ngtcp2_conn *conn) { assert(!ngtcp2_pq_empty(&conn->tx.strmq)); return ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx.strmq), ngtcp2_strm, pe); @@ -9350,6 +9517,21 @@ uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) { return conn->tx.max_offset - conn->tx.offset; } +uint64_t ngtcp2_conn_get_streams_bidi_left(ngtcp2_conn *conn) { + uint64_t n = ngtcp2_ord_stream_id(conn->local.bidi.next_stream_id); + + return n > conn->local.bidi.max_streams + ? 0 + : conn->local.bidi.max_streams - n + 1; +} + +uint64_t ngtcp2_conn_get_streams_uni_left(ngtcp2_conn *conn) { + uint64_t n = ngtcp2_ord_stream_id(conn->local.uni.next_stream_id); + + return n > conn->local.uni.max_streams ? 0 + : conn->local.uni.max_streams - n + 1; +} + ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { ngtcp2_duration trpto; ngtcp2_duration idle_timeout; @@ -9358,6 +9540,7 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { completion. */ if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) || + conn->remote.transport_params.max_idle_timeout == 0 || (conn->local.settings.transport_params.max_idle_timeout && conn->local.settings.transport_params.max_idle_timeout < conn->remote.transport_params.max_idle_timeout)) { @@ -9370,13 +9553,19 @@ ngtcp2_tstamp ngtcp2_conn_get_idle_expiry(ngtcp2_conn *conn) { return UINT64_MAX; } - trpto = 3 * conn_compute_pto(conn); + trpto = 3 * conn_compute_pto( + conn, (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) + ? &conn->pktns + : conn->hs_pktns); return conn->idle_ts + ngtcp2_max(idle_timeout, trpto); } ngtcp2_duration ngtcp2_conn_get_pto(ngtcp2_conn *conn) { - return conn_compute_pto(conn); + return conn_compute_pto(conn, + (conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) + ? &conn->pktns + : conn->hs_pktns); } void ngtcp2_conn_set_initial_crypto_ctx(ngtcp2_conn *conn, @@ -9406,6 +9595,15 @@ const ngtcp2_crypto_ctx *ngtcp2_conn_get_crypto_ctx(ngtcp2_conn *conn) { return &conn->pktns.crypto.ctx; } +void *ngtcp2_conn_get_tls_native_handle(ngtcp2_conn *conn) { + return conn->crypto.tls_native_handle; +} + +void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn, + void *tls_native_handle) { + conn->crypto.tls_native_handle = tls_native_handle; +} + void ngtcp2_conn_get_connection_close_error_code( ngtcp2_conn *conn, ngtcp2_connection_close_error_code *ccec) { *ccec = conn->rx.ccec; @@ -9423,6 +9621,8 @@ int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id) { return conn_local_stream(conn, stream_id); } +int ngtcp2_conn_is_server(ngtcp2_conn *conn) { return conn->server; } + void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, const uint8_t *data) { memcpy(pcent->data, data, sizeof(pcent->data)); @@ -9430,7 +9630,9 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, void ngtcp2_settings_default(ngtcp2_settings *settings) { memset(settings, 0, sizeof(*settings)); - settings->transport_params.max_packet_size = NGTCP2_MAX_PKT_SIZE; + settings->cc_algo = NGTCP2_CC_ALGO_CUBIC; + settings->transport_params.max_udp_payload_size = + NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE; settings->transport_params.ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; settings->transport_params.max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; diff --git a/deps/ngtcp2/lib/ngtcp2_conn.h b/deps/ngtcp2/lib/ngtcp2_conn.h index 3b17a3d230ada7..39b5b029385fcb 100644 --- a/deps/ngtcp2/lib/ngtcp2_conn.h +++ b/deps/ngtcp2/lib/ngtcp2_conn.h @@ -262,16 +262,18 @@ struct ngtcp2_conn { /* rcid is a connection ID present in Initial or 0-RTT packet from client as destination connection ID. Server uses this field to check that duplicated Initial or 0-RTT packet are indeed sent to - this connection. Client uses this field to validate - original_connection_id transport parameter. */ + this connection. It is also sent to client as + original_destination_connection_id transport parameter. Client + uses this field to validate original_destination_connection_id + transport parameter if no Retry packet is involved. */ ngtcp2_cid rcid; /* oscid is the source connection ID initially used by the local endpoint. */ ngtcp2_cid oscid; - /* odcid is the destination connection ID initially negotiated - during handshake. It is used to receive late handshake packets - after handshake completion. */ - ngtcp2_cid odcid; + /* retry_scid is the source connection ID from Retry packet. Client + records it in order to verify retry_source_connection_id + transport parameter. Server does not use this field. */ + ngtcp2_cid retry_scid; ngtcp2_pktns *in_pktns; ngtcp2_pktns *hs_pktns; ngtcp2_pktns pktns; @@ -338,6 +340,14 @@ struct ngtcp2_conn { ngtcp2_ringbuf path_challenge; /* ccec is the received connection close error code. */ ngtcp2_connection_close_error_code ccec; + struct { + /* start_ts is the time instant when receiving rate measurement + is started. */ + ngtcp2_tstamp start_ts; + /* received is the number of bytes received in the current + measurement period. */ + uint64_t received; + } rate; } rx; struct { @@ -417,6 +427,8 @@ struct ngtcp2_conn { ngtcp2_tstamp confirmed_ts; } key_update; + /* tls_native_handle is a native handle to TLS session object. */ + void *tls_native_handle; size_t aead_overhead; /* decrypt_buf is a buffer which is used to write decrypted data. */ ngtcp2_vec decrypt_buf; @@ -441,23 +453,13 @@ struct ngtcp2_conn { } pkt; ngtcp2_map strms; - ngtcp2_rcvry_stat rcs; - ngtcp2_cc_stat ccs; + ngtcp2_conn_stat cstat; ngtcp2_pv *pv; ngtcp2_log log; ngtcp2_qlog qlog; ngtcp2_rst rst; - ngtcp2_default_cc cc; - /* token is an address validation token received from server. */ - ngtcp2_buf token; - /* hs_recved is the number of bytes received from client before its - address is validated. This field is only used by server to - ensure "3 times received data" rule. */ - size_t hs_recved; - /* hs_sent is the number of bytes sent from server during handshake. - This field is only used by server to ensure "3 times received - data" rule. */ - size_t hs_sent; + ngtcp2_cc_algo cc_algo; + ngtcp2_cc cc; const ngtcp2_mem *mem; /* idle_ts is the time instant when idle timer started. */ ngtcp2_tstamp idle_ts; @@ -468,101 +470,6 @@ struct ngtcp2_conn { int server; }; -/** - * @function - * - * `ngtcp2_conn_read_handshake` performs QUIC cryptographic handshake - * by reading given data. |pkt| points to the buffer to read and - * |pktlen| is the length of the buffer. |path| is the network path. - * - * The application should call `ngtcp2_conn_write_handshake` (or - * `ngtcp2_conn_client_write_handshake` for client session) to make - * handshake go forward after calling this function. - * - * Application should call this function until - * `ngtcp2_conn_get_handshake_completed` returns nonzero. After the - * completion of handshake, `ngtcp2_conn_read_pkt` and - * `ngtcp2_conn_write_pkt` should be called instead. - * - * This function must not be called from inside the callback - * functions. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: (TBD). - */ -int ngtcp2_conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path, - const uint8_t *pkt, size_t pktlen, - ngtcp2_tstamp ts); - -/** - * @function - * - * `ngtcp2_conn_write_handshake` performs QUIC cryptographic handshake - * by writing handshake packets. It may write a packet in the given - * buffer pointed by |dest| whose capacity is given as |destlen|. - * Application must ensure that the buffer pointed by |dest| is not - * empty. - * - * Application should keep calling this function repeatedly until it - * returns zero, or negative error code. - * - * Application should call this function until - * `ngtcp2_conn_get_handshake_completed` returns nonzero. After the - * completion of handshake, `ngtcp2_conn_read_pkt` and - * `ngtcp2_conn_write_pkt` should be called instead. - * - * During handshake, application can send 0-RTT data (or its response) - * using `ngtcp2_conn_write_stream`. - * `ngtcp2_conn_client_write_handshake` is generally efficient because - * it can coalesce Handshake packet and 0-RTT packet into one UDP - * packet. - * - * This function returns 0 if it cannot write any frame because buffer - * is too small, or packet is congestion limited. Application should - * keep reading and wait for congestion window to grow. - * - * This function must not be called from inside the callback - * functions. - * - * This function returns the number of bytes written to the buffer - * pointed by |dest| if it succeeds, or one of the following negative - * error codes: (TBD). - */ -ngtcp2_ssize ngtcp2_conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest, - size_t destlen, ngtcp2_tstamp ts); - -/** - * @function - * - * `ngtcp2_conn_client_write_handshake` is just like - * `ngtcp2_conn_write_handshake`, but it is for client only, and can - * write 0-RTT data. This function can coalesce handshake packet and - * 0-RTT packet into single UDP packet, thus it is generally more - * efficient than the combination of `ngtcp2_conn_write_handshake` and - * `ngtcp2_conn_write_stream`. - * - * |stream_id|, |fin|, |datav|, and |datavcnt| are stream identifier - * to which 0-RTT data is sent, whether it is a last data chunk in - * this stream, a vector of 0-RTT data, and its number of elements - * respectively. If there is no 0RTT data to send, pass negative - * integer to |stream_id|. The amount of 0RTT data sent is assigned - * to |*pdatalen|. If no data is sent, -1 is assigned. Note that 0 - * length STREAM frame is allowed in QUIC, so 0 might be assigned to - * |*pdatalen|. - * - * This function returns 0 if it cannot write any frame because buffer - * is too small, or packet is congestion limited. Application should - * keep reading and wait for congestion window to grow. - * - * This function returns the number of bytes written to the buffer - * pointed by |dest| if it succeeds, or one of the following negative - * error codes: (TBD). - */ -ngtcp2_ssize ngtcp2_conn_client_write_handshake( - ngtcp2_conn *conn, uint8_t *dest, size_t destlen, ngtcp2_ssize *pdatalen, - uint32_t flags, int64_t stream_id, int fin, const ngtcp2_vec *datav, - size_t datavcnt, ngtcp2_tstamp ts); - /* * ngtcp2_conn_sched_ack stores packet number |pkt_num| and its * reception timestamp |ts| in order to send its ACK. @@ -653,7 +560,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts); * Out of memory. */ int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, - ngtcp2_rcvry_stat *rcs, ngtcp2_tstamp ts); + ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); /* * ngtcp2_conn_tx_strmq_top returns the ngtcp2_strm which sits on the diff --git a/deps/ngtcp2/lib/ngtcp2_crypto.c b/deps/ngtcp2/lib/ngtcp2_crypto.c index dd65ff7e3039fb..26eacb87299336 100644 --- a/deps/ngtcp2/lib/ngtcp2_crypto.c +++ b/deps/ngtcp2/lib/ngtcp2_crypto.c @@ -72,6 +72,7 @@ int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen, (*pckm)->iv.base = p; (*pckm)->iv.len = ivlen; (*pckm)->pkt_num = -1; + (*pckm)->use_count = 0; (*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE; return 0; @@ -118,6 +119,33 @@ static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id, return ngtcp2_put_varint(p, value); } +/* + * cid_paramlen returns the length of a single transport parameter + * which has |cid| as value. + */ +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) + + cid->datalen; +} + +/* + * write_cid_param writes parameter |id| of the given |cid|. It + * returns p + the number of bytes written. + */ +static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id, + const ngtcp2_cid *cid) { + 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); + if (cid->datalen) { + p = ngtcp2_cpymem(p, cid->data, cid->datalen); + } + return p; +} + ngtcp2_ssize ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype, @@ -131,6 +159,10 @@ ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, case NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO: break; case NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS: + 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) + @@ -138,8 +170,7 @@ ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, NGTCP2_STATELESS_RESET_TOKENLEN; } if (params->preferred_address_present) { - assert(params->preferred_address.cid.datalen == 0 || - params->preferred_address.cid.datalen >= NGTCP2_MIN_CIDLEN); + 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 */ @@ -149,17 +180,18 @@ ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) + ngtcp2_put_varint_len(preferred_addrlen) + preferred_addrlen; } - if (params->original_connection_id_present) { - len += - ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_ORIGINAL_CONNECTION_ID) + - ngtcp2_put_varint_len(params->original_connection_id.datalen) + - params->original_connection_id.datalen; + 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; } + len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID, + ¶ms->initial_scid); + if (params->initial_max_stream_data_bidi_local) { len += varint_paramlen( NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, @@ -186,9 +218,9 @@ ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI, params->initial_max_streams_uni); } - if (params->max_packet_size != NGTCP2_MAX_PKT_SIZE) { - len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_PACKET_SIZE, - params->max_packet_size); + if (params->max_udp_payload_size != NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE) { + len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE, + params->max_udp_payload_size); } if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) { len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT, @@ -221,6 +253,10 @@ ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, p = dest; if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { + p = write_cid_param( + p, NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID, + ¶ms->original_dcid); + 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)); @@ -248,14 +284,15 @@ ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, p, params->preferred_address.stateless_reset_token, sizeof(params->preferred_address.stateless_reset_token)); } - if (params->original_connection_id_present) { - p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_ORIGINAL_CONNECTION_ID); - p = ngtcp2_put_varint(p, params->original_connection_id.datalen); - p = ngtcp2_cpymem(p, params->original_connection_id.data, - params->original_connection_id.datalen); + if (params->retry_scid_present) { + p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID, + ¶ms->retry_scid); } } + 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( p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, @@ -289,9 +326,9 @@ ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen, params->initial_max_streams_uni); } - if (params->max_packet_size != NGTCP2_MAX_PKT_SIZE) { - p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_PACKET_SIZE, - params->max_packet_size); + if (params->max_udp_payload_size != NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE) { + p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE, + params->max_udp_payload_size); } if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) { @@ -371,6 +408,10 @@ static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p, p += nread; + if (p == end) { + return -1; + } + if ((uint64_t)(end - p) < valuelen) { return -1; } @@ -386,6 +427,37 @@ static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p, return (ngtcp2_ssize)(p - begin); } +/* + * decode_cid_param decodes length prefixed ngtcp2_cid from the buffer + * pointed by |p| of length |end - p|. 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. + */ +static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p, + const uint8_t *end) { + const uint8_t *begin = p; + uint64_t valuelen; + ngtcp2_ssize nread = decode_varint(&valuelen, p, end); + + if (nread < 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; + } + + ngtcp2_cid_init(pdest, p, (size_t)valuelen); + + p += valuelen; + + return (ngtcp2_ssize)(p - begin); +} + int ngtcp2_decode_transport_params(ngtcp2_transport_params *params, ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen) { @@ -394,37 +466,37 @@ int ngtcp2_decode_transport_params(ngtcp2_transport_params *params, uint64_t param_type; uint64_t valuelen; ngtcp2_ssize nread; - uint8_t scb[8192]; - size_t scb_idx; - size_t scb_shift; + int initial_scid_present = 0; + int original_dcid_present = 0; p = data; end = data + datalen; /* Set default values */ + memset(params, 0, sizeof(*params)); params->initial_max_streams_bidi = 0; params->initial_max_streams_uni = 0; params->initial_max_stream_data_bidi_local = 0; params->initial_max_stream_data_bidi_remote = 0; params->initial_max_stream_data_uni = 0; - params->max_packet_size = NGTCP2_MAX_PKT_SIZE; + params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE; params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT; params->stateless_reset_token_present = 0; params->preferred_address_present = 0; - memset(¶ms->preferred_address, 0, sizeof(params->preferred_address)); params->disable_active_migration = 0; params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY; params->max_idle_timeout = 0; params->active_connection_id_limit = NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT; - params->original_connection_id_present = 0; + params->retry_scid_present = 0; + memset(¶ms->retry_scid, 0, sizeof(params->retry_scid)); + memset(¶ms->initial_scid, 0, sizeof(params->initial_scid)); + memset(¶ms->original_dcid, 0, sizeof(params->original_dcid)); if (datalen == 0) { return 0; } - memset(scb, 0, sizeof(scb)); - for (; (size_t)(end - p) >= 2;) { nread = decode_varint(¶m_type, p, end); if (nread < 0) { @@ -432,13 +504,6 @@ int ngtcp2_decode_transport_params(ngtcp2_transport_params *params, } p += nread; - scb_idx = param_type / 8; - scb_shift = param_type % 8; - - if (scb[scb_idx] & (1 << scb_shift)) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; - } - scb[scb_idx] |= (uint8_t)(1 << scb_shift); switch (param_type) { case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL: nread = decode_varint_param(¶ms->initial_max_stream_data_bidi_local, @@ -498,8 +563,8 @@ int ngtcp2_decode_transport_params(ngtcp2_transport_params *params, params->max_idle_timeout *= NGTCP2_MILLISECONDS; p += nread; break; - case NGTCP2_TRANSPORT_PARAM_MAX_PACKET_SIZE: - nread = decode_varint_param(¶ms->max_packet_size, p, end); + case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE: + nread = decode_varint_param(¶ms->max_udp_payload_size, p, end); if (nread < 0) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } @@ -570,8 +635,7 @@ int ngtcp2_decode_transport_params(ngtcp2_transport_params *params, len += params->preferred_address.cid.datalen; if (valuelen != len || params->preferred_address.cid.datalen > NGTCP2_MAX_CIDLEN || - (params->preferred_address.cid.datalen != 0 && - params->preferred_address.cid.datalen < NGTCP2_MIN_CIDLEN)) { + params->preferred_address.cid.datalen < NGTCP2_MIN_CIDLEN) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } if (params->preferred_address.cid.datalen) { @@ -594,22 +658,35 @@ int ngtcp2_decode_transport_params(ngtcp2_transport_params *params, p += nread; params->disable_active_migration = 1; break; - case NGTCP2_TRANSPORT_PARAM_ORIGINAL_CONNECTION_ID: + case NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID: if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - nread = decode_varint(&valuelen, p, end); + nread = decode_cid_param(¶ms->original_dcid, p, end); if (nread < 0) { - return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; + return (int)nread; } + original_dcid_present = 1; p += nread; - if (valuelen < NGTCP2_MIN_CIDLEN || valuelen > NGTCP2_MAX_CIDLEN || - (size_t)(end - p) < valuelen) { + break; + case NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID: + if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } - ngtcp2_cid_init(¶ms->original_connection_id, p, valuelen); - params->original_connection_id_present = 1; - p += valuelen; + nread = decode_cid_param(¶ms->retry_scid, p, end); + if (nread < 0) { + return (int)nread; + } + 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; + } + initial_scid_present = 1; + p += nread; break; case NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY: nread = decode_varint_param(¶ms->max_ack_delay, p, end); @@ -645,5 +722,11 @@ int ngtcp2_decode_transport_params(ngtcp2_transport_params *params, 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; + } + return 0; } diff --git a/deps/ngtcp2/lib/ngtcp2_crypto.h b/deps/ngtcp2/lib/ngtcp2_crypto.h index 8dc1ef9f39d344..1cc144e801a1ef 100644 --- a/deps/ngtcp2/lib/ngtcp2_crypto.h +++ b/deps/ngtcp2/lib/ngtcp2_crypto.h @@ -57,6 +57,10 @@ typedef struct { a packet. For decryption key, it is the lowest packet number of a packet which can be decrypted with this keying material. */ int64_t pkt_num; + /* use_count is the number of encryption or decryption failure. For + tx key, this is the number of encryption. For rx key, this is + the number of decryption failure. */ + uint64_t use_count; /* flags is the bitwise OR of zero or more of ngtcp2_crypto_km_flag. */ uint8_t flags; @@ -88,7 +92,7 @@ void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem); typedef struct { ngtcp2_crypto_aead aead; ngtcp2_crypto_cipher hp; - const ngtcp2_crypto_km *ckm; + ngtcp2_crypto_km *ckm; const ngtcp2_vec *hp_key; size_t aead_overhead; ngtcp2_encrypt encrypt; diff --git a/deps/ngtcp2/lib/ngtcp2_err.c b/deps/ngtcp2/lib/ngtcp2_err.c index ae2edb35ee428f..6de827b0f97d2b 100644 --- a/deps/ngtcp2/lib/ngtcp2_err.c +++ b/deps/ngtcp2/lib/ngtcp2_err.c @@ -98,6 +98,8 @@ const char *ngtcp2_strerror(int liberr) { return "ERR_WRITE_STREAM_MORE"; case NGTCP2_ERR_RETRY: return "ERR_RETRY"; + case NGTCP2_ERR_DROP_CONN: + return "ERR_DROP_CONN"; default: return "(unknown)"; } diff --git a/deps/ngtcp2/lib/ngtcp2_gaptr.c b/deps/ngtcp2/lib/ngtcp2_gaptr.c index 4cbd898a292dc1..b93cd828c211b3 100644 --- a/deps/ngtcp2/lib/ngtcp2_gaptr.c +++ b/deps/ngtcp2/lib/ngtcp2_gaptr.c @@ -30,7 +30,6 @@ int ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) { int rv; ngtcp2_range range = {0, UINT64_MAX}; - ngtcp2_ksl_key key; rv = ngtcp2_ksl_init(&gaptr->gap, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem); @@ -38,8 +37,7 @@ int ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) { return rv; } - rv = ngtcp2_ksl_insert(&gaptr->gap, NULL, ngtcp2_ksl_key_ptr(&key, &range), - NULL); + rv = ngtcp2_ksl_insert(&gaptr->gap, NULL, &range, NULL); if (rv != 0) { ngtcp2_ksl_free(&gaptr->gap); return rv; @@ -62,37 +60,33 @@ int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, size_t datalen) { int rv; ngtcp2_range k, m, l, r, q = {offset, offset + datalen}; ngtcp2_ksl_it it; - ngtcp2_ksl_key key, old_key; - it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, ngtcp2_ksl_key_ptr(&key, &q), + it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q, ngtcp2_ksl_range_exclusive_compar); for (; !ngtcp2_ksl_it_end(&it);) { - k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it).ptr; + k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it); m = ngtcp2_range_intersect(&q, &k); if (!ngtcp2_range_len(&m)) { break; } if (ngtcp2_range_eq(&k, &m)) { - ngtcp2_ksl_remove(&gaptr->gap, &it, ngtcp2_ksl_key_ptr(&key, &k)); + ngtcp2_ksl_remove(&gaptr->gap, &it, &k); continue; } ngtcp2_range_cut(&l, &r, &k, &m); if (ngtcp2_range_len(&l)) { - ngtcp2_ksl_update_key(&gaptr->gap, ngtcp2_ksl_key_ptr(&old_key, &k), - ngtcp2_ksl_key_ptr(&key, &l)); + ngtcp2_ksl_update_key(&gaptr->gap, &k, &l); if (ngtcp2_range_len(&r)) { - rv = ngtcp2_ksl_insert(&gaptr->gap, &it, ngtcp2_ksl_key_ptr(&key, &r), - NULL); + rv = ngtcp2_ksl_insert(&gaptr->gap, &it, &r, NULL); if (rv != 0) { return rv; } } } else if (ngtcp2_range_len(&r)) { - ngtcp2_ksl_update_key(&gaptr->gap, ngtcp2_ksl_key_ptr(&old_key, &k), - ngtcp2_ksl_key_ptr(&key, &r)); + ngtcp2_ksl_update_key(&gaptr->gap, &k, &r); } ngtcp2_ksl_it_next(&it); } @@ -101,27 +95,23 @@ int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, size_t datalen) { uint64_t ngtcp2_gaptr_first_gap_offset(ngtcp2_gaptr *gaptr) { ngtcp2_ksl_it it = ngtcp2_ksl_begin(&gaptr->gap); - ngtcp2_range r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it).ptr; + ngtcp2_range r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it); return r.begin; } ngtcp2_ksl_it ngtcp2_gaptr_get_first_gap_after(ngtcp2_gaptr *gaptr, uint64_t offset) { ngtcp2_range q = {offset, offset + 1}; - ngtcp2_ksl_key key; - return ngtcp2_ksl_lower_bound_compar(&gaptr->gap, - ngtcp2_ksl_key_ptr(&key, &q), + return ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q, ngtcp2_ksl_range_exclusive_compar); } int ngtcp2_gaptr_is_pushed(ngtcp2_gaptr *gaptr, uint64_t offset, size_t datalen) { - ngtcp2_ksl_key key; ngtcp2_range q = {offset, offset + datalen}; - ngtcp2_ksl_it it = - ngtcp2_ksl_lower_bound_compar(&gaptr->gap, ngtcp2_ksl_key_ptr(&key, &q), - ngtcp2_ksl_range_exclusive_compar); - ngtcp2_range k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it).ptr; + ngtcp2_ksl_it it = ngtcp2_ksl_lower_bound_compar( + &gaptr->gap, &q, ngtcp2_ksl_range_exclusive_compar); + ngtcp2_range k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it); ngtcp2_range m = ngtcp2_range_intersect(&q, &k); return ngtcp2_range_len(&m) == 0; } diff --git a/deps/ngtcp2/lib/ngtcp2_ksl.c b/deps/ngtcp2/lib/ngtcp2_ksl.c index 7936a269127c21..10c49806254890 100644 --- a/deps/ngtcp2/lib/ngtcp2_ksl.c +++ b/deps/ngtcp2/lib/ngtcp2_ksl.c @@ -48,30 +48,7 @@ static size_t ksl_blklen(size_t nodelen) { */ static void ksl_node_set_key(ngtcp2_ksl *ksl, ngtcp2_ksl_node *node, const void *key) { - memcpy(&node->key, key, ksl->keylen); -} - -/* - * ksl_node_key assigns the pointer to key of |node| to key->ptr and - * returns |key|. - */ -static ngtcp2_ksl_key *ksl_node_key(ngtcp2_ksl_key *key, - ngtcp2_ksl_node *node) { - key->ptr = &node->key; - return key; -} - -/* - * ksl_nth_node returns |n|th node under |blk|. - */ -static ngtcp2_ksl_node *ksl_nth_node(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, - size_t n) { - return (ngtcp2_ksl_node *)(void *)(blk->nodes + ksl->nodelen * n); -} - -ngtcp2_ksl_node *ngtcp2_ksl_nth_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, - size_t n) { - return ksl_nth_node(ksl, blk, n); + memcpy(node->key, key, ksl->keylen); } int ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, size_t keylen, @@ -107,7 +84,7 @@ static void ksl_free_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) { if (!blk->leaf) { for (i = 0; i < blk->n; ++i) { - ksl_free_blk(ksl, ksl_nth_node(ksl, blk, i)->blk); + ksl_free_blk(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk); } } @@ -174,7 +151,7 @@ static ngtcp2_ksl_blk *ksl_split_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) { */ static int ksl_split_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) { ngtcp2_ksl_node *node; - ngtcp2_ksl_blk *lblk = ksl_nth_node(ksl, blk, i)->blk, *rblk; + ngtcp2_ksl_blk *lblk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk, *rblk; rblk = ksl_split_blk(ksl, lblk); if (rblk == NULL) { @@ -185,13 +162,13 @@ static int ksl_split_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) { blk->nodes + (i + 1) * ksl->nodelen, ksl->nodelen * (blk->n - (i + 1))); - node = ksl_nth_node(ksl, blk, i + 1); + node = ngtcp2_ksl_nth_node(ksl, blk, i + 1); node->blk = rblk; ++blk->n; - ksl_node_set_key(ksl, node, &ksl_nth_node(ksl, rblk, rblk->n - 1)->key); + ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key); - node = ksl_nth_node(ksl, blk, i); - ksl_node_set_key(ksl, node, &ksl_nth_node(ksl, lblk, lblk->n - 1)->key); + node = ngtcp2_ksl_nth_node(ksl, blk, i); + ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key); return 0; } @@ -226,12 +203,12 @@ static int ksl_split_head(ngtcp2_ksl *ksl) { nhead->n = 2; nhead->leaf = 0; - node = ksl_nth_node(ksl, nhead, 0); - ksl_node_set_key(ksl, node, &ksl_nth_node(ksl, lblk, lblk->n - 1)->key); + node = ngtcp2_ksl_nth_node(ksl, nhead, 0); + ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key); node->blk = lblk; - node = ksl_nth_node(ksl, nhead, 1); - ksl_node_set_key(ksl, node, &ksl_nth_node(ksl, rblk, rblk->n - 1)->key); + node = ngtcp2_ksl_nth_node(ksl, nhead, 1); + ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key); node->blk = rblk; ksl->head = nhead; @@ -254,8 +231,8 @@ static void ksl_insert_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i, memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen, ksl->nodelen * (blk->n - i)); - node = ksl_nth_node(ksl, blk, i); - ksl_node_set_key(ksl, node, key->ptr); + node = ngtcp2_ksl_nth_node(ksl, blk, i); + ksl_node_set_key(ksl, node, key); node->data = data; ++blk->n; @@ -265,12 +242,11 @@ static size_t ksl_bsearch(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, const ngtcp2_ksl_key *key, ngtcp2_ksl_compar compar) { ngtcp2_ssize left = -1, right = (ngtcp2_ssize)blk->n, mid; ngtcp2_ksl_node *node; - ngtcp2_ksl_key node_key; while (right - left > 1) { mid = (left + right) / 2; - node = ksl_nth_node(ksl, blk, (size_t)mid); - if (compar(ksl_node_key(&node_key, node), key)) { + node = ngtcp2_ksl_nth_node(ksl, blk, (size_t)mid); + if (compar((ngtcp2_ksl_key *)node->key, key)) { left = mid; } else { right = mid; @@ -284,7 +260,6 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it, const ngtcp2_ksl_key *key, void *data) { ngtcp2_ksl_blk *blk = ksl->head; ngtcp2_ksl_node *node; - ngtcp2_ksl_key node_key; size_t i; int rv; @@ -311,15 +286,15 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it, if (i == blk->n) { /* This insertion extends the largest key in this subtree. */ for (; !blk->leaf;) { - node = ksl_nth_node(ksl, blk, blk->n - 1); + node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1); if (node->blk->n == NGTCP2_KSL_MAX_NBLK) { rv = ksl_split_node(ksl, blk, blk->n - 1); if (rv != 0) { return rv; } - node = ksl_nth_node(ksl, blk, blk->n - 1); + node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1); } - ksl_node_set_key(ksl, node, key->ptr); + ksl_node_set_key(ksl, node, key); blk = node->blk; } ksl_insert_node(ksl, blk, blk->n, key, data); @@ -330,17 +305,17 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it, return 0; } - node = ksl_nth_node(ksl, blk, i); + node = ngtcp2_ksl_nth_node(ksl, blk, i); if (node->blk->n == NGTCP2_KSL_MAX_NBLK) { rv = ksl_split_node(ksl, blk, i); if (rv != 0) { return rv; } - if (ksl->compar(ksl_node_key(&node_key, node), key)) { - node = ksl_nth_node(ksl, blk, i + 1); - if (ksl->compar(ksl_node_key(&node_key, node), key)) { - ksl_node_set_key(ksl, node, key->ptr); + if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) { + node = ngtcp2_ksl_nth_node(ksl, blk, i + 1); + if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) { + ksl_node_set_key(ksl, node, key); } } } @@ -376,8 +351,8 @@ static ngtcp2_ksl_blk *ksl_merge_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, assert(i + 1 < blk->n); - lblk = ksl_nth_node(ksl, blk, i)->blk; - rblk = ksl_nth_node(ksl, blk, i + 1)->blk; + lblk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk; + rblk = ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk; assert(lblk->n + rblk->n < NGTCP2_KSL_MAX_NBLK); @@ -399,8 +374,8 @@ static ngtcp2_ksl_blk *ksl_merge_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, ksl->head = lblk; } else { ksl_remove_node(ksl, blk, i + 1); - ksl_node_set_key(ksl, ksl_nth_node(ksl, blk, i), - &ksl_nth_node(ksl, lblk, lblk->n - 1)->key); + ksl_node_set_key(ksl, ngtcp2_ksl_nth_node(ksl, blk, i), + ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key); } return lblk; @@ -415,17 +390,17 @@ static void ksl_shift_left(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) { assert(i > 0); - lnode = ksl_nth_node(ksl, blk, i - 1); - rnode = ksl_nth_node(ksl, blk, i); + lnode = ngtcp2_ksl_nth_node(ksl, blk, i - 1); + rnode = ngtcp2_ksl_nth_node(ksl, blk, i); assert(lnode->blk->n < NGTCP2_KSL_MAX_NBLK); assert(rnode->blk->n > NGTCP2_KSL_MIN_NBLK); - dest = ksl_nth_node(ksl, lnode->blk, lnode->blk->n); - src = ksl_nth_node(ksl, rnode->blk, 0); + dest = ngtcp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n); + src = ngtcp2_ksl_nth_node(ksl, rnode->blk, 0); memcpy(dest, src, ksl->nodelen); - ksl_node_set_key(ksl, lnode, &dest->key); + ksl_node_set_key(ksl, lnode, dest->key); ++lnode->blk->n; --rnode->blk->n; @@ -442,8 +417,8 @@ static void ksl_shift_right(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) { assert(i < blk->n - 1); - lnode = ksl_nth_node(ksl, blk, i); - rnode = ksl_nth_node(ksl, blk, i + 1); + lnode = ngtcp2_ksl_nth_node(ksl, blk, i); + rnode = ngtcp2_ksl_nth_node(ksl, blk, i + 1); assert(lnode->blk->n > NGTCP2_KSL_MIN_NBLK); assert(rnode->blk->n < NGTCP2_KSL_MAX_NBLK); @@ -452,14 +427,14 @@ static void ksl_shift_right(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) { ksl->nodelen * rnode->blk->n); ++rnode->blk->n; - dest = ksl_nth_node(ksl, rnode->blk, 0); - src = ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1); + dest = ngtcp2_ksl_nth_node(ksl, rnode->blk, 0); + src = ngtcp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1); memcpy(dest, src, ksl->nodelen); --lnode->blk->n; - ksl_node_set_key(ksl, lnode, - &ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key); + ksl_node_set_key( + ksl, lnode, ngtcp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key); } /* @@ -478,8 +453,8 @@ void ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it, size_t i; if (!blk->leaf && blk->n == 2 && - ksl_nth_node(ksl, blk, 0)->blk->n == NGTCP2_KSL_MIN_NBLK && - ksl_nth_node(ksl, blk, 1)->blk->n == NGTCP2_KSL_MIN_NBLK) { + ngtcp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGTCP2_KSL_MIN_NBLK && + ngtcp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGTCP2_KSL_MIN_NBLK) { blk = ksl_merge_node(ksl, ksl->head, 0); } @@ -502,15 +477,18 @@ void ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it, return; } - node = ksl_nth_node(ksl, blk, i); + node = ngtcp2_ksl_nth_node(ksl, blk, i); if (node->blk->n == NGTCP2_KSL_MIN_NBLK) { if (i > 0 && - ksl_nth_node(ksl, blk, i - 1)->blk->n > NGTCP2_KSL_MIN_NBLK) { + ngtcp2_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGTCP2_KSL_MIN_NBLK) { ksl_shift_right(ksl, blk, i - 1); + blk = node->blk; } else if (i + 1 < blk->n && - ksl_nth_node(ksl, blk, i + 1)->blk->n > NGTCP2_KSL_MIN_NBLK) { + ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk->n > + NGTCP2_KSL_MIN_NBLK) { ksl_shift_left(ksl, blk, i + 1); + blk = node->blk; } else if (i > 0) { blk = ksl_merge_node(ksl, blk, i - 1); } else { @@ -544,7 +522,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound(ngtcp2_ksl *ksl, if (i == blk->n) { /* This happens if descendant has smaller key. Fast forward to find last node in this subtree. */ - for (; !blk->leaf; blk = ksl_nth_node(ksl, blk, blk->n - 1)->blk) + for (; !blk->leaf; blk = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk) ; if (blk->next) { blk = blk->next; @@ -555,7 +533,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound(ngtcp2_ksl *ksl, ngtcp2_ksl_it_init(&it, ksl, blk, i); return it; } - blk = ksl_nth_node(ksl, blk, i)->blk; + blk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk; } } @@ -581,7 +559,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_compar(ngtcp2_ksl *ksl, if (i == blk->n) { /* This happens if descendant has smaller key. Fast forward to find last node in this subtree. */ - for (; !blk->leaf; blk = ksl_nth_node(ksl, blk, blk->n - 1)->blk) + for (; !blk->leaf; blk = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk) ; if (blk->next) { blk = blk->next; @@ -592,7 +570,7 @@ ngtcp2_ksl_it ngtcp2_ksl_lower_bound_compar(ngtcp2_ksl *ksl, ngtcp2_ksl_it_init(&it, ksl, blk, i); return it; } - blk = ksl_nth_node(ksl, blk, i)->blk; + blk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk; } } @@ -600,25 +578,23 @@ void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key, const ngtcp2_ksl_key *new_key) { ngtcp2_ksl_blk *blk = ksl->head; ngtcp2_ksl_node *node; - ngtcp2_ksl_key node_key; size_t i; for (;;) { i = ksl_bsearch(ksl, blk, old_key, ksl->compar); assert(i < blk->n); - node = ksl_nth_node(ksl, blk, i); + node = ngtcp2_ksl_nth_node(ksl, blk, i); if (blk->leaf) { - assert(key_equal(ksl->compar, ksl_node_key(&node_key, node), old_key)); - ksl_node_set_key(ksl, node, new_key->ptr); + assert(key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key)); + ksl_node_set_key(ksl, node, new_key); return; } - ksl_node_key(&node_key, node); - if (key_equal(ksl->compar, &node_key, old_key) || - ksl->compar(&node_key, new_key)) { - ksl_node_set_key(ksl, node, new_key->ptr); + if (key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key) || + ksl->compar((ngtcp2_ksl_key *)node->key, new_key)) { + ksl_node_set_key(ksl, node, new_key); } blk = node->blk; @@ -628,21 +604,20 @@ void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key, static void ksl_print(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t level) { size_t i; ngtcp2_ksl_node *node; - ngtcp2_ksl_key node_key; fprintf(stderr, "LV=%zu n=%zu\n", level, blk->n); if (blk->leaf) { for (i = 0; i < blk->n; ++i) { - node = ksl_nth_node(ksl, blk, i); - fprintf(stderr, " %" PRId64, *ksl_node_key(&node_key, node)->i); + node = ngtcp2_ksl_nth_node(ksl, blk, i); + fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key); } fprintf(stderr, "\n"); return; } for (i = 0; i < blk->n; ++i) { - ksl_print(ksl, ksl_nth_node(ksl, blk, i)->blk, level + 1); + ksl_print(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk, level + 1); } } @@ -654,7 +629,7 @@ void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) { if (!ksl->head->leaf) { for (i = 0; i < ksl->head->n; ++i) { - ksl_free_blk(ksl, ksl_nth_node(ksl, ksl->head, i)->blk); + ksl_free_blk(ksl, ngtcp2_ksl_nth_node(ksl, ksl->head, i)->blk); } } @@ -691,16 +666,7 @@ void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl, void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it) { assert(it->i < it->blk->n); - return ksl_nth_node(it->ksl, it->blk, it->i)->data; -} - -void ngtcp2_ksl_it_next(ngtcp2_ksl_it *it) { - assert(!ngtcp2_ksl_it_end(it)); - - if (++it->i == it->blk->n && it->blk->next) { - it->blk = it->blk->next; - it->i = 0; - } + return ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->data; } void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it) { @@ -714,36 +680,19 @@ void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it) { } } -int ngtcp2_ksl_it_end(const ngtcp2_ksl_it *it) { - return it->blk->n == it->i && it->blk->next == NULL; -} - int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it) { return it->i == 0 && it->blk->prev == NULL; } -ngtcp2_ksl_key ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it) { - ngtcp2_ksl_key node_key; - - assert(it->i < it->blk->n); - - return *ksl_node_key(&node_key, ksl_nth_node(it->ksl, it->blk, it->i)); -} - -ngtcp2_ksl_key *ngtcp2_ksl_key_ptr(ngtcp2_ksl_key *key, const void *ptr) { - key->ptr = ptr; - return key; -} - int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { - const ngtcp2_range *a = lhs->ptr, *b = rhs->ptr; + const ngtcp2_range *a = lhs, *b = rhs; return a->begin < b->begin; } int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { - const ngtcp2_range *a = lhs->ptr, *b = rhs->ptr; + const ngtcp2_range *a = lhs, *b = rhs; return a->begin < b->begin && !(ngtcp2_max(a->begin, b->begin) < ngtcp2_min(a->end, b->end)); } diff --git a/deps/ngtcp2/lib/ngtcp2_ksl.h b/deps/ngtcp2/lib/ngtcp2_ksl.h index c9ce128a2209b2..ae8bb8de5b5bf1 100644 --- a/deps/ngtcp2/lib/ngtcp2_ksl.h +++ b/deps/ngtcp2/lib/ngtcp2_ksl.h @@ -37,7 +37,7 @@ * Skip List using single key instead of range. */ -#define NGTCP2_KSL_DEGR 8 +#define NGTCP2_KSL_DEGR 16 /* NGTCP2_KSL_MAX_NBLK is the maximum number of nodes which a single block can contain. */ #define NGTCP2_KSL_MAX_NBLK (2 * NGTCP2_KSL_DEGR - 1) @@ -48,12 +48,7 @@ /* * ngtcp2_ksl_key represents key in ngtcp2_ksl. */ -typedef union { - /* i is defined to retrieve int64_t key for convenience. */ - const int64_t *i; - /* ptr points to the key. */ - const void *ptr; -} ngtcp2_ksl_key; +typedef void ngtcp2_ksl_key; struct ngtcp2_ksl_node; typedef struct ngtcp2_ksl_node ngtcp2_ksl_node; @@ -246,11 +241,10 @@ size_t ngtcp2_ksl_len(ngtcp2_ksl *ksl); void ngtcp2_ksl_clear(ngtcp2_ksl *ksl); /* - * ngtcp2_ksl_nth_node returns the |n|th node under |blk|. This - * function is provided for unit testing. + * ngtcp2_ksl_nth_node returns the |n|th node under |blk|. */ -ngtcp2_ksl_node *ngtcp2_ksl_nth_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, - size_t n); +#define ngtcp2_ksl_nth_node(KSL, BLK, N) \ + ((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) /* * ngtcp2_ksl_print prints its internal state in stderr. It assumes @@ -277,7 +271,10 @@ void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it); * if this function is called when ngtcp2_ksl_it_end(it) returns * nonzero. */ -void ngtcp2_ksl_it_next(ngtcp2_ksl_it *it); +#define ngtcp2_ksl_it_next(IT) \ + (++(IT)->i == (IT)->blk->n && (IT)->blk->next \ + ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \ + : 0) /* * ngtcp2_ksl_it_prev moves backward the iterator by one. It is @@ -290,7 +287,8 @@ void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it); * ngtcp2_ksl_it_end returns nonzero if |it| points to the beyond the * last node. */ -int ngtcp2_ksl_it_end(const ngtcp2_ksl_it *it); +#define ngtcp2_ksl_it_end(IT) \ + ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL) /* * ngtcp2_ksl_it_begin returns nonzero if |it| points to the first @@ -304,13 +302,8 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it); * It is undefined to call this function when ngtcp2_ksl_it_end(it) * returns nonzero. */ -ngtcp2_ksl_key ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it); - -/* - * ngtcp2_ksl_key_ptr is a convenient function which initializes |key| - * with |ptr| and returns |key|. - */ -ngtcp2_ksl_key *ngtcp2_ksl_key_ptr(ngtcp2_ksl_key *key, const void *ptr); +#define ngtcp2_ksl_it_key(IT) \ + ((ngtcp2_ksl_key *)ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key) /* * ngtcp2_ksl_range_compar is an implementation of ngtcp2_ksl_compar. diff --git a/deps/ngtcp2/lib/ngtcp2_log.c b/deps/ngtcp2/lib/ngtcp2_log.c index 11f335d974c3eb..8b7ec0def65baf 100644 --- a/deps/ngtcp2/lib/ngtcp2_log.c +++ b/deps/ngtcp2/lib/ngtcp2_log.c @@ -29,7 +29,6 @@ # include #endif #include -#include #include #include "ngtcp2_str.h" @@ -115,8 +114,8 @@ static const char *strerrorcode(uint64_t error_code) { return "NO_ERROR"; case NGTCP2_INTERNAL_ERROR: return "INTERNAL_ERROR"; - case NGTCP2_SERVER_BUSY: - return "SERVER_BUSY"; + case NGTCP2_CONNECTION_REFUSED: + return "CONNECTION_REFUSED"; case NGTCP2_FLOW_CONTROL_ERROR: return "FLOW_CONTROL_ERROR"; case NGTCP2_STREAM_LIMIT_ERROR: @@ -135,6 +134,8 @@ static const char *strerrorcode(uint64_t error_code) { return "PROTOCOL_VIOLATION"; case NGTCP2_INVALID_TOKEN: return "INVALID_TOKEN"; + case NGTCP2_APPLICATION_ERROR: + return "APPLICATION_ERROR"; case NGTCP2_CRYPTO_BUFFER_EXCEEDED: return "CRYPTO_BUFFER_EXCEEDED"; case NGTCP2_KEY_UPDATE_ERROR: @@ -200,13 +201,13 @@ static uint64_t timestamp_cast(uint64_t ns) { return ns / NGTCP2_MILLISECONDS; } 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_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); + log->log_printf(log->user_data, + (NGTCP2_LOG_PKT " STREAM(0x%02x) id=0x%" PRIx64 + " fin=%d offset=%" PRIu64 " len=%zu 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); } static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -245,8 +246,7 @@ 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=%" PRIu64), + log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PADDING(0x%02x) len=%zu"), NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->len); } @@ -270,7 +270,7 @@ static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log->log_printf(log->user_data, (NGTCP2_LOG_PKT " CONNECTION_CLOSE(0x%02x) error_code=%s(0x%" PRIx64 ") " - "frame_type=%" PRIx64 " reason_len=%" PRIu64 " reason=[%s]"), + "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) @@ -323,7 +323,8 @@ static void log_fr_stream_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, log->log_printf(log->user_data, (NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02x) id=0x%" PRIx64 " offset=%" PRIu64), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->stream_id, fr->offset); + NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id, + fr->offset); } static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -407,17 +408,16 @@ 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->tokenlen > 64) { - p = ngtcp2_encode_hex(buf, fr->token, 64); + if (fr->token.len > 64) { + p = ngtcp2_encode_hex(buf, fr->token.base, 64); p[128] = '*'; p[129] = '\0'; } else { - p = ngtcp2_encode_hex(buf, fr->token, fr->tokenlen); + p = ngtcp2_encode_hex(buf, fr->token.base, fr->token.len); } log->log_printf( - log->user_data, - (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02x) token=0x%s token_len=%zu"), - NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, fr->tokenlen); + 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); } static void log_fr_retire_connection_id(ngtcp2_log *log, @@ -615,40 +615,57 @@ void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype, sizeof(params->preferred_address.stateless_reset_token))); } - if (params->original_connection_id_present) { - log->log_printf(log->user_data, - (NGTCP2_LOG_TP " original_connection_id=0x%s"), - NGTCP2_LOG_TP_HD_FIELDS, - (const char *)ngtcp2_encode_hex( - cid, params->original_connection_id.data, - params->original_connection_id.datalen)); + 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)); } } log->log_printf( - log->user_data, (NGTCP2_LOG_TP " initial_max_stream_data_bidi_local=%u"), + 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, + (NGTCP2_LOG_TP " initial_max_stream_data_bidi_local=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_local); log->log_printf( - log->user_data, (NGTCP2_LOG_TP " initial_max_stream_data_bidi_remote=%u"), + log->user_data, + (NGTCP2_LOG_TP " initial_max_stream_data_bidi_remote=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_remote); log->log_printf(log->user_data, - (NGTCP2_LOG_TP " initial_max_stream_data_uni=%u"), + (NGTCP2_LOG_TP " initial_max_stream_data_uni=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_uni); - log->log_printf(log->user_data, (NGTCP2_LOG_TP " initial_max_data=%u"), + log->log_printf(log->user_data, (NGTCP2_LOG_TP " initial_max_data=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_data); log->log_printf(log->user_data, - (NGTCP2_LOG_TP " initial_max_bidi_streams=%u"), + (NGTCP2_LOG_TP " initial_max_bidi_streams=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_bidi); - log->log_printf(log->user_data, (NGTCP2_LOG_TP " initial_max_uni_streams=%u"), + log->log_printf(log->user_data, + (NGTCP2_LOG_TP " initial_max_uni_streams=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_uni); - log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_idle_timeout=%u"), + log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_idle_timeout=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->max_idle_timeout / NGTCP2_MILLISECONDS); - log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_packet_size=%u"), - NGTCP2_LOG_TP_HD_FIELDS, params->max_packet_size); - log->log_printf(log->user_data, (NGTCP2_LOG_TP " ack_delay_exponent=%u"), + log->log_printf(log->user_data, + (NGTCP2_LOG_TP " max_udp_payload_size=%" PRIu64), + NGTCP2_LOG_TP_HD_FIELDS, params->max_udp_payload_size); + log->log_printf(log->user_data, + (NGTCP2_LOG_TP " ack_delay_exponent=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->ack_delay_exponent); - log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_ack_delay=%u"), + log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_ack_delay=%" PRIu64), NGTCP2_LOG_TP_HD_FIELDS, params->max_ack_delay / NGTCP2_MILLISECONDS); log->log_printf(log->user_data, diff --git a/deps/ngtcp2/lib/ngtcp2_log.h b/deps/ngtcp2/lib/ngtcp2_log.h index bb9737e354b019..985aa84b2711f8 100644 --- a/deps/ngtcp2/lib/ngtcp2_log.h +++ b/deps/ngtcp2/lib/ngtcp2_log.h @@ -33,22 +33,6 @@ #include "ngtcp2_pkt.h" -typedef enum { - NGTCP2_LOG_EVENT_NONE, - /* connection (catch-all) event */ - NGTCP2_LOG_EVENT_CON, - /* packet event */ - NGTCP2_LOG_EVENT_PKT, - /* frame event */ - NGTCP2_LOG_EVENT_FRM, - /* recovery event */ - NGTCP2_LOG_EVENT_RCV, - /* crypto event */ - NGTCP2_LOG_EVENT_CRY, - /* path validation event */ - NGTCP2_LOG_EVENT_PTV, -} ngtcp2_log_event; - struct ngtcp2_log { /* log_printf is a sink to write log. NULL means no logging output. */ @@ -76,9 +60,6 @@ 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); -void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt, - ...); - void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const uint32_t *sv, size_t nsv); diff --git a/deps/ngtcp2/lib/ngtcp2_net.h b/deps/ngtcp2/lib/ngtcp2_net.h deleted file mode 100644 index 9c121ea7f21547..00000000000000 --- a/deps/ngtcp2/lib/ngtcp2_net.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2019 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_NET_H -#define NGTCP2_NET_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#ifdef HAVE_ARPA_INET_H -# include -#endif /* HAVE_ARPA_INET_H */ - -#ifdef HAVE_NETINET_IN_H -# include -#endif /* HAVE_NETINET_IN_H */ - -#include - -#if defined(WIN32) -/* Windows requires ws2_32 library for ntonl family functions. We - define inline functions for those function so that we don't have - dependeny on that lib. */ - -# ifdef _MSC_VER -# define STIN static __inline -# else -# define STIN static inline -# endif - -STIN uint32_t htonl(uint32_t hostlong) { - uint32_t res; - unsigned char *p = (unsigned char *)&res; - *p++ = hostlong >> 24; - *p++ = (hostlong >> 16) & 0xffu; - *p++ = (hostlong >> 8) & 0xffu; - *p = hostlong & 0xffu; - return res; -} - -STIN uint16_t htons(uint16_t hostshort) { - uint16_t res; - unsigned char *p = (unsigned char *)&res; - *p++ = hostshort >> 8; - *p = hostshort & 0xffu; - return res; -} - -STIN uint32_t ntohl(uint32_t netlong) { - uint32_t res; - unsigned char *p = (unsigned char *)&netlong; - res = *p++ << 24; - res += *p++ << 16; - res += *p++ << 8; - res += *p; - return res; -} - -STIN uint16_t ntohs(uint16_t netshort) { - uint16_t res; - unsigned char *p = (unsigned char *)&netshort; - res = *p++ << 8; - res += *p; - return res; -} - -#endif /* WIN32 */ - -#endif /* NGTCP2_NET_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_pipeack.c b/deps/ngtcp2/lib/ngtcp2_pipeack.c deleted file mode 100644 index f44bdf07bbb485..00000000000000 --- a/deps/ngtcp2/lib/ngtcp2_pipeack.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2019 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_pipeack.h" - -#include - -#include "ngtcp2_macro.h" -#include "ngtcp2_rcvry.h" - -void ngtcp2_pipeack_init(ngtcp2_pipeack *pipeack, ngtcp2_tstamp ts) { - ngtcp2_pipeack_sample *sample; - - memset(pipeack, 0, sizeof(*pipeack)); - - /* Initialize value to UINT64_MAX so that it does not restrict CWND - growth. It serves as "undefined" value. */ - pipeack->value = UINT64_MAX; - pipeack->ts = ts; - pipeack->len = 1; - - sample = &pipeack->samples[pipeack->pos]; - sample->value = 0; - sample->ts = ts; -} - -static ngtcp2_duration get_rtt(const ngtcp2_rcvry_stat *rcs) { - if (rcs->smoothed_rtt == 0) { - return NGTCP2_DEFAULT_INITIAL_RTT; - } - return rcs->smoothed_rtt; -} - -/* - * compute_sampling_period returns pipeACK sampling period. - */ -static ngtcp2_duration compute_sampling_period(ngtcp2_duration rtt) { - return ngtcp2_max(rtt * 3, NGTCP2_SECONDS); -} - -/* - * compute_measurement_period returns the measurement period using - * pipeACK sampling period |speriod|. - */ -static ngtcp2_duration compute_measurement_period(ngtcp2_duration speriod) { - return speriod / NGTCP2_PIPEACK_NUM_SAMPLES; -} - -static void pipeack_update_sample(ngtcp2_pipeack *pipeack, uint64_t acked_bytes, - const ngtcp2_rcvry_stat *rcs, - ngtcp2_tstamp ts) { - ngtcp2_pipeack_sample *sample; - ngtcp2_duration rtt = get_rtt(rcs); - ngtcp2_duration speriod = compute_sampling_period(rtt); - ngtcp2_duration mperiod = compute_measurement_period(speriod); - - if (pipeack->len == 0) { - pipeack->len = 1; - - sample = &pipeack->samples[pipeack->pos]; - sample->ts = ts; - sample->value = acked_bytes; - - return; - } - - sample = &pipeack->samples[pipeack->pos]; - if (sample->ts + mperiod <= ts) { - ts = sample->ts + (ts - sample->ts) / mperiod * mperiod; - pipeack->pos = (pipeack->pos - 1) & (NGTCP2_PIPEACK_NUM_SAMPLES - 1); - - if (pipeack->len < NGTCP2_PIPEACK_NUM_SAMPLES) { - ++pipeack->len; - } - - sample = &pipeack->samples[pipeack->pos]; - sample->ts = ts; - sample->value = acked_bytes; - - return; - } - - sample->value = ngtcp2_max(sample->value, acked_bytes); -} - -void ngtcp2_pipeack_update(ngtcp2_pipeack *pipeack, uint64_t acked_bytes, - const ngtcp2_rcvry_stat *rcs, ngtcp2_tstamp ts) { - uint64_t value; - ngtcp2_duration d = ts - pipeack->ts; - ngtcp2_duration rtt = get_rtt(rcs); - - pipeack->acked_bytes += acked_bytes; - - if (d < rtt) { - return; - } - - value = pipeack->acked_bytes * rtt / d; - pipeack->acked_bytes = 0; - pipeack->ts = ts; - - pipeack_update_sample(pipeack, value, rcs, ts); -} - -void ngtcp2_pipeack_update_value(ngtcp2_pipeack *pipeack, - const ngtcp2_rcvry_stat *rcs, - ngtcp2_tstamp ts) { - ngtcp2_pipeack_sample *sample; - ngtcp2_duration rtt = get_rtt(rcs); - ngtcp2_duration speriod = compute_sampling_period(rtt); - ngtcp2_duration mperiod = compute_measurement_period(speriod); - size_t i; - uint64_t res = 0; - - for (i = pipeack->len; i > 0; --i) { - sample = &pipeack->samples[(pipeack->pos + i - 1) & - (NGTCP2_PIPEACK_NUM_SAMPLES - 1)]; - if (sample->ts + speriod <= ts) { - --pipeack->len; - continue; - } - if (sample->ts + mperiod > ts) { - break; - } - - res = ngtcp2_max(res, sample->value); - } - - if (res == 0) { - pipeack->value = UINT64_MAX; - } else { - pipeack->value = res; - } -} diff --git a/deps/ngtcp2/lib/ngtcp2_pipeack.h b/deps/ngtcp2/lib/ngtcp2_pipeack.h deleted file mode 100644 index d7a34a936bbb57..00000000000000 --- a/deps/ngtcp2/lib/ngtcp2_pipeack.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2019 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_PIPEACK_H -#define NGTCP2_PIPEACK_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -typedef struct ngtcp2_pipeack_sample { - /* - * value is the maximum cumulative acknowledged bytes per RTT in - * this sample. - */ - uint64_t value; - /* ts is the time when this sample started. */ - ngtcp2_tstamp ts; -} ngtcp2_pipeack_sample; - -#define NGTCP2_PIPEACK_NUM_SAMPLES 4 - -/* - * ngtcp2_pipeack implements pipeACK measurement described in RFC - * 7661. - */ -typedef struct ngtcp2_pipeack { - /* value is the pre-computed maximum pipeACK value in the effective - sample period. */ - uint64_t value; - /* acked_bytes is the accumulated acked_bytes per RTT. */ - uint64_t acked_bytes; - /* ts is the timestamp when the accumulation to acked_bytes - started. */ - ngtcp2_tstamp ts; - /* pos points to the latest sample in samples. */ - size_t pos; - /* len is the number of effective from pos. samples is treated as - ring buffer and its index will wrap when pos + len goes beyond - NGTCP2_PIPEACK_NUM_SAMPLES - 1. */ - size_t len; - ngtcp2_pipeack_sample samples[NGTCP2_PIPEACK_NUM_SAMPLES]; -} ngtcp2_pipeack; - -/* - * ngtcp2_pipeack_init initializes the object pointed by |pipeack|. - */ -void ngtcp2_pipeack_init(ngtcp2_pipeack *pipeack, ngtcp2_tstamp ts); - -/* - * ngtcp2_pipeack_update notifies the acknowledged bytes |acked_bytes| - * to |pipeack|. - */ -void ngtcp2_pipeack_update(ngtcp2_pipeack *pipeack, uint64_t acked_bytes, - const ngtcp2_rcvry_stat *rcs, ngtcp2_tstamp ts); - -/* - * ngtcp2_pipeack_update_value computes maximum pipeACK value. - * Samples which have timestamp <= |ts| - pipeACK sampling period are - * discarded. - */ -void ngtcp2_pipeack_update_value(ngtcp2_pipeack *pipeack, - const ngtcp2_rcvry_stat *rcs, - ngtcp2_tstamp ts); - -#endif /* NGTCP2_PIPEACK_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_pkt.c b/deps/ngtcp2/lib/ngtcp2_pkt.c index 059022bf2ca8d0..a67a376d364fd9 100644 --- a/deps/ngtcp2/lib/ngtcp2_pkt.c +++ b/deps/ngtcp2/lib/ngtcp2_pkt.c @@ -141,8 +141,8 @@ 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 = NULL; - hd->tokenlen = 0; + hd->token.base = NULL; + hd->token.len = 0; hd->pkt_numlen = pkt_numlen; hd->version = version; hd->len = len; @@ -161,6 +161,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t ntokenlen = 0; const uint8_t *token = NULL; size_t tokenlen = 0; + uint64_t vi; if (pktlen < 5) { return NGTCP2_ERR_INVALID_ARGUMENT; @@ -241,12 +242,12 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, return NGTCP2_ERR_INVALID_ARGUMENT; } - tokenlen = ngtcp2_get_varint(&ntokenlen, p); - len += tokenlen; - - if (pktlen < len) { + vi = ngtcp2_get_varint(&ntokenlen, p); + if (pktlen - len < vi) { return NGTCP2_ERR_INVALID_ARGUMENT; } + tokenlen = (size_t)vi; + len += tokenlen; p += ntokenlen; @@ -283,8 +284,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 = (uint8_t *)token; - dest->tokenlen = tokenlen; + dest->token.base = (uint8_t *)token; + dest->token.len = tokenlen; p += ntokenlen + tokenlen; switch (type) { @@ -293,7 +294,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, dest->len = 0; break; default: - dest->len = ngtcp2_get_varint(&n, p); + vi = ngtcp2_get_varint(&n, p); + if (vi > SIZE_MAX) { + return NGTCP2_ERR_INVALID_ARGUMENT; + } + dest->len = (size_t)vi; p += n; } @@ -352,7 +357,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->tokenlen) + hd->tokenlen; + len += ngtcp2_put_varint_len(hd->token.len) + hd->token.len; } if (outlen < len) { @@ -374,9 +379,9 @@ 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->tokenlen); - if (hd->tokenlen) { - p = ngtcp2_cpymem(p, hd->token, hd->tokenlen); + p = ngtcp2_put_varint(p, hd->token.len); + if (hd->token.len) { + p = ngtcp2_cpymem(p, hd->token.base, hd->token.len); } } @@ -504,6 +509,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, size_t datalen; size_t ndatalen = 0; size_t n; + uint64_t vi; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -551,12 +557,12 @@ ngtcp2_ssize ngtcp2_pkt_decode_stream_frame(ngtcp2_stream *dest, return NGTCP2_ERR_FRAME_ENCODING; } - datalen = ngtcp2_get_varint(&ndatalen, p); - len += datalen; - - if (payloadlen < len) { + vi = ngtcp2_get_varint(&ndatalen, p); + if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } + datalen = (size_t)vi; + len += datalen; } else { len = payloadlen; } @@ -607,6 +613,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, ngtcp2_ack_blk *blk; size_t n; uint8_t type; + uint64_t vi; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -644,13 +651,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_ack_frame(ngtcp2_ack *dest, return NGTCP2_ERR_FRAME_ENCODING; } - num_blks = ngtcp2_get_varint(&nnum_blks, p); - len += num_blks * (1 + 1); - - if (payloadlen < len) { + vi = ngtcp2_get_varint(&nnum_blks, 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; /* First ACK Block */ @@ -810,6 +818,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( size_t nreasonlen; size_t n; uint8_t type; + uint64_t vi; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -845,12 +854,12 @@ ngtcp2_ssize ngtcp2_pkt_decode_connection_close_frame( return NGTCP2_ERR_FRAME_ENCODING; } - reasonlen = ngtcp2_get_varint(&nreasonlen, p); - len += reasonlen; - - if (payloadlen < len) { + vi = ngtcp2_get_varint(&nreasonlen, p); + if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } + reasonlen = (size_t)vi; + len += reasonlen; p = payload + 1; @@ -1232,6 +1241,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, size_t datalen; size_t ndatalen; size_t n; + uint64_t vi; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -1255,13 +1265,14 @@ ngtcp2_ssize ngtcp2_pkt_decode_crypto_frame(ngtcp2_crypto *dest, return NGTCP2_ERR_FRAME_ENCODING; } - datalen = ngtcp2_get_varint(&ndatalen, p); - len += datalen; - - if (payloadlen < len) { + vi = ngtcp2_get_varint(&ndatalen, p); + if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } + datalen = (size_t)vi; + len += datalen; + p = payload + 1; dest->type = NGTCP2_FRAME_CRYPTO; @@ -1290,6 +1301,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_token_frame(ngtcp2_new_token *dest, const uint8_t *p; size_t n; size_t datalen; + uint64_t vi; if (payloadlen < len) { return NGTCP2_ERR_FRAME_ENCODING; @@ -1304,18 +1316,18 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_token_frame(ngtcp2_new_token *dest, return NGTCP2_ERR_FRAME_ENCODING; } - datalen = ngtcp2_get_varint(&n, p); - len += datalen; - - if (payloadlen < len) { + vi = ngtcp2_get_varint(&n, p); + if (payloadlen - len < vi) { return NGTCP2_ERR_FRAME_ENCODING; } + datalen = (size_t)vi; + len += datalen; dest->type = NGTCP2_FRAME_NEW_TOKEN; - dest->tokenlen = datalen; + dest->token.len = datalen; p += n; - dest->token = p; - p += dest->tokenlen; + dest->token.base = (uint8_t *)p; + p += dest->token.len; assert((size_t)(p - payload) == len); @@ -1844,9 +1856,11 @@ 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->tokenlen) + fr->tokenlen; + size_t len = 1 + ngtcp2_put_varint_len(fr->token.len) + fr->token.len; uint8_t *p; + assert(fr->token.len); + if (outlen < len) { return NGTCP2_ERR_NOBUF; } @@ -1855,10 +1869,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->tokenlen); - if (fr->tokenlen) { - p = ngtcp2_cpymem(p, fr->token, fr->tokenlen); - } + p = ngtcp2_put_varint(p, fr->token.len); + p = ngtcp2_cpymem(p, fr->token.base, fr->token.len); assert((size_t)(p - out) == len); @@ -1976,9 +1988,9 @@ int ngtcp2_pkt_decode_retry(ngtcp2_pkt_retry *dest, const uint8_t *payload, return NGTCP2_ERR_INVALID_ARGUMENT; } - dest->token = payload; - dest->tokenlen = (size_t)(payloadlen - NGTCP2_RETRY_TAGLEN); - ngtcp2_cpymem(dest->tag, payload + dest->tokenlen, NGTCP2_RETRY_TAGLEN); + 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); return 0; } @@ -2055,9 +2067,9 @@ ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen, } static const uint8_t retry_key[] = - "\x4d\x32\xec\xdb\x2a\x21\x33\xc8\x41\xe4\x04\x3d\xf2\x7d\x44\x30"; + "\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1"; static const uint8_t retry_nonce[] = - "\x4d\x16\x11\xd0\x55\x13\xa5\x52\xc5\x87\xd5\x75"; + "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c"; ngtcp2_ssize ngtcp2_pkt_write_retry(uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid, @@ -2194,7 +2206,9 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, left -= n; if (left > 8 + 1073741823 && len > 1073741823) { +#if SIZE_MAX > UINT32_MAX len = ngtcp2_min(len, 4611686018427387903lu); +#endif /* SIZE_MAX > UINT32_MAX */ return ngtcp2_min(len, left - 8); } @@ -2222,7 +2236,9 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { left -= n; if (left > 8 + 1073741823 && len > 1073741823) { +#if SIZE_MAX > UINT32_MAX len = ngtcp2_min(len, 4611686018427387903lu); +#endif /* SIZE_MAX > UINT32_MAX */ return ngtcp2_min(len, left - 8); } @@ -2241,7 +2257,7 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { } uint8_t ngtcp2_pkt_get_type_long(uint8_t c) { - return (c & NGTCP2_LONG_TYPE_MASK) >> 4; + return (uint8_t)((c & NGTCP2_LONG_TYPE_MASK) >> 4); } int ngtcp2_pkt_verify_reserved_bits(uint8_t c) { diff --git a/deps/ngtcp2/lib/ngtcp2_pkt.h b/deps/ngtcp2/lib/ngtcp2_pkt.h index 962218057afcca..caf4152c045558 100644 --- a/deps/ngtcp2/lib/ngtcp2_pkt.h +++ b/deps/ngtcp2/lib/ngtcp2_pkt.h @@ -89,7 +89,7 @@ /* 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 255 +#define NGTCP2_MAX_ACK_BLKS 32 /* NGTCP2_MAX_PKT_NUM is the maximum packet number. */ #define NGTCP2_MAX_PKT_NUM ((int64_t)((1ll << 62) - 1)) @@ -99,6 +99,15 @@ Reset. */ #define NGTCP2_MIN_PKT_EXPANDLEN 22 +/* NGTCP2_RETRY_TAGLEN is the length of Retry packet integrity tag. */ +#define NGTCP2_RETRY_TAGLEN 16 + +typedef struct ngtcp2_pkt_retry { + ngtcp2_cid odcid; + ngtcp2_vec token; + uint8_t tag[NGTCP2_RETRY_TAGLEN]; +} ngtcp2_pkt_retry; + typedef enum { NGTCP2_FRAME_PADDING = 0x00, NGTCP2_FRAME_PING = 0x01, @@ -155,8 +164,7 @@ typedef struct { uint64_t ack_delay; /** * ack_delay_unscaled is an ack_delay multiplied by - * 2**ack_delay_component * NGTCP2_DURATION_TICK / - * NGTCP2_MICROSECONDS. + * 2**ack_delay_component * NGTCP2_MICROSECONDS. */ ngtcp2_duration ack_delay_unscaled; uint64_t first_ack_blklen; @@ -263,8 +271,7 @@ typedef struct { typedef struct { uint8_t type; - size_t tokenlen; - const uint8_t *token; + ngtcp2_vec token; } ngtcp2_new_token; typedef struct { diff --git a/deps/ngtcp2/lib/ngtcp2_ppe.c b/deps/ngtcp2/lib/ngtcp2_ppe.c index e4aab22ca33f83..c1856d0fe092e7 100644 --- a/deps/ngtcp2/lib/ngtcp2_ppe.c +++ b/deps/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->tokenlen) + hd->tokenlen; + ppe->len_offset += ngtcp2_put_varint_len(hd->token.len) + hd->token.len; } ppe->pkt_num_offset = ppe->len_offset + 2; rv = ngtcp2_pkt_encode_hd_long( diff --git a/deps/ngtcp2/lib/ngtcp2_psl.c b/deps/ngtcp2/lib/ngtcp2_psl.c deleted file mode 100644 index 54a8e894d503a3..00000000000000 --- a/deps/ngtcp2/lib/ngtcp2_psl.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2018 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_psl.h" - -#include -#include -#include -#include - -#include "ngtcp2_macro.h" -#include "ngtcp2_mem.h" - -int ngtcp2_psl_init(ngtcp2_psl *psl, const ngtcp2_mem *mem) { - ngtcp2_psl_blk *head; - - psl->mem = mem; - psl->head = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_psl_blk)); - if (!psl->head) { - return NGTCP2_ERR_NOMEM; - } - psl->front = psl->head; - psl->n = 0; - - head = psl->head; - - head->next = NULL; - head->n = 1; - head->leaf = 1; - head->nodes[0].range.begin = UINT64_MAX; - head->nodes[0].range.end = UINT64_MAX; - head->nodes[0].data = NULL; - - return 0; -} - -/* - * free_blk frees |blk| recursively. - */ -static void free_blk(ngtcp2_psl_blk *blk, const ngtcp2_mem *mem) { - size_t i; - - if (!blk->leaf) { - for (i = 0; i < blk->n; ++i) { - free_blk(blk->nodes[i].blk, mem); - } - } - - ngtcp2_mem_free(mem, blk); -} - -void ngtcp2_psl_free(ngtcp2_psl *psl) { - if (!psl) { - return; - } - - free_blk(psl->head, psl->mem); -} - -/* - * psl_split_blk splits |blk| into 2 ngtcp2_psl_blk objects. The new - * ngtcp2_psl_blk is always the "right" block. - * - * It returns the pointer to the ngtcp2_psl_blk created which is the - * located at the right of |blk|, or NULL which indicates out of - * memory error. - */ -static ngtcp2_psl_blk *psl_split_blk(ngtcp2_psl *psl, ngtcp2_psl_blk *blk) { - ngtcp2_psl_blk *rblk; - - rblk = ngtcp2_mem_malloc(psl->mem, sizeof(ngtcp2_psl_blk)); - if (rblk == NULL) { - return NULL; - } - - rblk->next = blk->next; - blk->next = rblk; - rblk->leaf = blk->leaf; - - rblk->n = blk->n / 2; - - memcpy(rblk->nodes, &blk->nodes[blk->n - rblk->n], - sizeof(ngtcp2_psl_node) * rblk->n); - - blk->n -= rblk->n; - - assert(blk->n >= NGTCP2_PSL_MIN_NBLK); - assert(rblk->n >= NGTCP2_PSL_MIN_NBLK); - - return rblk; -} - -/* - * psl_split_node splits a node included in |blk| at the position |i| - * into 2 adjacent nodes. The new node is always inserted at the - * position |i+1|. - * - * It returns 0 if it succeeds, or one of the following negative error - * codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static int psl_split_node(ngtcp2_psl *psl, ngtcp2_psl_blk *blk, size_t i) { - ngtcp2_psl_blk *lblk = blk->nodes[i].blk, *rblk; - - rblk = psl_split_blk(psl, lblk); - if (rblk == NULL) { - return NGTCP2_ERR_NOMEM; - } - - memmove(&blk->nodes[i + 2], &blk->nodes[i + 1], - sizeof(ngtcp2_psl_node) * (blk->n - (i + 1))); - - blk->nodes[i + 1].blk = rblk; - - ++blk->n; - - blk->nodes[i].range = lblk->nodes[lblk->n - 1].range; - blk->nodes[i + 1].range = rblk->nodes[rblk->n - 1].range; - - return 0; -} - -/* - * psl_split_head splits a head (root) block. It increases the height - * of skip list by 1. - * - * It returns 0 if it succeeds, or one of the following negative error - * codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static int psl_split_head(ngtcp2_psl *psl) { - ngtcp2_psl_blk *rblk = NULL, *lblk, *nhead = NULL; - - rblk = psl_split_blk(psl, psl->head); - if (rblk == NULL) { - return NGTCP2_ERR_NOMEM; - } - - lblk = psl->head; - - nhead = ngtcp2_mem_malloc(psl->mem, sizeof(ngtcp2_psl_blk)); - if (nhead == NULL) { - ngtcp2_mem_free(psl->mem, rblk); - return NGTCP2_ERR_NOMEM; - } - nhead->next = NULL; - nhead->n = 2; - nhead->leaf = 0; - - nhead->nodes[0].range = lblk->nodes[lblk->n - 1].range; - nhead->nodes[0].blk = lblk; - nhead->nodes[1].range = rblk->nodes[rblk->n - 1].range; - nhead->nodes[1].blk = rblk; - - psl->head = nhead; - - return 0; -} - -/* - * insert_node inserts a node whose range is |range| with the - * associated |data| at the index of |i|. This function assumes that - * the number of nodes contained by |blk| is strictly less than - * NGTCP2_PSL_MAX_NBLK. - */ -static void insert_node(ngtcp2_psl_blk *blk, size_t i, - const ngtcp2_range *range, void *data) { - ngtcp2_psl_node *node; - - assert(blk->n < NGTCP2_PSL_MAX_NBLK); - - memmove(&blk->nodes[i + 1], &blk->nodes[i], - sizeof(ngtcp2_psl_node) * (blk->n - i)); - - node = &blk->nodes[i]; - node->range = *range; - node->data = data; - - ++blk->n; -} - -static int range_intersect(const ngtcp2_range *a, const ngtcp2_range *b) { - return ngtcp2_max(a->begin, b->begin) < ngtcp2_min(a->end, b->end); -} - -int ngtcp2_psl_insert(ngtcp2_psl *psl, ngtcp2_psl_it *it, - const ngtcp2_range *range, void *data) { - ngtcp2_psl_blk *blk = psl->head; - ngtcp2_psl_node *node; - size_t i; - int rv; - - if (blk->n == NGTCP2_PSL_MAX_NBLK) { - rv = psl_split_head(psl); - if (rv != 0) { - return rv; - } - blk = psl->head; - } - - for (;;) { - for (i = 0, node = &blk->nodes[i]; node->range.begin < range->begin; - ++i, ++node) - ; - - assert(!range_intersect(&node->range, range)); - - if (blk->leaf) { - insert_node(blk, i, range, data); - ++psl->n; - if (it) { - ngtcp2_psl_it_init(it, blk, i); - } - return 0; - } - - if (node->blk->n == NGTCP2_PSL_MAX_NBLK) { - rv = psl_split_node(psl, blk, i); - if (rv != 0) { - return rv; - } - if (node->range.begin < range->begin) { - node = &blk->nodes[i + 1]; - } - } - - blk = node->blk; - } -} - -/* - * remove_node removes the node included in |blk| at the index of |i|. - */ -static void remove_node(ngtcp2_psl_blk *blk, size_t i) { - memmove(&blk->nodes[i], &blk->nodes[i + 1], - sizeof(ngtcp2_psl_node) * (blk->n - (i + 1))); - - --blk->n; -} - -/* - * psl_merge_node merges 2 nodes which are the nodes at the index of - * |i| and |i + 1|. - * - * If |blk| is the direct descendant of head (root) block and the head - * block contains just 2 nodes, the merged block becomes head block, - * which decreases the height of |psl| by 1. - * - * This function returns the pointer to the merged block. - */ -static ngtcp2_psl_blk *psl_merge_node(ngtcp2_psl *psl, ngtcp2_psl_blk *blk, - size_t i) { - ngtcp2_psl_blk *lblk, *rblk; - - assert(i + 1 < blk->n); - - lblk = blk->nodes[i].blk; - rblk = blk->nodes[i + 1].blk; - - assert(lblk->n + rblk->n < NGTCP2_PSL_MAX_NBLK); - - memcpy(&lblk->nodes[lblk->n], &rblk->nodes[0], - sizeof(ngtcp2_psl_node) * rblk->n); - - lblk->n += rblk->n; - lblk->next = rblk->next; - - ngtcp2_mem_free(psl->mem, rblk); - - if (psl->head == blk && blk->n == 2) { - ngtcp2_mem_free(psl->mem, psl->head); - psl->head = lblk; - } else { - remove_node(blk, i + 1); - blk->nodes[i].range = lblk->nodes[lblk->n - 1].range; - } - - return lblk; -} - -/* - * psl_relocate_node replaces the key at the index |*pi| in - * *pblk->nodes with something other without violating contract. It - * might involve merging 2 nodes or moving a node to left or right. - * - * It assigns the index of the block in |*pblk| where the node is - * moved to |*pi|. If merging 2 nodes occurs and it becomes new head, - * the new head is assigned to |*pblk| and it still contains the key. - * The caller should handle this situation. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -static int psl_relocate_node(ngtcp2_psl *psl, ngtcp2_psl_blk **pblk, - size_t *pi) { - ngtcp2_psl_blk *blk = *pblk; - size_t i = *pi; - ngtcp2_psl_node *node = &blk->nodes[i]; - ngtcp2_psl_node *rnode = &blk->nodes[i + 1]; - size_t j; - int rv; - - assert(i + 1 < blk->n); - - if (node->blk->n == NGTCP2_PSL_MIN_NBLK && - node->blk->n + rnode->blk->n < NGTCP2_PSL_MAX_NBLK) { - j = node->blk->n - 1; - blk = psl_merge_node(psl, blk, i); - if (blk != psl->head) { - return 0; - } - *pblk = blk; - i = j; - if (blk->leaf) { - *pi = i; - return 0; - } - node = &blk->nodes[i]; - rnode = &blk->nodes[i + 1]; - - if (node->blk->n == NGTCP2_PSL_MIN_NBLK && - node->blk->n + rnode->blk->n < NGTCP2_PSL_MAX_NBLK) { - j = node->blk->n - 1; - blk = psl_merge_node(psl, blk, i); - assert(blk != psl->head); - *pi = j; - return 0; - } - } - - if (node->blk->n < rnode->blk->n) { - node->blk->nodes[node->blk->n] = rnode->blk->nodes[0]; - memmove(&rnode->blk->nodes[0], &rnode->blk->nodes[1], - sizeof(ngtcp2_psl_node) * (rnode->blk->n - 1)); - --rnode->blk->n; - ++node->blk->n; - node->range = node->blk->nodes[node->blk->n - 1].range; - *pi = i; - return 0; - } - - if (rnode->blk->n == NGTCP2_PSL_MAX_NBLK) { - rv = psl_split_node(psl, blk, i + 1); - if (rv != 0) { - return rv; - } - } - - memmove(&rnode->blk->nodes[1], &rnode->blk->nodes[0], - sizeof(ngtcp2_psl_node) * rnode->blk->n); - - rnode->blk->nodes[0] = node->blk->nodes[node->blk->n - 1]; - ++rnode->blk->n; - - --node->blk->n; - - node->range = node->blk->nodes[node->blk->n - 1].range; - - *pi = i + 1; - return 0; -} - -/* - * shift_left moves the first node in blk->nodes[i]->blk->nodes to - * blk->nodes[i - 1]->blk->nodes. - */ -static void shift_left(ngtcp2_psl_blk *blk, size_t i) { - ngtcp2_psl_node *lnode, *rnode; - - assert(i > 0); - - lnode = &blk->nodes[i - 1]; - rnode = &blk->nodes[i]; - - assert(lnode->blk->n < NGTCP2_PSL_MAX_NBLK); - assert(rnode->blk->n > NGTCP2_PSL_MIN_NBLK); - - lnode->blk->nodes[lnode->blk->n] = rnode->blk->nodes[0]; - lnode->range = lnode->blk->nodes[lnode->blk->n].range; - ++lnode->blk->n; - - --rnode->blk->n; - memmove(&rnode->blk->nodes[0], &rnode->blk->nodes[1], - sizeof(ngtcp2_psl_node) * rnode->blk->n); -} - -/* - * shift_right moves the last node in blk->nodes[i]->blk->nodes to - * blk->nodes[i + 1]->blk->nodes. - */ -static void shift_right(ngtcp2_psl_blk *blk, size_t i) { - ngtcp2_psl_node *lnode, *rnode; - - assert(i < blk->n - 1); - - lnode = &blk->nodes[i]; - rnode = &blk->nodes[i + 1]; - - assert(lnode->blk->n > NGTCP2_PSL_MIN_NBLK); - assert(rnode->blk->n < NGTCP2_PSL_MAX_NBLK); - - memmove(&rnode->blk->nodes[1], &rnode->blk->nodes[0], - sizeof(ngtcp2_psl_node) * rnode->blk->n); - ++rnode->blk->n; - rnode->blk->nodes[0] = lnode->blk->nodes[lnode->blk->n - 1]; - - --lnode->blk->n; - lnode->range = lnode->blk->nodes[lnode->blk->n - 1].range; -} - -int ngtcp2_psl_remove(ngtcp2_psl *psl, ngtcp2_psl_it *it, - const ngtcp2_range *range) { - ngtcp2_psl_blk *blk = psl->head, *lblk, *rblk; - ngtcp2_psl_node *node; - size_t i, j; - int rv; - - if (!blk->leaf && blk->n == NGTCP2_PSL_MAX_NBLK) { - rv = psl_split_head(psl); - if (rv != 0) { - return rv; - } - blk = psl->head; - } - - for (;;) { - for (i = 0, node = &blk->nodes[i]; node->range.begin < range->begin; - ++i, ++node) - ; - - if (blk->leaf) { - assert(i < blk->n); - remove_node(blk, i); - --psl->n; - if (it) { - if (blk->n == i) { - ngtcp2_psl_it_init(it, blk->next, 0); - } else { - ngtcp2_psl_it_init(it, blk, i); - } - } - return 0; - } - - if (node->blk->n == NGTCP2_PSL_MAX_NBLK) { - rv = psl_split_node(psl, blk, i); - if (rv != 0) { - return rv; - } - if (node->range.begin < range->begin) { - ++i; - node = &blk->nodes[i]; - } - } - - if (ngtcp2_range_eq(&node->range, range)) { - rv = psl_relocate_node(psl, &blk, &i); - if (rv != 0) { - return rv; - } - if (!blk->leaf) { - node = &blk->nodes[i]; - blk = node->blk; - } - } else if (node->blk->n == NGTCP2_PSL_MIN_NBLK) { - j = i == 0 ? 0 : i - 1; - - lblk = blk->nodes[j].blk; - rblk = blk->nodes[j + 1].blk; - - if (lblk->n + rblk->n < NGTCP2_PSL_MAX_NBLK) { - blk = psl_merge_node(psl, blk, j); - } else { - if (i == j) { - shift_left(blk, j + 1); - } else { - shift_right(blk, j); - } - blk = node->blk; - } - } else { - blk = node->blk; - } - } -} - -ngtcp2_psl_it ngtcp2_psl_lower_bound(ngtcp2_psl *psl, - const ngtcp2_range *range) { - ngtcp2_psl_blk *blk = psl->head; - ngtcp2_psl_node *node; - size_t i; - - for (;;) { - for (i = 0, node = &blk->nodes[i]; node->range.begin < range->begin && - !range_intersect(&node->range, range); - ++i, node = &blk->nodes[i]) - ; - - if (blk->leaf) { - ngtcp2_psl_it it = {blk, i}; - return it; - } - - blk = node->blk; - } -} - -void ngtcp2_psl_update_range(ngtcp2_psl *psl, const ngtcp2_range *old_range, - const ngtcp2_range *new_range) { - ngtcp2_psl_blk *blk = psl->head; - ngtcp2_psl_node *node; - size_t i; - - assert(old_range->begin <= new_range->begin); - assert(new_range->end <= old_range->end); - - for (;;) { - for (i = 0, node = &blk->nodes[i]; node->range.begin < old_range->begin; - ++i, node = &blk->nodes[i]) - ; - - if (blk->leaf) { - assert(ngtcp2_range_eq(&node->range, old_range)); - node->range = *new_range; - return; - } - - if (ngtcp2_range_eq(&node->range, old_range)) { - node->range = *new_range; - } else { - assert(!range_intersect(&node->range, old_range)); - } - - blk = node->blk; - } -} - -static void psl_print(ngtcp2_psl *psl, const ngtcp2_psl_blk *blk, - size_t level) { - size_t i; - - fprintf(stderr, "LV=%zu n=%zu\n", level, blk->n); - - if (blk->leaf) { - for (i = 0; i < blk->n; ++i) { - fprintf(stderr, " [%" PRIu64 ", %" PRIu64 ")", blk->nodes[i].range.begin, - blk->nodes[i].range.end); - } - fprintf(stderr, "\n"); - return; - } - - for (i = 0; i < blk->n; ++i) { - psl_print(psl, blk->nodes[i].blk, level + 1); - } -} - -void ngtcp2_psl_print(ngtcp2_psl *psl) { psl_print(psl, psl->head, 0); } - -ngtcp2_psl_it ngtcp2_psl_begin(const ngtcp2_psl *psl) { - ngtcp2_psl_it it = {psl->front, 0}; - return it; -} - -size_t ngtcp2_psl_len(ngtcp2_psl *psl) { return psl->n; } - -void ngtcp2_psl_it_init(ngtcp2_psl_it *it, const ngtcp2_psl_blk *blk, - size_t i) { - it->blk = blk; - it->i = i; -} - -void *ngtcp2_psl_it_get(const ngtcp2_psl_it *it) { - return it->blk->nodes[it->i].data; -} - -void ngtcp2_psl_it_next(ngtcp2_psl_it *it) { - assert(!ngtcp2_psl_it_end(it)); - - if (++it->i == it->blk->n) { - it->blk = it->blk->next; - it->i = 0; - } -} - -int ngtcp2_psl_it_end(const ngtcp2_psl_it *it) { - ngtcp2_range end = {UINT64_MAX, UINT64_MAX}; - return ngtcp2_range_eq(&end, &it->blk->nodes[it->i].range); -} - -ngtcp2_range ngtcp2_psl_it_range(const ngtcp2_psl_it *it) { - return it->blk->nodes[it->i].range; -} diff --git a/deps/ngtcp2/lib/ngtcp2_psl.h b/deps/ngtcp2/lib/ngtcp2_psl.h deleted file mode 100644 index f0310a87e41bab..00000000000000 --- a/deps/ngtcp2/lib/ngtcp2_psl.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * ngtcp2 - * - * Copyright (c) 2018 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_PSL_H -#define NGTCP2_PSL_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include - -#include "ngtcp2_range.h" - -/* - * Skip List implementation inspired by - * https://github.com/jabr/olio/blob/master/skiplist.c - */ - -#define NGTCP2_PSL_DEGR 8 -/* NGTCP2_PSL_MAX_NBLK is the maximum number of nodes which a single - block can contain. */ -#define NGTCP2_PSL_MAX_NBLK (2 * NGTCP2_PSL_DEGR - 1) -/* NGTCP2_PSL_MIN_NBLK is the minimum number of nodes which a single - block other than root must contains. */ -#define NGTCP2_PSL_MIN_NBLK (NGTCP2_PSL_DEGR - 1) - -struct ngtcp2_psl_node; -typedef struct ngtcp2_psl_node ngtcp2_psl_node; - -struct ngtcp2_psl_blk; -typedef struct ngtcp2_psl_blk ngtcp2_psl_blk; - -/* - * ngtcp2_psl_node is a node which contains either ngtcp2_psl_blk or - * opaque data. If a node is an internal node, it contains - * ngtcp2_psl_blk. Otherwise, it has data. The invariant is that the - * range of internal node dictates the maximum range in its - * descendants, and the corresponding leaf node must exist. - */ -struct ngtcp2_psl_node { - ngtcp2_range range; - union { - ngtcp2_psl_blk *blk; - void *data; - }; -}; - -/* - * ngtcp2_psl_blk contains ngtcp2_psl_node objects. - */ -struct ngtcp2_psl_blk { - /* next points to the next block if leaf field is nonzero. */ - ngtcp2_psl_blk *next; - /* n is the number of nodes this object contains in nodes. */ - size_t n; - /* leaf is nonzero if this block contains leaf nodes. */ - int leaf; - ngtcp2_psl_node nodes[NGTCP2_PSL_MAX_NBLK]; -}; - -struct ngtcp2_psl_it; -typedef struct ngtcp2_psl_it ngtcp2_psl_it; - -/* - * ngtcp2_psl_it is a forward iterator to iterate nodes. - */ -struct ngtcp2_psl_it { - const ngtcp2_psl_blk *blk; - size_t i; -}; - -struct ngtcp2_psl; -typedef struct ngtcp2_psl ngtcp2_psl; - -/* - * ngtcp2_psl is a deterministic paged skip list. - */ -struct ngtcp2_psl { - /* head points to the root block. */ - ngtcp2_psl_blk *head; - /* front points to the first leaf block. */ - ngtcp2_psl_blk *front; - size_t n; - const ngtcp2_mem *mem; -}; - -/* - * ngtcp2_psl_init initializes |psl|. - * - * It returns 0 if it succeeds, or one of the following negative error - * codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -int ngtcp2_psl_init(ngtcp2_psl *psl, const ngtcp2_mem *mem); - -/* - * ngtcp2_psl_free frees resources allocated for |psl|. If |psl| is - * NULL, this function does nothing. It does not free the memory - * region pointed by |psl| itself. - */ -void ngtcp2_psl_free(ngtcp2_psl *psl); - -/* - * ngtcp2_psl_insert inserts |range| with its associated |data|. On - * successful insertion, the iterator points to the inserted node is - * stored in |*it|. - * - * This function assumes that the existing ranges do not intersect - * with |range|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -int ngtcp2_psl_insert(ngtcp2_psl *psl, ngtcp2_psl_it *it, - const ngtcp2_range *range, void *data); - -/* - * ngtcp2_psl_remove removes the |range| from |psl|. It assumes such - * the range is included in |psl|. - * - * This function assigns the iterator to |*it|, which points to the - * node which is located at the right next of the removed node if |it| - * is not NULL. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGTCP2_ERR_NOMEM - * Out of memory. - */ -int ngtcp2_psl_remove(ngtcp2_psl *psl, ngtcp2_psl_it *it, - const ngtcp2_range *range); - -/* - * ngtcp2_psl_update_range replaces the range of nodes which has - * |old_range| with |new_range|. |old_range| must include - * |new_range|. - */ -void ngtcp2_psl_update_range(ngtcp2_psl *psl, const ngtcp2_range *old_range, - const ngtcp2_range *new_range); - -/* - * ngtcp2_psl_lower_bound returns the iterator which points to the - * first node whose range intersects with |range|. If there is no - * such node, it returns the iterator which satisfies - * ngtcp2_psl_it_end(it) != 0. - */ -ngtcp2_psl_it ngtcp2_psl_lower_bound(ngtcp2_psl *psl, - const ngtcp2_range *range); - -/* - * ngtcp2_psl_begin returns the iterator which points to the first - * node. If there is no node in |psl|, it returns the iterator which - * satisfies ngtcp2_psl_it_end(it) != 0. - */ -ngtcp2_psl_it ngtcp2_psl_begin(const ngtcp2_psl *psl); - -/* - * ngtcp2_psl_len returns the number of elements stored in |ksl|. - */ -size_t ngtcp2_psl_len(ngtcp2_psl *psl); - -/* - * ngtcp2_psl_print prints its internal state in stderr. This - * function should be used for the debugging purpose only. - */ -void ngtcp2_psl_print(ngtcp2_psl *psl); - -/* - * ngtcp2_psl_it_init initializes |it|. - */ -void ngtcp2_psl_it_init(ngtcp2_psl_it *it, const ngtcp2_psl_blk *blk, size_t i); - -/* - * ngtcp2_psl_it_get returns the data associated to the node which - * |it| points to. If this function is called when - * ngtcp2_psl_it_end(it) returns nonzero, it returns NULL. - */ -void *ngtcp2_psl_it_get(const ngtcp2_psl_it *it); - -/* - * ngtcp2_psl_it_next advances the iterator by one. It is undefined - * if this function is called when ngtcp2_psl_it_end(it) returns - * nonzero. - */ -void ngtcp2_psl_it_next(ngtcp2_psl_it *it); - -/* - * ngtcp2_psl_it_end returns nonzero if |it| points to the beyond the - * last node. - */ -int ngtcp2_psl_it_end(const ngtcp2_psl_it *it); - -/* - * ngtcp2_psl_range returns the range of the node which |it| points - * to. It is OK to call this function when ngtcp2_psl_it_end(it) - * returns nonzero. In this case, this function returns {UINT64_MAX, - * UINT64_MAX}. - */ -ngtcp2_range ngtcp2_psl_it_range(const ngtcp2_psl_it *it); - -#endif /* NGTCP2_PSL_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_qlog.c b/deps/ngtcp2/lib/ngtcp2_qlog.c index 2f6d2390c9afee..f0abc8dba7ca1b 100644 --- a/deps/ngtcp2/lib/ngtcp2_qlog.c +++ b/deps/ngtcp2/lib/ngtcp2_qlog.c @@ -447,14 +447,17 @@ static uint8_t *write_new_token_frame(uint8_t *p, const ngtcp2_new_token *fr) { (void)fr; /* - * {"frame_type":"new_token"} + * {"frame_type":"new_token","length":0000000000000000000,"token":""} */ -#define NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD 26 +#define NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD 66 *p++ = '{'; p = write_pair(p, ngtcp2_vec_lit(&name, "frame_type"), ngtcp2_vec_lit(&value, "new_token")); - /* TODO Write token here */ + *p++ = ','; + p = write_pair_number(p, ngtcp2_vec_lit(&name, "length"), fr->token.len); + *p++ = ','; + p = write_pair_hex(p, ngtcp2_vec_lit(&name, "token"), &fr->token); *p++ = '}'; return p; @@ -870,7 +873,8 @@ void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) { p = write_crypto_frame(p, &fr->crypto); break; case NGTCP2_FRAME_NEW_TOKEN: - if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD + 1 + + if (ngtcp2_buf_left(&qlog->buf) < NGTCP2_QLOG_NEW_TOKEN_FRAME_OVERHEAD + + fr->new_token.token.len * 2 + 1 + NGTCP2_QLOG_PKT_WRITE_END_OVERHEAD) { return; } @@ -1010,7 +1014,8 @@ void ngtcp2_qlog_pkt_sent_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, } void ngtcp2_qlog_parameters_set_transport_params( - ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int local) { + ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int server, + int local) { uint8_t buf[1024]; uint8_t *p = buf; ngtcp2_vec name, value; @@ -1032,9 +1037,19 @@ void ngtcp2_qlog_parameters_set_transport_params( local ? ngtcp2_vec_lit(&value, "local") : ngtcp2_vec_lit(&value, "remote")); *p++ = ','; - if (params->original_connection_id_present) { - p = write_pair_cid(p, ngtcp2_vec_lit(&name, "original_connection_id"), - ¶ms->original_connection_id); + p = write_pair_cid(p, ngtcp2_vec_lit(&name, "initial_source_connection_id"), + ¶ms->initial_scid); + *p++ = ','; + if (!server == !local) { + p = write_pair_cid( + p, ngtcp2_vec_lit(&name, "original_destination_connection_id"), + ¶ms->original_dcid); + *p++ = ','; + } + if (params->retry_scid_present) { + assert(!server); + p = write_pair_cid(p, ngtcp2_vec_lit(&name, "retry_source_connection_id"), + ¶ms->retry_scid); *p++ = ','; } if (params->stateless_reset_token_present) { @@ -1049,8 +1064,8 @@ void ngtcp2_qlog_parameters_set_transport_params( p = write_pair_duration(p, ngtcp2_vec_lit(&name, "max_idle_timeout"), params->max_idle_timeout); *p++ = ','; - p = write_pair_number(p, ngtcp2_vec_lit(&name, "max_packet_size"), - params->max_packet_size); + p = write_pair_number(p, ngtcp2_vec_lit(&name, "max_udp_payload_size"), + params->max_udp_payload_size); *p++ = ','; p = write_pair_number(p, ngtcp2_vec_lit(&name, "ack_delay_exponent"), params->ack_delay_exponent); @@ -1115,8 +1130,7 @@ void ngtcp2_qlog_parameters_set_transport_params( } void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog, - const ngtcp2_rcvry_stat *rcs, - ngtcp2_cc_stat *ccs) { + const ngtcp2_conn_stat *cstat) { uint8_t buf[1024]; uint8_t *p = buf; ngtcp2_vec name, value; @@ -1134,30 +1148,33 @@ void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog, *p++ = ','; *p++ = '{'; - if (rcs->min_rtt != UINT64_MAX) { - p = write_pair_duration(p, ngtcp2_vec_lit(&name, "min_rtt"), rcs->min_rtt); + if (cstat->min_rtt != UINT64_MAX) { + p = write_pair_duration(p, ngtcp2_vec_lit(&name, "min_rtt"), + cstat->min_rtt); *p++ = ','; } p = write_pair_duration(p, ngtcp2_vec_lit(&name, "smoothed_rtt"), - rcs->smoothed_rtt); + cstat->smoothed_rtt); *p++ = ','; p = write_pair_duration(p, ngtcp2_vec_lit(&name, "latest_rtt"), - rcs->latest_rtt); + cstat->latest_rtt); *p++ = ','; p = write_pair_duration(p, ngtcp2_vec_lit(&name, "rtt_variance"), - rcs->rttvar); + cstat->rttvar); *p++ = ','; /* TODO max_ack_delay? */ - p = write_pair_number(p, ngtcp2_vec_lit(&name, "pto_count"), rcs->pto_count); + p = write_pair_number(p, ngtcp2_vec_lit(&name, "pto_count"), + cstat->pto_count); *p++ = ','; p = write_pair_number(p, ngtcp2_vec_lit(&name, "congestion_window"), - ccs->cwnd); + cstat->cwnd); *p++ = ','; p = write_pair_number(p, ngtcp2_vec_lit(&name, "bytes_in_flight"), - ccs->bytes_in_flight); - if (ccs->ssthresh != UINT64_MAX) { + cstat->bytes_in_flight); + if (cstat->ssthresh != UINT64_MAX) { *p++ = ','; - p = write_pair_number(p, ngtcp2_vec_lit(&name, "ssthresh"), ccs->ssthresh); + p = write_pair_number(p, ngtcp2_vec_lit(&name, "ssthresh"), + cstat->ssthresh); } *p++ = '}'; diff --git a/deps/ngtcp2/lib/ngtcp2_qlog.h b/deps/ngtcp2/lib/ngtcp2_qlog.h index 160cacd2322ed7..cd967984a7482a 100644 --- a/deps/ngtcp2/lib/ngtcp2_qlog.h +++ b/deps/ngtcp2/lib/ngtcp2_qlog.h @@ -110,19 +110,20 @@ void ngtcp2_qlog_pkt_sent_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, /* * ngtcp2_qlog_parameters_set_transport_params writes |params| to qlog - * as parameters_set event. If |local| is nonzero, it is "owner" - * field becomes "local", otherwise "remote". + * as parameters_set event. |server| is nonzero if the local endpoint + * is server. If |local| is nonzero, it is "owner" field becomes + * "local", otherwise "remote". */ void ngtcp2_qlog_parameters_set_transport_params( - ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int local); + ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int server, + int local); /* * ngtcp2_qlog_metrics_updated writes metrics_updated event of * recovery category. */ void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog, - const ngtcp2_rcvry_stat *rcs, - ngtcp2_cc_stat *ccs); + const ngtcp2_conn_stat *cstat); /* * ngtcp2_qlog_pkt_lost writes packet_lost event. diff --git a/deps/ngtcp2/lib/ngtcp2_rcvry.h b/deps/ngtcp2/lib/ngtcp2_rcvry.h index 254c3c797a0301..0ff0bc4b6ed75e 100644 --- a/deps/ngtcp2/lib/ngtcp2_rcvry.h +++ b/deps/ngtcp2/lib/ngtcp2_rcvry.h @@ -39,6 +39,6 @@ draft-ietf-quic-recovery-17. */ #define NGTCP2_GRANULARITY NGTCP2_MILLISECONDS -#define NGTCP2_DEFAULT_INITIAL_RTT (500 * NGTCP2_MILLISECONDS) +#define NGTCP2_DEFAULT_INITIAL_RTT (333 * NGTCP2_MILLISECONDS) #endif /* NGTCP2_RCVRY_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_rob.c b/deps/ngtcp2/lib/ngtcp2_rob.c index ab7f44ecb88cb7..499c07ec6be247 100644 --- a/deps/ngtcp2/lib/ngtcp2_rob.c +++ b/deps/ngtcp2/lib/ngtcp2_rob.c @@ -68,7 +68,6 @@ void ngtcp2_rob_data_del(ngtcp2_rob_data *d, const ngtcp2_mem *mem) { int ngtcp2_rob_init(ngtcp2_rob *rob, size_t chunk, const ngtcp2_mem *mem) { int rv; ngtcp2_rob_gap *g; - ngtcp2_ksl_key key; rv = ngtcp2_ksl_init(&rob->gapksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range), mem); @@ -81,8 +80,7 @@ int ngtcp2_rob_init(ngtcp2_rob *rob, size_t chunk, const ngtcp2_mem *mem) { goto fail_rob_gap_new; } - rv = ngtcp2_ksl_insert(&rob->gapksl, NULL, - ngtcp2_ksl_key_ptr(&key, &g->range), g); + rv = ngtcp2_ksl_insert(&rob->gapksl, NULL, &g->range, g); if (rv != 0) { goto fail_gapksl_ksl_insert; } @@ -135,10 +133,8 @@ static int rob_write_data(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, ngtcp2_rob_data *d; ngtcp2_range range = {offset, offset + len}; ngtcp2_ksl_it it; - ngtcp2_ksl_key key; - for (it = ngtcp2_ksl_lower_bound_compar(&rob->dataksl, - ngtcp2_ksl_key_ptr(&key, &range), + for (it = ngtcp2_ksl_lower_bound_compar(&rob->dataksl, &range, ngtcp2_ksl_range_exclusive_compar); len; ngtcp2_ksl_it_next(&it)) { if (ngtcp2_ksl_it_end(&it)) { @@ -154,15 +150,14 @@ static int rob_write_data(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, return rv; } - rv = ngtcp2_ksl_insert(&rob->dataksl, &it, - ngtcp2_ksl_key_ptr(&key, &d->range), d); + rv = ngtcp2_ksl_insert(&rob->dataksl, &it, &d->range, d); if (rv != 0) { ngtcp2_rob_data_del(d, rob->mem); return rv; } } - n = ngtcp2_min(len, d->range.begin + rob->chunk - offset); + n = (size_t)ngtcp2_min((uint64_t)len, d->range.begin + rob->chunk - offset); memcpy(d->begin + (offset - d->range.begin), data, n); offset += n; data += n; @@ -178,9 +173,8 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, ngtcp2_rob_gap *g; ngtcp2_range m, l, r, q = {offset, offset + datalen}; ngtcp2_ksl_it it; - ngtcp2_ksl_key key, old_key; - it = ngtcp2_ksl_lower_bound_compar(&rob->gapksl, ngtcp2_ksl_key_ptr(&key, &q), + it = ngtcp2_ksl_lower_bound_compar(&rob->gapksl, &q, ngtcp2_ksl_range_exclusive_compar); for (; !ngtcp2_ksl_it_end(&it);) { @@ -191,10 +185,10 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, break; } if (ngtcp2_range_eq(&g->range, &m)) { - ngtcp2_ksl_remove(&rob->gapksl, &it, ngtcp2_ksl_key_ptr(&key, &g->range)); + ngtcp2_ksl_remove(&rob->gapksl, &it, &g->range); ngtcp2_rob_gap_del(g, rob->mem); rv = rob_write_data(rob, m.begin, data + (m.begin - offset), - ngtcp2_range_len(&m)); + (size_t)ngtcp2_range_len(&m)); if (rv != 0) { return rv; } @@ -203,9 +197,7 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, } ngtcp2_range_cut(&l, &r, &g->range, &m); if (ngtcp2_range_len(&l)) { - ngtcp2_ksl_update_key(&rob->gapksl, - ngtcp2_ksl_key_ptr(&old_key, &g->range), - ngtcp2_ksl_key_ptr(&key, &l)); + ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &l); g->range = l; if (ngtcp2_range_len(&r)) { @@ -214,21 +206,18 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data, if (rv != 0) { return rv; } - rv = ngtcp2_ksl_insert(&rob->gapksl, &it, - ngtcp2_ksl_key_ptr(&key, &ng->range), ng); + rv = ngtcp2_ksl_insert(&rob->gapksl, &it, &ng->range, ng); if (rv != 0) { ngtcp2_rob_gap_del(ng, rob->mem); return rv; } } } else if (ngtcp2_range_len(&r)) { - ngtcp2_ksl_update_key(&rob->gapksl, - ngtcp2_ksl_key_ptr(&old_key, &g->range), - ngtcp2_ksl_key_ptr(&key, &r)); + ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &r); g->range = r; } rv = rob_write_data(rob, m.begin, data + (m.begin - offset), - ngtcp2_range_len(&m)); + (size_t)ngtcp2_range_len(&m)); if (rv != 0) { return rv; } @@ -241,7 +230,6 @@ int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { ngtcp2_rob_gap *g; ngtcp2_rob_data *d; ngtcp2_ksl_it it; - ngtcp2_ksl_key key, old_key; it = ngtcp2_ksl_begin(&rob->gapksl); @@ -252,13 +240,11 @@ int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { } if (offset < g->range.end) { ngtcp2_range r = {offset, g->range.end}; - ngtcp2_ksl_update_key(&rob->gapksl, - ngtcp2_ksl_key_ptr(&old_key, &g->range), - ngtcp2_ksl_key_ptr(&key, &r)); + ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &r); g->range.begin = offset; break; } - ngtcp2_ksl_remove(&rob->gapksl, &it, ngtcp2_ksl_key_ptr(&key, &g->range)); + ngtcp2_ksl_remove(&rob->gapksl, &it, &g->range); ngtcp2_rob_gap_del(g, rob->mem); } @@ -269,7 +255,7 @@ int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) { if (offset < d->range.begin + rob->chunk) { return 0; } - ngtcp2_ksl_remove(&rob->dataksl, &it, ngtcp2_ksl_key_ptr(&key, &d->range)); + ngtcp2_ksl_remove(&rob->dataksl, &it, &d->range); ngtcp2_rob_data_del(d, rob->mem); } @@ -302,12 +288,12 @@ size_t ngtcp2_rob_data_at(ngtcp2_rob *rob, const uint8_t **pdest, *pdest = d->begin + (offset - d->range.begin); - return ngtcp2_min(g->range.begin, d->range.begin + rob->chunk) - offset; + return (size_t)(ngtcp2_min(g->range.begin, d->range.begin + rob->chunk) - + offset); } void ngtcp2_rob_pop(ngtcp2_rob *rob, uint64_t offset, size_t len) { ngtcp2_ksl_it it; - ngtcp2_ksl_key key; ngtcp2_rob_data *d; it = ngtcp2_ksl_begin(&rob->dataksl); @@ -319,7 +305,7 @@ void ngtcp2_rob_pop(ngtcp2_rob *rob, uint64_t offset, size_t len) { return; } - ngtcp2_ksl_remove(&rob->dataksl, NULL, ngtcp2_ksl_key_ptr(&key, &d->range)); + ngtcp2_ksl_remove(&rob->dataksl, NULL, &d->range); ngtcp2_rob_data_del(d, rob->mem); } diff --git a/deps/ngtcp2/lib/ngtcp2_rst.c b/deps/ngtcp2/lib/ngtcp2_rst.c index c9c994e2bae16b..e546fdf85c623b 100644 --- a/deps/ngtcp2/lib/ngtcp2_rst.c +++ b/deps/ngtcp2/lib/ngtcp2_rst.c @@ -27,15 +27,7 @@ #include "ngtcp2_cc.h" #include "ngtcp2_macro.h" -void ngtcp2_rst_init(ngtcp2_rst *rst) { - ngtcp2_rs *rs = &rst->rs; - - rst->delivered = 0; - rst->delivered_ts = 0; - rst->first_sent_ts = 0; - rst->app_limited = 0; - - rs->delivery_rate = 0.; +void ngtcp2_rs_init(ngtcp2_rs *rs) { rs->interval = UINT64_MAX; rs->delivered = 0; rs->prior_delivered = 0; @@ -45,9 +37,17 @@ void ngtcp2_rst_init(ngtcp2_rst *rst) { rs->is_app_limited = 0; } +void ngtcp2_rst_init(ngtcp2_rst *rst) { + ngtcp2_rs_init(&rst->rs); + rst->delivered = 0; + rst->delivered_ts = 0; + rst->first_sent_ts = 0; + rst->app_limited = 0; +} + void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, - const ngtcp2_cc_stat *ccs) { - if (ccs->bytes_in_flight == 0) { + const ngtcp2_conn_stat *cstat) { + if (cstat->bytes_in_flight == 0) { rst->first_sent_ts = rst->delivered_ts = ent->ts; } ent->rst.first_sent_ts = rst->first_sent_ts; @@ -56,7 +56,7 @@ void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, ent->rst.is_app_limited = rst->app_limited != 0; } -int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, const ngtcp2_rcvry_stat *rcs) { +int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) { ngtcp2_rs *rs = &rst->rs; if (rst->app_limited && rst->delivered > rst->app_limited) { @@ -71,16 +71,16 @@ int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, const ngtcp2_rcvry_stat *rcs) { rs->delivered = rst->delivered - rs->prior_delivered; - if (rs->interval < rcs->min_rtt) { + if (rs->interval < cstat->min_rtt) { rs->interval = UINT64_MAX; return 0; } if (rs->interval) { - rs->delivery_rate = (double)rs->delivered / (double)rs->interval; + cstat->delivery_rate_sec = rs->delivered * NGTCP2_SECONDS / rs->interval; } - return 1; + return 0; } void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, @@ -100,8 +100,8 @@ void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent, } } -void ngtcp2_rst_update_app_limited(ngtcp2_rst *rst, const ngtcp2_cc_stat *ccs) { +void ngtcp2_rst_update_app_limited(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) { (void)rst; - (void)ccs; + (void)cstat; /* TODO Not implemented */ } diff --git a/deps/ngtcp2/lib/ngtcp2_rst.h b/deps/ngtcp2/lib/ngtcp2_rst.h index b7137b79c957b8..f68a1f9b22d8b5 100644 --- a/deps/ngtcp2/lib/ngtcp2_rst.h +++ b/deps/ngtcp2/lib/ngtcp2_rst.h @@ -34,8 +34,12 @@ struct ngtcp2_rtb_entry; typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry; +/** + * @struct + * + * ngtcp2_rs contains connection state for delivery rate estimation. + */ typedef struct ngtcp2_rs { - double delivery_rate; ngtcp2_duration interval; uint64_t delivered; uint64_t prior_delivered; @@ -45,25 +49,27 @@ typedef struct ngtcp2_rs { int is_app_limited; } ngtcp2_rs; +void ngtcp2_rs_init(ngtcp2_rs *rs); + /* * ngtcp2_rst implements delivery rate estimation described in * https://tools.ietf.org/html/draft-cheng-iccrg-delivery-rate-estimation-00 */ typedef struct ngtcp2_rst { + ngtcp2_rs rs; uint64_t delivered; ngtcp2_tstamp delivered_ts; ngtcp2_tstamp first_sent_ts; uint64_t app_limited; - ngtcp2_rs rs; } ngtcp2_rst; void ngtcp2_rst_init(ngtcp2_rst *rst); void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent, - const ngtcp2_cc_stat *ccs); -int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, const ngtcp2_rcvry_stat *rcs); + const ngtcp2_conn_stat *cstat); +int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat); 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, const ngtcp2_cc_stat *ccs); +void ngtcp2_rst_update_app_limited(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat); #endif /* NGTCP2_RST_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_rtb.c b/deps/ngtcp2/lib/ngtcp2_rtb.c index 83936f2aa69013..e7e6762e03daf4 100644 --- a/deps/ngtcp2/lib/ngtcp2_rtb.c +++ b/deps/ngtcp2/lib/ngtcp2_rtb.c @@ -144,12 +144,12 @@ void ngtcp2_rtb_entry_del(ngtcp2_rtb_entry *ent, const ngtcp2_mem *mem) { } static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { - return *lhs->i > *rhs->i; + return *(int64_t *)lhs > *(int64_t *)rhs; } -void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_crypto_level crypto_level, - ngtcp2_strm *crypto, ngtcp2_rst *rst, - ngtcp2_default_cc *cc, ngtcp2_log *log, ngtcp2_qlog *qlog, +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, const ngtcp2_mem *mem) { ngtcp2_ksl_init(&rtb->ents, greater, sizeof(int64_t), mem); rtb->crypto = crypto; @@ -160,10 +160,10 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_crypto_level crypto_level, rtb->mem = mem; rtb->largest_acked_tx_pkt_num = -1; rtb->num_ack_eliciting = 0; - rtb->loss_time = UINT64_MAX; rtb->probe_pkt_left = 0; - rtb->crypto_level = crypto_level; + rtb->pktns_id = pktns_id; rtb->cc_pkt_num = 0; + rtb->cc_bytes_in_flight = 0; } void ngtcp2_rtb_free(ngtcp2_rtb *rtb) { @@ -182,29 +182,35 @@ void ngtcp2_rtb_free(ngtcp2_rtb *rtb) { ngtcp2_ksl_free(&rtb->ents); } -static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent) { - ngtcp2_rst_on_pkt_sent(rtb->rst, ent, rtb->cc->ccs); +static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, + ngtcp2_conn_stat *cstat) { + ngtcp2_rst_on_pkt_sent(rtb->rst, ent, cstat); assert(rtb->cc_pkt_num <= ent->hd.pkt_num); - rtb->cc->ccs->bytes_in_flight += ent->pktlen; + cstat->bytes_in_flight += ent->pktlen; + rtb->cc_bytes_in_flight += ent->pktlen; - ngtcp2_rst_update_app_limited(rtb->rst, rtb->cc->ccs); + ngtcp2_rst_update_app_limited(rtb->rst, cstat); if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) { ++rtb->num_ack_eliciting; } } -static void rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent) { +static void rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, + ngtcp2_conn_stat *cstat) { if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) { assert(rtb->num_ack_eliciting); --rtb->num_ack_eliciting; } if (rtb->cc_pkt_num <= ent->hd.pkt_num) { - assert(rtb->cc->ccs->bytes_in_flight >= ent->pktlen); - rtb->cc->ccs->bytes_in_flight -= ent->pktlen; + assert(cstat->bytes_in_flight >= ent->pktlen); + cstat->bytes_in_flight -= ent->pktlen; + + assert(rtb->cc_bytes_in_flight >= ent->pktlen); + rtb->cc_bytes_in_flight -= ent->pktlen; } } @@ -229,24 +235,28 @@ static void rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, frame_chain_insert(pfrc, ent->frc); ent->frc = NULL; } + } else { + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + "pkn=%" PRId64 + " is a probe packet, no retransmission is necessary", + ent->hd.pkt_num); } ngtcp2_rtb_entry_del(ent, rtb->mem); } -int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent) { +int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, + ngtcp2_conn_stat *cstat) { int rv; - ngtcp2_ksl_key key; ent->next = NULL; - rv = ngtcp2_ksl_insert(&rtb->ents, NULL, - ngtcp2_ksl_key_ptr(&key, &ent->hd.pkt_num), ent); + rv = ngtcp2_ksl_insert(&rtb->ents, NULL, &ent->hd.pkt_num, ent); if (rv != 0) { return rv; } - rtb_on_add(rtb, ent); + rtb_on_add(rtb, ent, cstat); return 0; } @@ -256,22 +266,21 @@ ngtcp2_ksl_it ngtcp2_rtb_head(ngtcp2_rtb *rtb) { } static void rtb_remove(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it, - ngtcp2_rtb_entry *ent) { - ngtcp2_ksl_key key; - - ngtcp2_ksl_remove(&rtb->ents, it, ngtcp2_ksl_key_ptr(&key, &ent->hd.pkt_num)); - rtb_on_remove(rtb, ent); + ngtcp2_rtb_entry *ent, ngtcp2_conn_stat *cstat) { + ngtcp2_ksl_remove(&rtb->ents, it, &ent->hd.pkt_num); + rtb_on_remove(rtb, ent, cstat); ngtcp2_rtb_entry_del(ent, rtb->mem); } -static int rtb_call_acked_stream_offset(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, - ngtcp2_conn *conn) { +static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, + ngtcp2_conn *conn) { ngtcp2_frame_chain *frc; uint64_t prev_stream_offset, stream_offset; ngtcp2_strm *strm; int rv; - size_t datalen; + uint64_t datalen; ngtcp2_strm *crypto = rtb->crypto; + ngtcp2_crypto_level crypto_level; for (frc = ent->frc; frc; frc = frc->next) { switch (frc->fr.type) { @@ -326,9 +335,22 @@ static int rtb_call_acked_stream_offset(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, break; } - rv = conn->callbacks.acked_crypto_offset(conn, rtb->crypto_level, - prev_stream_offset, datalen, - conn->user_data); + switch (rtb->pktns_id) { + case NGTCP2_PKTNS_ID_INITIAL: + crypto_level = NGTCP2_CRYPTO_LEVEL_INITIAL; + break; + case NGTCP2_PKTNS_ID_HANDSHAKE: + crypto_level = NGTCP2_CRYPTO_LEVEL_HANDSHAKE; + break; + case NGTCP2_PKTNS_ID_APP: + crypto_level = NGTCP2_CRYPTO_LEVEL_APP; + break; + default: + assert(0); + } + + rv = conn->callbacks.acked_crypto_offset( + conn, crypto_level, prev_stream_offset, datalen, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -345,34 +367,47 @@ static int rtb_call_acked_stream_offset(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, return rv; } break; + case NGTCP2_FRAME_RETIRE_CONNECTION_ID: + assert(conn->dcid.num_retire_queued); + --conn->dcid.num_retire_queued; + break; } } return 0; } static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, - ngtcp2_tstamp ts) { + ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { + ngtcp2_cc *cc = rtb->cc; ngtcp2_cc_pkt pkt; ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts); - ngtcp2_default_cc_on_pkt_acked( - rtb->cc, ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, ent->ts)); + cc->on_pkt_acked(cc, cstat, + ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, + rtb->pktns_id, ent->ts), + ts); + + if (!(ent->flags & NGTCP2_RTB_FLAG_PROBE) && + (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING)) { + cstat->pto_count = 0; + } } ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, - ngtcp2_conn *conn, ngtcp2_tstamp pkt_ts, - ngtcp2_tstamp ts) { + ngtcp2_conn_stat *cstat, ngtcp2_conn *conn, + ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts) { ngtcp2_rtb_entry *ent; int64_t largest_ack = fr->largest_ack, min_ack; size_t i; int rv; ngtcp2_ksl_it it; - ngtcp2_ksl_key key; ngtcp2_ssize num_acked = 0; int largest_pkt_acked = 0; int rtt_updated = 0; ngtcp2_tstamp largest_pkt_sent_ts = 0; + int64_t pkt_num; + ngtcp2_cc *cc = rtb->cc; if (conn && (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) && largest_ack >= conn->pktns.crypto.tx.ckm->pkt_num) { @@ -386,8 +421,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ngtcp2_max(rtb->largest_acked_tx_pkt_num, largest_ack); /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */ - it = ngtcp2_ksl_lower_bound(&rtb->ents, - ngtcp2_ksl_key_ptr(&key, &largest_ack)); + it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack); if (ngtcp2_ksl_it_end(&it)) { return 0; } @@ -395,15 +429,15 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, min_ack = largest_ack - (int64_t)fr->first_ack_blklen; for (; !ngtcp2_ksl_it_end(&it);) { - key = ngtcp2_ksl_it_key(&it); - if (min_ack <= *key.i && *key.i <= largest_ack) { + pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it); + if (min_ack <= pkt_num && pkt_num <= largest_ack) { ent = ngtcp2_ksl_it_get(&it); if (conn) { - rv = rtb_call_acked_stream_offset(rtb, ent, conn); + rv = rtb_process_acked_pkt(rtb, ent, conn); if (rv != 0) { return rv; } - if (largest_ack == *key.i) { + if (largest_ack == pkt_num) { largest_pkt_sent_ts = ent->ts; largest_pkt_acked = 1; } @@ -412,12 +446,16 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, rtt_updated = 1; ngtcp2_conn_update_rtt(conn, pkt_ts - largest_pkt_sent_ts, fr->ack_delay_unscaled); + if (cc->new_rtt_sample) { + cc->new_rtt_sample(cc, cstat, ts); + } } - rtb_on_pkt_acked(rtb, ent, ts); + + rtb_on_pkt_acked(rtb, ent, cstat, ts); /* At this point, it is invalided because rtb->ents might be modified. */ } - rtb_remove(rtb, &it, ent); + rtb_remove(rtb, &it, ent, cstat); ++num_acked; continue; } @@ -428,20 +466,19 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2; min_ack = largest_ack - (int64_t)fr->blks[i].blklen; - it = ngtcp2_ksl_lower_bound(&rtb->ents, - ngtcp2_ksl_key_ptr(&key, &largest_ack)); + it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack); if (ngtcp2_ksl_it_end(&it)) { break; } for (; !ngtcp2_ksl_it_end(&it);) { - key = ngtcp2_ksl_it_key(&it); - if (*key.i < min_ack) { + pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it); + if (pkt_num < min_ack) { break; } ent = ngtcp2_ksl_it_get(&it); if (conn) { - rv = rtb_call_acked_stream_offset(rtb, ent, conn); + rv = rtb_process_acked_pkt(rtb, ent, conn); if (rv != 0) { return rv; } @@ -450,38 +487,50 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, rtt_updated = 1; ngtcp2_conn_update_rtt(conn, pkt_ts - largest_pkt_sent_ts, fr->ack_delay_unscaled); + if (cc->new_rtt_sample) { + cc->new_rtt_sample(cc, cstat, ts); + } } - rtb_on_pkt_acked(rtb, ent, ts); + + rtb_on_pkt_acked(rtb, ent, cstat, ts); } - rtb_remove(rtb, &it, ent); + rtb_remove(rtb, &it, ent, cstat); ++num_acked; } ++i; } - if (conn) { - ngtcp2_rst_on_ack_recv(rtb->rst, &conn->rcs); - ngtcp2_default_cc_on_ack_recv(rtb->cc, - rtt_updated ? conn->rcs.latest_rtt : 0, ts); - } + ngtcp2_rst_on_ack_recv(rtb->rst, cstat); + cc->on_ack_recv(cc, cstat, ts); return num_acked; } -static int rtb_pkt_lost(ngtcp2_rtb *rtb, const ngtcp2_rtb_entry *ent, - uint64_t loss_delay, ngtcp2_tstamp lost_send_time) { +static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, + const ngtcp2_rtb_entry *ent, uint64_t loss_delay, + ngtcp2_tstamp lost_send_time) { + ngtcp2_tstamp loss_time; + uint64_t pkt_thres = + rtb->cc_bytes_in_flight / cstat->max_udp_payload_size / 2; + + pkt_thres = ngtcp2_max(pkt_thres, NGTCP2_PKT_THRESHOLD); + if (ent->ts <= lost_send_time || - rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + NGTCP2_PKT_THRESHOLD) { + rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + (int64_t)pkt_thres) { return 1; } - if (rtb->loss_time == UINT64_MAX) { - rtb->loss_time = ent->ts + loss_delay; + loss_time = cstat->loss_time[rtb->pktns_id]; + + if (loss_time == UINT64_MAX) { + loss_time = ent->ts + loss_delay; } else { - rtb->loss_time = ngtcp2_min(rtb->loss_time, ent->ts + loss_delay); + loss_time = ngtcp2_min(loss_time, ent->ts + loss_delay); } + cstat->loss_time[rtb->pktns_id] = loss_time; + return 0; } @@ -489,15 +538,15 @@ static int rtb_pkt_lost(ngtcp2_rtb *rtb, const ngtcp2_rtb_entry *ent, * rtb_compute_pkt_loss_delay computes delay until packet is * considered lost in NGTCP2_MICROSECONDS resolution. */ -static ngtcp2_duration compute_pkt_loss_delay(const ngtcp2_rcvry_stat *rcs) { +static ngtcp2_duration compute_pkt_loss_delay(const ngtcp2_conn_stat *cstat) { /* 9/8 is kTimeThreshold */ ngtcp2_duration loss_delay = - ngtcp2_max(rcs->latest_rtt, rcs->smoothed_rtt) * 9 / 8; + ngtcp2_max(cstat->latest_rtt, cstat->smoothed_rtt) * 9 / 8; return ngtcp2_max(loss_delay, NGTCP2_GRANULARITY); } void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, - ngtcp2_rcvry_stat *rcs, ngtcp2_duration pto, + ngtcp2_conn_stat *cstat, ngtcp2_duration pto, ngtcp2_tstamp ts) { ngtcp2_rtb_entry *ent; ngtcp2_duration loss_delay; @@ -505,26 +554,25 @@ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, ngtcp2_ksl_it it; ngtcp2_tstamp latest_ts, oldest_ts; int64_t last_lost_pkt_num; - ngtcp2_ksl_key key; + ngtcp2_duration loss_window, congestion_period; + ngtcp2_cc *cc = rtb->cc; - rtb->loss_time = UINT64_MAX; - loss_delay = compute_pkt_loss_delay(rcs); + cstat->loss_time[rtb->pktns_id] = UINT64_MAX; + loss_delay = compute_pkt_loss_delay(cstat); lost_send_time = ts - loss_delay; - it = ngtcp2_ksl_lower_bound( - &rtb->ents, ngtcp2_ksl_key_ptr(&key, &rtb->largest_acked_tx_pkt_num)); + it = ngtcp2_ksl_lower_bound(&rtb->ents, &rtb->largest_acked_tx_pkt_num); for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { ent = ngtcp2_ksl_it_get(&it); - if (rtb_pkt_lost(rtb, ent, loss_delay, lost_send_time)) { + if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, lost_send_time)) { /* All entries from ent are considered to be lost. */ latest_ts = oldest_ts = ent->ts; last_lost_pkt_num = ent->hd.pkt_num; for (; !ngtcp2_ksl_it_end(&it);) { ent = ngtcp2_ksl_it_get(&it); - ngtcp2_ksl_remove(&rtb->ents, &it, - ngtcp2_ksl_key_ptr(&key, &ent->hd.pkt_num)); + ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); if (last_lost_pkt_num == ent->hd.pkt_num + 1) { last_lost_pkt_num = ent->hd.pkt_num; @@ -533,15 +581,23 @@ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, } oldest_ts = ent->ts; - rtb_on_remove(rtb, ent); + rtb_on_remove(rtb, ent, cstat); rtb_on_pkt_lost(rtb, pfrc, ent); } - ngtcp2_default_cc_congestion_event(rtb->cc, latest_ts, ts); + cc->congestion_event(cc, cstat, latest_ts, ts); if (last_lost_pkt_num != -1) { - ngtcp2_default_cc_handle_persistent_congestion( - rtb->cc, latest_ts - oldest_ts, pto); + loss_window = latest_ts - oldest_ts; + congestion_period = pto * NGTCP2_PERSISTENT_CONGESTION_THRESHOLD; + if (loss_window >= congestion_period) { + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + "persistent congestion loss_window=%" PRIu64 + " congestion_period=%" PRIu64, + loss_window, congestion_period); + + cc->on_persistent_congestion(cc, cstat, ts); + } } return; @@ -549,25 +605,25 @@ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, } } -void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc) { +void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, + ngtcp2_conn_stat *cstat) { ngtcp2_rtb_entry *ent; ngtcp2_ksl_it it; - ngtcp2_ksl_key key; it = ngtcp2_ksl_begin(&rtb->ents); for (; !ngtcp2_ksl_it_end(&it);) { ent = ngtcp2_ksl_it_get(&it); - rtb_on_remove(rtb, ent); - ngtcp2_ksl_remove(&rtb->ents, &it, - ngtcp2_ksl_key_ptr(&key, &ent->hd.pkt_num)); + rtb_on_remove(rtb, ent, cstat); + ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); rtb_on_pkt_lost(rtb, pfrc, ent); } } -int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc) { +int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, + ngtcp2_conn_stat *cstat) { ngtcp2_rtb_entry *ent; ngtcp2_ksl_it it; ngtcp2_frame_chain *nfrc; @@ -577,7 +633,6 @@ int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc) { ngtcp2_crypto *fr; int all_acked; int rv; - ngtcp2_ksl_key key; it = ngtcp2_ksl_begin(&rtb->ents); @@ -601,7 +656,7 @@ int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc) { been acknowledged */ gapit = ngtcp2_gaptr_get_first_gap_after(&rtb->crypto->tx.acked_offset, fr->offset); - gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit).ptr; + gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit); range.begin = fr->offset; range.end = fr->offset + ngtcp2_vec_len(fr->data, fr->datacnt); @@ -630,9 +685,8 @@ int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc) { if (all_acked) { /* If the frames that ent contains have been acknowledged, remove it from rtb. Otherwise crypto timer keeps firing. */ - rtb_on_remove(rtb, ent); - ngtcp2_ksl_remove(&rtb->ents, &it, - ngtcp2_ksl_key_ptr(&key, &ent->hd.pkt_num)); + rtb_on_remove(rtb, ent, cstat); + ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); ngtcp2_rtb_entry_del(ent, rtb->mem); continue; } @@ -649,22 +703,7 @@ int ngtcp2_rtb_empty(ngtcp2_rtb *rtb) { return ngtcp2_ksl_len(&rtb->ents) == 0; } -uint64_t ngtcp2_rtb_get_bytes_in_flight(ngtcp2_rtb *rtb) { - uint64_t bytes_in_flight = 0; - ngtcp2_ksl_it it; - ngtcp2_rtb_entry *ent; - - for (it = ngtcp2_ksl_begin(&rtb->ents); !ngtcp2_ksl_it_end(&it); - ngtcp2_ksl_it_next(&it)) { - ent = ngtcp2_ksl_it_get(&it); - if (rtb->cc_pkt_num <= ent->hd.pkt_num) { - bytes_in_flight += ent->pktlen; - } - } - - return bytes_in_flight; -} - -size_t ngtcp2_rtb_num_ack_eliciting(ngtcp2_rtb *rtb) { - return rtb->num_ack_eliciting; +void ngtcp2_rtb_reset_cc_state(ngtcp2_rtb *rtb, int64_t cc_pkt_num) { + rtb->cc_pkt_num = cc_pkt_num; + rtb->cc_bytes_in_flight = 0; } diff --git a/deps/ngtcp2/lib/ngtcp2_rtb.h b/deps/ngtcp2/lib/ngtcp2_rtb.h index 0e11cea5d4f0f0..6dac9b6357e69b 100644 --- a/deps/ngtcp2/lib/ngtcp2_rtb.h +++ b/deps/ngtcp2/lib/ngtcp2_rtb.h @@ -47,9 +47,6 @@ typedef struct ngtcp2_log ngtcp2_log; struct ngtcp2_qlog; typedef struct ngtcp2_qlog ngtcp2_qlog; -struct ngtcp2_default_cc; -typedef struct ngtcp2_default_cc ngtcp2_default_cc; - struct ngtcp2_strm; typedef struct ngtcp2_strm ngtcp2_strm; @@ -211,31 +208,34 @@ typedef struct { /* crypto is CRYPTO stream. */ ngtcp2_strm *crypto; ngtcp2_rst *rst; - ngtcp2_default_cc *cc; + ngtcp2_cc *cc; ngtcp2_log *log; ngtcp2_qlog *qlog; const ngtcp2_mem *mem; /* largest_acked_tx_pkt_num is the largest packet number acknowledged by the peer. */ int64_t largest_acked_tx_pkt_num; + /* num_ack_eliciting is the number of ACK eliciting entries. */ size_t num_ack_eliciting; - ngtcp2_tstamp loss_time; /* probe_pkt_left is the number of probe packet to send */ size_t probe_pkt_left; - /* crypto_level is encryption level which |crypto| belongs to. */ - ngtcp2_crypto_level crypto_level; + /* pktns_id is the identifier of packet number space. */ + ngtcp2_pktns_id pktns_id; /* cc_pkt_num is the smallest packet number that is contributed to - bytes_in_flight. */ + ngtcp2_conn_stat.bytes_in_flight. */ int64_t cc_pkt_num; + /* cc_bytes_in_flight is the number of in-flight bytes that is + contributed to ngtcp2_conn_stat.bytes_in_flight. It only + includes the bytes after congestion state is reset. */ + uint64_t cc_bytes_in_flight; } ngtcp2_rtb; /* * ngtcp2_rtb_init initializes |rtb|. */ -void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_crypto_level crypto_level, - ngtcp2_strm *crypto, ngtcp2_rst *rst, - ngtcp2_default_cc *cc, ngtcp2_log *log, ngtcp2_qlog *qlog, - const ngtcp2_mem *mem); +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, const ngtcp2_mem *mem); /* * ngtcp2_rtb_free deallocates resources allocated for |rtb|. @@ -251,7 +251,8 @@ void ngtcp2_rtb_free(ngtcp2_rtb *rtb); * NGTCP2_ERR_NOMEM * Out of memory */ -int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent); +int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, + ngtcp2_conn_stat *cstat); /* * ngtcp2_rtb_head returns the iterator which points to the entry @@ -276,8 +277,8 @@ ngtcp2_ksl_it ngtcp2_rtb_head(ngtcp2_rtb *rtb); * Out of memory */ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, - ngtcp2_conn *conn, ngtcp2_tstamp pkt_ts, - ngtcp2_tstamp ts); + ngtcp2_conn_stat *cstat, ngtcp2_conn *conn, + ngtcp2_tstamp pkt_ts, ngtcp2_tstamp ts); /* * ngtcp2_rtb_detect_lost_pkt detects lost packets and prepends the @@ -286,7 +287,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, * handle them. |pto| is PTO. */ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, - ngtcp2_rcvry_stat *rcs, ngtcp2_duration pto, + ngtcp2_conn_stat *cstat, ngtcp2_duration pto, ngtcp2_tstamp ts); /* @@ -294,7 +295,8 @@ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, * all frames to |*pfrc|. Even when this function fails, some frames * might be prepended to |*pfrc| and the caller should handle them. */ -void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc); +void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, + ngtcp2_conn_stat *cstat); /* * ngtcp2_rtb_on_crypto_timeout copies all unacknowledged CRYPTO @@ -307,7 +309,8 @@ void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc); * NGTCP2_ERR_NOMEM * Out of memory */ -int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc); +int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, + ngtcp2_conn_stat *cstat); /* * ngtcp2_rtb_empty returns nonzero if |rtb| have no entry. @@ -315,15 +318,10 @@ int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc); int ngtcp2_rtb_empty(ngtcp2_rtb *rtb); /* - * ngtcp2_rtb_get_bytes_in_flight returns the sum of bytes in flight - * for the stored entries. - */ -uint64_t ngtcp2_rtb_get_bytes_in_flight(ngtcp2_rtb *rtb); - -/* - * ngtcp2_rtb_num_ack_eliciting returns the number of ACK eliciting - * entries. + * ngtcp2_rtb_reset_cc_state resets congestion state in |rtb|. + * |cc_pkt_num| is the next outbound packet number which is sent under + * new congestion state. */ -size_t ngtcp2_rtb_num_ack_eliciting(ngtcp2_rtb *rtb); +void ngtcp2_rtb_reset_cc_state(ngtcp2_rtb *rtb, int64_t cc_pkt_num); #endif /* NGTCP2_RTB_H */ diff --git a/deps/ngtcp2/lib/ngtcp2_strm.c b/deps/ngtcp2/lib/ngtcp2_strm.c index b6b315489dc798..6c02e8a2274bdc 100644 --- a/deps/ngtcp2/lib/ngtcp2_strm.c +++ b/deps/ngtcp2/lib/ngtcp2_strm.c @@ -32,7 +32,7 @@ #include "ngtcp2_vec.h" static int offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { - return *lhs->i < *rhs->i; + return *(int64_t *)lhs < *(int64_t *)rhs; } int ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags, @@ -110,13 +110,10 @@ void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags) { } int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) { - ngtcp2_ksl_key key; - assert(frc->fr.type == NGTCP2_FRAME_STREAM); assert(frc->next == NULL); - return ngtcp2_ksl_insert(&strm->tx.streamfrq, NULL, - ngtcp2_ksl_key_ptr(&key, &frc->fr.stream.offset), + return ngtcp2_ksl_insert(&strm->tx.streamfrq, NULL, &frc->fr.stream.offset, frc); } @@ -131,7 +128,6 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, ngtcp2_vec b[NGTCP2_MAX_STREAM_DATACNT]; size_t acnt, bcnt; ngtcp2_ksl_it it; - ngtcp2_ksl_key key, old_key; uint64_t old_offset; if (ngtcp2_ksl_len(&strm->tx.streamfrq) == 0) { @@ -153,8 +149,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, } } - ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, - ngtcp2_ksl_key_ptr(&key, &fr->offset)); + ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, &fr->offset); if (datalen > left) { ngtcp2_vec_copy(a, fr->data, fr->datacnt); @@ -182,8 +177,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, nfr->datacnt = bcnt; ngtcp2_vec_copy(nfr->data, b, bcnt); - rv = ngtcp2_ksl_insert(&strm->tx.streamfrq, NULL, - ngtcp2_ksl_key_ptr(&key, &nfr->offset), nfrc); + rv = ngtcp2_ksl_insert(&strm->tx.streamfrq, NULL, &nfr->offset, nfrc); if (rv != 0) { assert(ngtcp2_err_is_fatal(rv)); ngtcp2_frame_chain_del(nfrc, strm->mem); @@ -228,8 +222,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, if (nfr->fin && nfr->datacnt == 0) { fr->fin = 1; - ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, - ngtcp2_ksl_key_ptr(&key, &nfr->offset)); + ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, &nfr->offset); ngtcp2_frame_chain_del(nfrc, strm->mem); break; } @@ -245,8 +238,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, if (nfr->datacnt == 0) { fr->fin = nfr->fin; - ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, - ngtcp2_ksl_key_ptr(&key, &nfr->offset)); + ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, &nfr->offset); ngtcp2_frame_chain_del(nfrc, strm->mem); continue; } @@ -254,9 +246,7 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc, old_offset = nfr->offset; nfr->offset += nmerged; - ngtcp2_ksl_update_key(&strm->tx.streamfrq, - ngtcp2_ksl_key_ptr(&old_key, &old_offset), - ngtcp2_ksl_key_ptr(&key, &nfr->offset)); + ngtcp2_ksl_update_key(&strm->tx.streamfrq, &old_offset, &nfr->offset); break; } diff --git a/deps/ngtcp2/ngtcp2.gyp b/deps/ngtcp2/ngtcp2.gyp index f86dcc5693e98a..532ee07b61e308 100644 --- a/deps/ngtcp2/ngtcp2.gyp +++ b/deps/ngtcp2/ngtcp2.gyp @@ -10,8 +10,9 @@ 'type': 'static_library', 'include_dirs': [ 'lib/includes', - 'crypto/includes', 'lib', + 'crypto/includes', + 'crypto' ], 'defines': [ 'BUILDING_NGTCP2', @@ -44,7 +45,7 @@ 'defines': [ 'NGTCP2_STATICLIB' ], 'include_dirs': [ 'lib/includes', - 'crypto/includes' + 'crypto/includes', ] }, 'sources': [ @@ -79,19 +80,14 @@ 'lib/ngtcp2_map.h', 'lib/ngtcp2_mem.c', 'lib/ngtcp2_mem.h', - 'lib/ngtcp2_net.h', 'lib/ngtcp2_path.c', 'lib/ngtcp2_path.h', - 'lib/ngtcp2_pipeack.c', - 'lib/ngtcp2_pipeack.h', 'lib/ngtcp2_pkt.c', 'lib/ngtcp2_pkt.h', 'lib/ngtcp2_ppe.c', 'lib/ngtcp2_ppe.h', 'lib/ngtcp2_pq.c', 'lib/ngtcp2_pq.h', - 'lib/ngtcp2_psl.c', - 'lib/ngtcp2_psl.h', 'lib/ngtcp2_pv.c', 'lib/ngtcp2_pv.h', 'lib/ngtcp2_qlog.c',