Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2020-08-12 20:56:00 +0300
committerJames M Snell <jasnell@gmail.com>2020-08-21 19:18:39 +0300
commitc788be2e6ecee66759f769c35f8940ea74b39da6 (patch)
tree14a529f76b340716ae488c232944cff89b6b2afe /deps
parentbc8a4df1bbf9c09b8d978a21b80b342b85a37f3c (diff)
deps: update ngtcp2
Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/34752 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'deps')
-rw-r--r--deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h117
-rw-r--r--deps/ngtcp2/crypto/openssl/openssl.c167
-rw-r--r--deps/ngtcp2/crypto/shared.c341
-rw-r--r--deps/ngtcp2/crypto/shared.h23
-rw-r--r--deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h431
-rw-r--r--deps/ngtcp2/lib/ngtcp2_acktr.c2
-rw-r--r--deps/ngtcp2/lib/ngtcp2_addr.c43
-rw-r--r--deps/ngtcp2/lib/ngtcp2_addr.h3
-rw-r--r--deps/ngtcp2/lib/ngtcp2_cc.c61
-rw-r--r--deps/ngtcp2/lib/ngtcp2_cc.h2
-rw-r--r--deps/ngtcp2/lib/ngtcp2_cid.c1
-rw-r--r--deps/ngtcp2/lib/ngtcp2_conn.c1454
-rw-r--r--deps/ngtcp2/lib/ngtcp2_conn.h101
-rw-r--r--deps/ngtcp2/lib/ngtcp2_conv.c16
-rw-r--r--deps/ngtcp2/lib/ngtcp2_conv.h41
-rw-r--r--deps/ngtcp2/lib/ngtcp2_crypto.c18
-rw-r--r--deps/ngtcp2/lib/ngtcp2_crypto.h10
-rw-r--r--deps/ngtcp2/lib/ngtcp2_err.c4
-rw-r--r--deps/ngtcp2/lib/ngtcp2_gaptr.c12
-rw-r--r--deps/ngtcp2/lib/ngtcp2_gaptr.h7
-rw-r--r--deps/ngtcp2/lib/ngtcp2_ksl.c27
-rw-r--r--deps/ngtcp2/lib/ngtcp2_ksl.h20
-rw-r--r--deps/ngtcp2/lib/ngtcp2_map.c239
-rw-r--r--deps/ngtcp2/lib/ngtcp2_map.h8
-rw-r--r--deps/ngtcp2/lib/ngtcp2_path.c20
-rw-r--r--deps/ngtcp2/lib/ngtcp2_pkt.c27
-rw-r--r--deps/ngtcp2/lib/ngtcp2_pkt.h3
-rw-r--r--deps/ngtcp2/lib/ngtcp2_ppe.c5
-rw-r--r--deps/ngtcp2/lib/ngtcp2_qlog.c28
-rw-r--r--deps/ngtcp2/lib/ngtcp2_qlog.h7
-rw-r--r--deps/ngtcp2/lib/ngtcp2_rcvry.h2
-rw-r--r--deps/ngtcp2/lib/ngtcp2_ringbuf.c12
-rw-r--r--deps/ngtcp2/lib/ngtcp2_ringbuf.h2
-rw-r--r--deps/ngtcp2/lib/ngtcp2_rtb.c779
-rw-r--r--deps/ngtcp2/lib/ngtcp2_rtb.h131
-rw-r--r--deps/ngtcp2/lib/ngtcp2_strm.c467
-rw-r--r--deps/ngtcp2/lib/ngtcp2_strm.h53
37 files changed, 3439 insertions, 1245 deletions
diff --git a/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h b/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
index 3197c5dcb86..4b6885a08e4 100644
--- a/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
+++ b/deps/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
@@ -210,8 +210,9 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_packet_protection_key(
*/
NGTCP2_EXTERN int ngtcp2_crypto_encrypt(uint8_t *dest,
const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *plaintext,
- size_t plaintextlen, const uint8_t *key,
+ size_t plaintextlen,
const uint8_t *nonce, size_t noncelen,
const uint8_t *ad, size_t adlen);
@@ -227,9 +228,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_encrypt(uint8_t *dest,
*/
NGTCP2_EXTERN int
ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *plaintext, size_t plaintextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen);
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen);
/**
* @function
@@ -243,11 +245,13 @@ ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
*
* This function returns 0 if it succeeds, or -1.
*/
-NGTCP2_EXTERN int
-ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
- const uint8_t *ciphertext, size_t ciphertextlen,
- const uint8_t *key, const uint8_t *nonce, size_t noncelen,
- const uint8_t *ad, size_t adlen);
+NGTCP2_EXTERN int ngtcp2_crypto_decrypt(uint8_t *dest,
+ const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *ciphertext,
+ size_t ciphertextlen,
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen);
/**
* @function
@@ -261,9 +265,10 @@ ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
*/
NGTCP2_EXTERN int
ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *ciphertext, size_t ciphertextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen);
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen);
/**
* @function
@@ -277,7 +282,7 @@ ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
*/
NGTCP2_EXTERN int ngtcp2_crypto_hp_mask(uint8_t *dest,
const ngtcp2_crypto_cipher *hp,
- const uint8_t *key,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx,
const uint8_t *sample);
/**
@@ -290,10 +295,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_hp_mask(uint8_t *dest,
* This function returns 0 if it succeeds, or
* :enum:`NGTCP2_ERR_CALLBACK_FAILURE`.
*/
-NGTCP2_EXTERN int ngtcp2_crypto_hp_mask_cb(uint8_t *dest,
- const ngtcp2_crypto_cipher *hp,
- const uint8_t *key,
- const uint8_t *sample);
+NGTCP2_EXTERN int
+ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx,
+ const uint8_t *sample);
/**
* @function
@@ -381,10 +386,12 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_tx_key(
* The derived packet protection key for decryption is written to the
* buffer pointed by |rx_key|. The derived packet protection IV for
* decryption is written to the buffer pointed by |rx_iv|.
+ * |rx_aead_ctx| must be constructed with |rx_key|.
*
* The derived packet protection key for encryption is written to the
* buffer pointed by |tx_key|. The derived packet protection IV for
* encryption is written to the buffer pointed by |tx_iv|.
+ * |tx_aead_ctx| must be constructed with |rx_key|.
*
* |current_rx_secret| and |current_tx_secret| are the current traffic
* secrets for decryption and encryption. |secretlen| specifies the
@@ -397,12 +404,12 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_tx_key(
*
* This function returns 0 if it succeeds, or -1.
*/
-NGTCP2_EXTERN int
-ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret,
- uint8_t *tx_secret, uint8_t *rx_key, uint8_t *rx_iv,
- uint8_t *tx_key, uint8_t *tx_iv,
- const uint8_t *current_rx_secret,
- const uint8_t *current_tx_secret, size_t secretlen);
+NGTCP2_EXTERN int ngtcp2_crypto_update_key(
+ ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_key, uint8_t *rx_iv,
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_key, uint8_t *tx_iv,
+ const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
+ size_t secretlen);
/**
* @function
@@ -415,8 +422,9 @@ ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret,
* :enum:`NGTCP2_ERR_CALLBACK_FAILURE`.
*/
NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb(
- ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, uint8_t *rx_key,
- uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv,
+ ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
size_t secretlen, void *user_data);
@@ -543,6 +551,69 @@ ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid,
const ngtcp2_cid *scid, const ngtcp2_cid *odcid,
const uint8_t *token, size_t tokenlen);
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_aead_ctx_encrypt_init` initializes |aead_ctx| with
+ * new AEAD cipher context object for encryption which is constructed
+ * to use |key| as encryption key. |aead| specifies AEAD cipher to
+ * use. |noncelen| is the length of nonce.
+ *
+ * This function returns 0 if it succeeds, or -1.
+ */
+NGTCP2_EXTERN int
+ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
+ const ngtcp2_crypto_aead *aead,
+ const uint8_t *key, size_t noncelen);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_aead_ctx_decrypt_init` initializes |aead_ctx| with
+ * new AEAD cipher context object for decryption which is constructed
+ * to use |key| as encryption key. |aead| specifies AEAD cipher to
+ * use. |noncelen| is the length of nonce.
+ *
+ * This function returns 0 if it succeeds, or -1.
+ */
+NGTCP2_EXTERN int
+ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
+ const ngtcp2_crypto_aead *aead,
+ const uint8_t *key, size_t noncelen);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_aead_ctx_free` frees up resources used by
+ * |aead_ctx|. This function does not free the memory pointed by
+ * |aead_ctx| itself.
+ */
+NGTCP2_EXTERN void
+ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_delete_crypto_aead_ctx_cb` deletes the given |aead_ctx|.
+ *
+ * This function can be directly passed to delete_crypto_aead_ctx
+ * field in ngtcp2_callbacks.
+ */
+NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_aead_ctx_cb(
+ ngtcp2_conn *conn, ngtcp2_crypto_aead_ctx *aead_ctx, void *user_data);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_delete_crypto_cipher_ctx_cb` deletes the given
+ * |cipher_ctx|.
+ *
+ * This function can be directly passed to delete_crypto_cipher_ctx
+ * field in ngtcp2_callbacks.
+ */
+NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_cipher_ctx_cb(
+ ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data);
+
#ifdef __cplusplus
}
#endif
diff --git a/deps/ngtcp2/crypto/openssl/openssl.c b/deps/ngtcp2/crypto/openssl/openssl.c
index 60e7250eae9..d1937441efb 100644
--- a/deps/ngtcp2/crypto/openssl/openssl.c
+++ b/deps/ngtcp2/crypto/openssl/openssl.c
@@ -173,6 +173,92 @@ size_t ngtcp2_crypto_aead_taglen(const ngtcp2_crypto_aead *aead) {
return crypto_aead_taglen(aead->native_handle);
}
+int ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
+ const ngtcp2_crypto_aead *aead,
+ const uint8_t *key, size_t noncelen) {
+ const EVP_CIPHER *cipher = aead->native_handle;
+ EVP_CIPHER_CTX *actx;
+
+ actx = EVP_CIPHER_CTX_new();
+ if (actx == NULL) {
+ return -1;
+ }
+
+ if (!EVP_EncryptInit_ex(actx, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen,
+ NULL) ||
+ (cipher == EVP_aes_128_ccm() &&
+ !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG,
+ (int)crypto_aead_taglen(cipher), NULL)) ||
+ !EVP_EncryptInit_ex(actx, NULL, NULL, key, NULL)) {
+ EVP_CIPHER_CTX_free(actx);
+ return -1;
+ }
+
+ aead_ctx->native_handle = actx;
+
+ return 0;
+}
+
+int ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
+ const ngtcp2_crypto_aead *aead,
+ const uint8_t *key, size_t noncelen) {
+ const EVP_CIPHER *cipher = aead->native_handle;
+ EVP_CIPHER_CTX *actx;
+
+ actx = EVP_CIPHER_CTX_new();
+ if (actx == NULL) {
+ return -1;
+ }
+
+ if (!EVP_DecryptInit_ex(actx, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen,
+ NULL) ||
+ (cipher == EVP_aes_128_ccm() &&
+ !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG,
+ (int)crypto_aead_taglen(cipher), NULL)) ||
+ !EVP_DecryptInit_ex(actx, NULL, NULL, key, NULL)) {
+ EVP_CIPHER_CTX_free(actx);
+ return -1;
+ }
+
+ aead_ctx->native_handle = actx;
+
+ return 0;
+}
+
+void ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx) {
+ if (aead_ctx->native_handle) {
+ EVP_CIPHER_CTX_free(aead_ctx->native_handle);
+ }
+}
+
+int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
+ const ngtcp2_crypto_cipher *cipher,
+ const uint8_t *key) {
+ EVP_CIPHER_CTX *actx;
+
+ actx = EVP_CIPHER_CTX_new();
+ if (actx == NULL) {
+ return -1;
+ }
+
+ if (!EVP_EncryptInit_ex(actx, cipher->native_handle, NULL, key, NULL)) {
+ EVP_CIPHER_CTX_free(actx);
+ return -1;
+ }
+
+ cipher_ctx->native_handle = actx;
+
+ return 0;
+}
+
+void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx) {
+ if (cipher_ctx->native_handle) {
+ EVP_CIPHER_CTX_free(cipher_ctx->native_handle);
+ }
+}
+
int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md,
const uint8_t *secret, size_t secretlen,
const uint8_t *salt, size_t saltlen) {
@@ -226,26 +312,18 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen,
}
int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *plaintext, size_t plaintextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen) {
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen) {
const EVP_CIPHER *cipher = aead->native_handle;
size_t taglen = crypto_aead_taglen(cipher);
- EVP_CIPHER_CTX *actx;
- int rv = 0;
+ EVP_CIPHER_CTX *actx = aead_ctx->native_handle;
int len;
- actx = EVP_CIPHER_CTX_new();
- if (actx == NULL) {
- return -1;
- }
+ (void)noncelen;
- if (!EVP_EncryptInit_ex(actx, cipher, NULL, NULL, NULL) ||
- !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen,
- NULL) ||
- (cipher == EVP_aes_128_ccm() &&
- !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen, NULL)) ||
- !EVP_EncryptInit_ex(actx, NULL, NULL, key, nonce) ||
+ if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, nonce) ||
(cipher == EVP_aes_128_ccm() &&
!EVP_EncryptUpdate(actx, NULL, &len, NULL, (int)plaintextlen)) ||
!EVP_EncryptUpdate(actx, NULL, &len, ad, (int)adlen) ||
@@ -253,25 +331,25 @@ int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
!EVP_EncryptFinal_ex(actx, dest + len, &len) ||
!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_GET_TAG, (int)taglen,
dest + plaintextlen)) {
- rv = -1;
+ return -1;
}
- EVP_CIPHER_CTX_free(actx);
-
- return rv;
+ return 0;
}
int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *ciphertext, size_t ciphertextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen) {
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen) {
const EVP_CIPHER *cipher = aead->native_handle;
size_t taglen = crypto_aead_taglen(cipher);
- EVP_CIPHER_CTX *actx;
- int rv = 0;
+ EVP_CIPHER_CTX *actx = aead_ctx->native_handle;
int len;
const uint8_t *tag;
+ (void)noncelen;
+
if (taglen > ciphertextlen) {
return -1;
}
@@ -279,56 +357,37 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
ciphertextlen -= taglen;
tag = ciphertext + ciphertextlen;
- actx = EVP_CIPHER_CTX_new();
- if (actx == NULL) {
- return -1;
- }
-
- if (!EVP_DecryptInit_ex(actx, cipher, NULL, NULL, NULL) ||
- !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen,
- NULL) ||
- (cipher == EVP_aes_128_ccm() &&
- !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen,
- (uint8_t *)tag)) ||
- !EVP_DecryptInit_ex(actx, NULL, NULL, key, nonce) ||
+ if (!EVP_DecryptInit_ex(actx, NULL, NULL, NULL, nonce) ||
+ !EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen,
+ (uint8_t *)tag) ||
(cipher == EVP_aes_128_ccm() &&
!EVP_DecryptUpdate(actx, NULL, &len, NULL, (int)ciphertextlen)) ||
!EVP_DecryptUpdate(actx, NULL, &len, ad, (int)adlen) ||
!EVP_DecryptUpdate(actx, dest, &len, ciphertext, (int)ciphertextlen) ||
(cipher != EVP_aes_128_ccm() &&
- (!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen,
- (uint8_t *)tag) ||
- !EVP_DecryptFinal_ex(actx, dest + ciphertextlen, &len)))) {
- rv = -1;
+ !EVP_DecryptFinal_ex(actx, dest + ciphertextlen, &len))) {
+ return -1;
}
- EVP_CIPHER_CTX_free(actx);
-
- return rv;
+ return 0;
}
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
- const uint8_t *hp_key, const uint8_t *sample) {
+ const ngtcp2_crypto_cipher_ctx *hp_ctx,
+ const uint8_t *sample) {
static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
- const EVP_CIPHER *cipher = hp->native_handle;
- EVP_CIPHER_CTX *actx;
- int rv = 0;
+ EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
int len;
- actx = EVP_CIPHER_CTX_new();
- if (actx == NULL) {
- return -1;
- }
+ (void)hp;
- if (!EVP_EncryptInit_ex(actx, cipher, NULL, hp_key, sample) ||
+ if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
!EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT) - 1) ||
!EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) {
- rv = -1;
+ return -1;
}
- EVP_CIPHER_CTX_free(actx);
-
- return rv;
+ return 0;
}
static OSSL_ENCRYPTION_LEVEL
diff --git a/deps/ngtcp2/crypto/shared.c b/deps/ngtcp2/crypto/shared.c
index bea088e85f3..7e5219c52f2 100644
--- a/deps/ngtcp2/crypto/shared.c
+++ b/deps/ngtcp2/crypto/shared.c
@@ -153,9 +153,11 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key,
const ngtcp2_crypto_ctx *ctx;
const ngtcp2_crypto_aead *aead;
const ngtcp2_crypto_md *md;
+ const ngtcp2_crypto_cipher *hp;
+ ngtcp2_crypto_aead_ctx aead_ctx = {0};
+ ngtcp2_crypto_cipher_ctx hp_ctx = {0};
void *tls = ngtcp2_conn_get_tls_native_handle(conn);
uint8_t keybuf[64], ivbuf[64], hp_keybuf[64];
- size_t keylen;
size_t ivlen;
int rv;
@@ -185,7 +187,7 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key,
aead = &ctx->aead;
md = &ctx->md;
- keylen = ngtcp2_crypto_aead_keylen(aead);
+ hp = &ctx->hp;
ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md,
@@ -193,36 +195,79 @@ int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key,
return -1;
}
+ if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, aead, key, ivlen) != 0) {
+ goto fail;
+ }
+
+ if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, hp, hp_key) != 0) {
+ goto fail;
+ }
+
switch (level) {
case NGTCP2_CRYPTO_LEVEL_EARLY:
- rv = ngtcp2_conn_install_early_key(conn, key, iv, hp_key, keylen, ivlen);
+ rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx);
if (rv != 0) {
- return -1;
+ goto fail;
}
break;
case NGTCP2_CRYPTO_LEVEL_HANDSHAKE:
- rv = ngtcp2_conn_install_rx_handshake_key(conn, key, iv, hp_key, keylen,
- ivlen);
+ rv = ngtcp2_conn_install_rx_handshake_key(conn, &aead_ctx, iv, ivlen,
+ &hp_ctx);
if (rv != 0) {
- return -1;
+ goto fail;
}
break;
case NGTCP2_CRYPTO_LEVEL_APP:
if (!ngtcp2_conn_is_server(conn)) {
rv = ngtcp2_crypto_set_remote_transport_params(conn, tls);
if (rv != 0) {
- return -1;
+ goto fail;
}
}
- rv = ngtcp2_conn_install_rx_key(conn, secret, key, iv, hp_key, secretlen,
- keylen, ivlen);
+ rv = ngtcp2_conn_install_rx_key(conn, secret, secretlen, &aead_ctx, iv,
+ ivlen, &hp_ctx);
if (rv != 0) {
- return -1;
+ goto fail;
}
break;
default:
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ ngtcp2_crypto_cipher_ctx_free(&hp_ctx);
+ ngtcp2_crypto_aead_ctx_free(&aead_ctx);
+
+ return -1;
+}
+
+/*
+ * 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, &params);
+
+ nwrite = ngtcp2_encode_transport_params(buf, sizeof(buf), exttype, &params);
+ if (nwrite < 0) {
+ return -1;
+ }
+
+ if (ngtcp2_crypto_set_local_transport_params(tls, buf, (size_t)nwrite) != 0) {
return -1;
}
@@ -237,9 +282,11 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key,
const ngtcp2_crypto_ctx *ctx;
const ngtcp2_crypto_aead *aead;
const ngtcp2_crypto_md *md;
+ const ngtcp2_crypto_cipher *hp;
+ ngtcp2_crypto_aead_ctx aead_ctx = {0};
+ ngtcp2_crypto_cipher_ctx hp_ctx = {0};
void *tls = ngtcp2_conn_get_tls_native_handle(conn);
uint8_t keybuf[64], ivbuf[64], hp_keybuf[64];
- size_t keylen;
size_t ivlen;
int rv;
@@ -269,7 +316,7 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key,
aead = &ctx->aead;
md = &ctx->md;
- keylen = ngtcp2_crypto_aead_keylen(aead);
+ hp = &ctx->hp;
ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md,
@@ -277,40 +324,59 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key,
return -1;
}
+ if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, aead, key, ivlen) != 0) {
+ goto fail;
+ }
+
+ if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, hp, hp_key) != 0) {
+ goto fail;
+ }
+
switch (level) {
case NGTCP2_CRYPTO_LEVEL_EARLY:
- rv = ngtcp2_conn_install_early_key(conn, key, iv, hp_key, keylen, ivlen);
+ rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx);
if (rv != 0) {
- return -1;
+ goto fail;
}
break;
case NGTCP2_CRYPTO_LEVEL_HANDSHAKE:
+ rv = ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, iv, ivlen,
+ &hp_ctx);
+ if (rv != 0) {
+ goto fail;
+ }
+
if (ngtcp2_conn_is_server(conn)) {
rv = ngtcp2_crypto_set_remote_transport_params(conn, tls);
if (rv != 0) {
- return -1;
+ goto fail;
}
- }
- rv = ngtcp2_conn_install_tx_handshake_key(conn, key, iv, hp_key, keylen,
- ivlen);
- if (rv != 0) {
- return -1;
+ if (crypto_set_local_transport_params(conn, tls) != 0) {
+ goto fail;
+ }
}
+
break;
case NGTCP2_CRYPTO_LEVEL_APP:
- rv = ngtcp2_conn_install_tx_key(conn, secret, key, iv, hp_key, secretlen,
- keylen, ivlen);
+ rv = ngtcp2_conn_install_tx_key(conn, secret, secretlen, &aead_ctx, iv,
+ ivlen, &hp_ctx);
if (rv != 0) {
- return -1;
+ goto fail;
}
break;
default:
- return -1;
+ goto fail;
}
return 0;
+
+fail:
+ ngtcp2_crypto_cipher_ctx_free(&hp_ctx);
+ ngtcp2_crypto_aead_ctx_free(&aead_ctx);
+
+ return -1;
}
int ngtcp2_crypto_derive_and_install_initial_key(
@@ -329,7 +395,13 @@ int ngtcp2_crypto_derive_and_install_initial_key(
uint8_t tx_hp_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN];
ngtcp2_crypto_ctx ctx;
ngtcp2_crypto_aead retry_aead;
+ ngtcp2_crypto_aead_ctx rx_aead_ctx = {0};
+ ngtcp2_crypto_cipher_ctx rx_hp_ctx = {0};
+ ngtcp2_crypto_aead_ctx tx_aead_ctx = {0};
+ ngtcp2_crypto_cipher_ctx tx_hp_ctx = {0};
+ ngtcp2_crypto_aead_ctx retry_aead_ctx = {0};
int rv;
+ int server = ngtcp2_conn_is_server(conn);
ngtcp2_crypto_ctx_initial(&ctx);
@@ -366,8 +438,8 @@ int ngtcp2_crypto_derive_and_install_initial_key(
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) {
+ server ? NGTCP2_CRYPTO_SIDE_SERVER : NGTCP2_CRYPTO_SIDE_CLIENT) !=
+ 0) {
return -1;
}
@@ -383,27 +455,69 @@ int ngtcp2_crypto_derive_and_install_initial_key(
return -1;
}
- rv = ngtcp2_conn_install_initial_key(
- conn, rx_key, rx_iv, rx_hp_key, tx_key, tx_iv, tx_hp_key,
- NGTCP2_CRYPTO_INITIAL_KEYLEN, NGTCP2_CRYPTO_INITIAL_IVLEN);
+ if (ngtcp2_crypto_aead_ctx_decrypt_init(&rx_aead_ctx, &ctx.aead, rx_key,
+ NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
+ goto fail;
+ }
+
+ if (ngtcp2_crypto_cipher_ctx_encrypt_init(&rx_hp_ctx, &ctx.hp, rx_hp_key) !=
+ 0) {
+ goto fail;
+ }
+
+ if (ngtcp2_crypto_aead_ctx_encrypt_init(&tx_aead_ctx, &ctx.aead, tx_key,
+ NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
+ goto fail;
+ }
+
+ if (ngtcp2_crypto_cipher_ctx_encrypt_init(&tx_hp_ctx, &ctx.hp, tx_hp_key) !=
+ 0) {
+ goto fail;
+ }
+
+ if (!server && !ngtcp2_conn_after_retry(conn)) {
+ ngtcp2_crypto_aead_retry(&retry_aead);
+
+ if (ngtcp2_crypto_aead_ctx_encrypt_init(
+ &retry_aead_ctx, &retry_aead, (const uint8_t *)NGTCP2_RETRY_KEY,
+ sizeof(NGTCP2_RETRY_NONCE) - 1) != 0) {
+ goto fail;
+ }
+ }
+
+ rv = ngtcp2_conn_install_initial_key(conn, &rx_aead_ctx, rx_iv, &rx_hp_ctx,
+ &tx_aead_ctx, tx_iv, &tx_hp_ctx,
+ NGTCP2_CRYPTO_INITIAL_IVLEN);
if (rv != 0) {
- return -1;
+ goto fail;
}
- ngtcp2_conn_set_retry_aead(conn, ngtcp2_crypto_aead_retry(&retry_aead));
+ if (retry_aead_ctx.native_handle) {
+ ngtcp2_conn_set_retry_aead(conn, &retry_aead, &retry_aead_ctx);
+ }
return 0;
+
+fail:
+ ngtcp2_crypto_aead_ctx_free(&retry_aead_ctx);
+ ngtcp2_crypto_cipher_ctx_free(&tx_hp_ctx);
+ ngtcp2_crypto_aead_ctx_free(&tx_aead_ctx);
+ ngtcp2_crypto_cipher_ctx_free(&rx_hp_ctx);
+ ngtcp2_crypto_aead_ctx_free(&rx_aead_ctx);
+
+ return -1;
}
-int ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret,
- uint8_t *tx_secret, uint8_t *rx_key,
- uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv,
- const uint8_t *current_rx_secret,
- const uint8_t *current_tx_secret,
- size_t secretlen) {
+int ngtcp2_crypto_update_key(
+ ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_key, uint8_t *rx_iv,
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_key, uint8_t *tx_iv,
+ const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
+ size_t secretlen) {
const ngtcp2_crypto_ctx *ctx = ngtcp2_conn_get_crypto_ctx(conn);
const ngtcp2_crypto_aead *aead = &ctx->aead;
const ngtcp2_crypto_md *md = &ctx->md;
+ size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
if (ngtcp2_crypto_update_traffic_secret(rx_secret, md, current_rx_secret,
secretlen) != 0) {
@@ -425,51 +539,69 @@ int ngtcp2_crypto_update_key(ngtcp2_conn *conn, uint8_t *rx_secret,
return -1;
}
+ if (ngtcp2_crypto_aead_ctx_decrypt_init(rx_aead_ctx, aead, rx_key, ivlen) !=
+ 0) {
+ return -1;
+ }
+
+ if (ngtcp2_crypto_aead_ctx_encrypt_init(tx_aead_ctx, aead, tx_key, ivlen) !=
+ 0) {
+ ngtcp2_crypto_aead_ctx_free(rx_aead_ctx);
+ rx_aead_ctx->native_handle = NULL;
+ return -1;
+ }
+
return 0;
}
int ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *plaintext, size_t plaintextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen) {
- if (ngtcp2_crypto_encrypt(dest, aead, plaintext, plaintextlen, key, nonce,
- noncelen, ad, adlen) != 0) {
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen) {
+ if (ngtcp2_crypto_encrypt(dest, aead, aead_ctx, plaintext, plaintextlen,
+ nonce, noncelen, ad, adlen) != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
int ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *ciphertext, size_t ciphertextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen) {
- if (ngtcp2_crypto_decrypt(dest, aead, ciphertext, ciphertextlen, key, nonce,
- noncelen, ad, adlen) != 0) {
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen) {
+ if (ngtcp2_crypto_decrypt(dest, aead, aead_ctx, ciphertext, ciphertextlen,
+ nonce, noncelen, ad, adlen) != 0) {
return NGTCP2_ERR_TLS_DECRYPT;
}
return 0;
}
int ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
- const uint8_t *hp_key, const uint8_t *sample) {
- if (ngtcp2_crypto_hp_mask(dest, hp, hp_key, sample) != 0) {
+ const ngtcp2_crypto_cipher_ctx *hp_ctx,
+ const uint8_t *sample) {
+ if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
-int ngtcp2_crypto_update_key_cb(ngtcp2_conn *conn, uint8_t *rx_secret,
- uint8_t *tx_secret, uint8_t *rx_key,
- uint8_t *rx_iv, uint8_t *tx_key, uint8_t *tx_iv,
- const uint8_t *current_rx_secret,
- const uint8_t *current_tx_secret,
- size_t secretlen, void *user_data) {
+int ngtcp2_crypto_update_key_cb(
+ ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
+ const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
+ size_t secretlen, void *user_data) {
+ uint8_t rx_key[64];
+ uint8_t tx_key[64];
(void)conn;
(void)user_data;
- if (ngtcp2_crypto_update_key(conn, rx_secret, tx_secret, rx_key, rx_iv,
- tx_key, tx_iv, current_rx_secret,
- current_tx_secret, secretlen) != 0) {
+ if (ngtcp2_crypto_update_key(conn, rx_secret, tx_secret, rx_aead_ctx, rx_key,
+ rx_iv, tx_aead_ctx, tx_key, tx_iv,
+ current_rx_secret, current_tx_secret,
+ secretlen) != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
@@ -509,6 +641,8 @@ ngtcp2_ssize ngtcp2_crypto_write_connection_close(uint8_t *dest, size_t destlen,
uint8_t tx_hp_key[NGTCP2_CRYPTO_INITIAL_KEYLEN];
ngtcp2_crypto_ctx ctx;
ngtcp2_ssize spktlen;
+ ngtcp2_crypto_aead_ctx aead_ctx = {0};
+ ngtcp2_crypto_cipher_ctx hp_ctx = {0};
ngtcp2_crypto_ctx_initial(&ctx);
@@ -524,13 +658,28 @@ ngtcp2_ssize ngtcp2_crypto_write_connection_close(uint8_t *dest, size_t destlen,
return -1;
}
+ if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &ctx.aead, tx_key,
+ NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
+ spktlen = -1;
+ goto end;
+ }
+
+ if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, &ctx.hp, tx_hp_key) != 0) {
+ spktlen = -1;
+ goto end;
+ }
+
spktlen = ngtcp2_pkt_write_connection_close(
dest, destlen, dcid, scid, error_code, ngtcp2_crypto_encrypt_cb,
- &ctx.aead, tx_key, tx_iv, ngtcp2_crypto_hp_mask_cb, &ctx.hp, tx_hp_key);
+ &ctx.aead, &aead_ctx, tx_iv, ngtcp2_crypto_hp_mask_cb, &ctx.hp, &hp_ctx);
if (spktlen < 0) {
- return -1;
+ spktlen = -1;
}
+end:
+ ngtcp2_crypto_cipher_ctx_free(&hp_ctx);
+ ngtcp2_crypto_aead_ctx_free(&aead_ctx);
+
return spktlen;
}
@@ -541,45 +690,26 @@ ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen,
const uint8_t *token, size_t tokenlen) {
ngtcp2_crypto_aead aead;
ngtcp2_ssize spktlen;
+ ngtcp2_crypto_aead_ctx aead_ctx = {0};
ngtcp2_crypto_aead_retry(&aead);
- spktlen = ngtcp2_pkt_write_retry(dest, destlen, dcid, scid, odcid, token,
- tokenlen, ngtcp2_crypto_encrypt_cb, &aead);
- if (spktlen < 0) {
+ if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &aead,
+ (const uint8_t *)NGTCP2_RETRY_KEY,
+ NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
return -1;
}
- 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, &params);
-
- nwrite = ngtcp2_encode_transport_params(buf, sizeof(buf), exttype, &params);
- if (nwrite < 0) {
- return -1;
+ spktlen =
+ ngtcp2_pkt_write_retry(dest, destlen, dcid, scid, odcid, token, tokenlen,
+ ngtcp2_crypto_encrypt_cb, &aead, &aead_ctx);
+ if (spktlen < 0) {
+ spktlen = -1;
}
- if (ngtcp2_crypto_set_local_transport_params(tls, buf, (size_t)nwrite) != 0) {
- return -1;
- }
+ ngtcp2_crypto_aead_ctx_free(&aead_ctx);
- return 0;
+ return spktlen;
}
/*
@@ -588,25 +718,23 @@ static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) {
*/
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);
+ return ngtcp2_crypto_derive_and_install_initial_key(
+ conn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dcid);
}
int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, void *user_data) {
const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(conn);
+ void *tls = ngtcp2_conn_get_tls_native_handle(conn);
(void)user_data;
if (crypto_setup_initial_crypto(conn, dcid) != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
+ if (crypto_set_local_transport_params(conn, tls) != 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;
@@ -639,3 +767,20 @@ int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn,
return 0;
}
+
+void ngtcp2_crypto_delete_crypto_aead_ctx_cb(ngtcp2_conn *conn,
+ ngtcp2_crypto_aead_ctx *aead_ctx,
+ void *user_data) {
+ (void)conn;
+ (void)user_data;
+
+ ngtcp2_crypto_aead_ctx_free(aead_ctx);
+}
+
+void ngtcp2_crypto_delete_crypto_cipher_ctx_cb(
+ ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data) {
+ (void)conn;
+ (void)user_data;
+
+ ngtcp2_crypto_cipher_ctx_free(cipher_ctx);
+}
diff --git a/deps/ngtcp2/crypto/shared.h b/deps/ngtcp2/crypto/shared.h
index a904f6994fb..b70513afb3a 100644
--- a/deps/ngtcp2/crypto/shared.h
+++ b/deps/ngtcp2/crypto/shared.h
@@ -110,7 +110,6 @@ int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf,
*/
int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls);
-
/**
* @function
*
@@ -165,4 +164,26 @@ int ngtcp2_crypto_derive_and_install_initial_key(
uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp,
const ngtcp2_cid *client_dcid);
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_cipher_ctx_encrypt_init` initializes |cipher_ctx|
+ * with new cipher context object for encryption which is constructed
+ * to use |key| as encryption key. |cipher| specifies cipher to use.
+ *
+ * This function returns 0 if it succeeds, or -1.
+ */
+int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
+ const ngtcp2_crypto_cipher *cipher,
+ const uint8_t *key);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_cipher_ctx_free` frees up resources used by
+ * |cipher_ctx|. This function does not free the memory pointed by
+ * |cipher_ctx| itself.
+ */
+void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx);
+
#endif /* NGTCP2_SHARED_H */
diff --git a/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h b/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
index 29cf3e54250..3373adb9f91 100644
--- a/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
+++ b/deps/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
@@ -49,6 +49,12 @@ extern "C" {
#include <stdarg.h>
#include <stddef.h>
+#ifdef WIN32
+# include <winsock2.h>
+#else
+# include <sys/socket.h>
+#endif
+
#include <ngtcp2/version.h>
#ifdef NGTCP2_STATICLIB
@@ -190,6 +196,15 @@ typedef struct ngtcp2_mem {
"\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97\x86\xf1\x9c\x61\x11\xe0\x43\x90" \
"\xa8\x99"
+/* NGTCP2_RETRY_KEY is an encryption key to create integrity tag of
+ Retry packet. */
+#define NGTCP2_RETRY_KEY \
+ "\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1"
+
+/* NGTCP2_RETRY_NONCE is nonce used when generating integrity tag of
+ Retry packet. */
+#define NGTCP2_RETRY_NONCE "\xe5\x49\x30\xf9\x7f\x21\x36\xf0\x53\x0a\x8c\x1c"
+
/* NGTCP2_HP_MASKLEN is the length of header protection mask. */
#define NGTCP2_HP_MASKLEN 5
@@ -212,6 +227,9 @@ typedef struct ngtcp2_mem {
nanosecond. */
#define NGTCP2_NANOSECONDS ((uint64_t)1ULL)
+/* NGTCP2_DEFAULT_INITIAL_RTT is a default initial RTT. */
+#define NGTCP2_DEFAULT_INITIAL_RTT (333 * NGTCP2_MILLISECONDS)
+
#if defined(__cplusplus) && __cplusplus >= 201103L
typedef enum ngtcp2_lib_error : int {
#else
@@ -248,7 +266,7 @@ typedef enum ngtcp2_lib_error {
NGTCP2_ERR_CONN_ID_BLOCKED = -237,
NGTCP2_ERR_INTERNAL = -238,
NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED = -239,
- NGTCP2_ERR_WRITE_STREAM_MORE = -240,
+ NGTCP2_ERR_WRITE_MORE = -240,
NGTCP2_ERR_RETRY = -241,
NGTCP2_ERR_DROP_CONN = -242,
NGTCP2_ERR_FATAL = -500,
@@ -488,9 +506,8 @@ typedef struct ngtcp2_transport_params {
ngtcp2_preferred_addr preferred_address;
/* 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
+ field. It is expected that application knows the original
+ Destination Connection ID even if it sends Retry packet, for
example, by including it in retry token. Otherwise, application
should not specify this field. */
ngtcp2_cid original_dcid;
@@ -573,6 +590,7 @@ typedef struct ngtcp2_conn_stat {
ngtcp2_duration min_rtt;
ngtcp2_duration smoothed_rtt;
ngtcp2_duration rttvar;
+ ngtcp2_duration initial_rtt;
size_t pto_count;
ngtcp2_tstamp loss_detection_timer;
/* last_tx_pkt_ts corresponds to
@@ -678,8 +696,30 @@ typedef struct ngtcp2_cc {
ngtcp2_conn_server_new. */
typedef void (*ngtcp2_printf)(void *user_data, const char *format, ...);
-typedef void (*ngtcp2_qlog_write)(void *user_data, const void *data,
- size_t datalen);
+/**
+ * @enum
+ *
+ * :type:`ngtcp2_qlog_write_flag` defines the set of flags passed to
+ * :type:`ngtcp2_qlog_write` callback.
+ */
+typedef enum ngtcp2_qlog_write_flag {
+ NGTCP2_QLOG_WRITE_FLAG_NONE = 0,
+ /**
+ * NGTCP2_QLOG_WRITE_FLAG_FIN indicates that this is the final call
+ * to :type:`ngtcp2_qlog_write` in the current connection.
+ */
+ NGTCP2_QLOG_WRITE_FLAG_FIN = 0x01
+} ngtcp2_qlog_write_flag;
+
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_qlog_write` is a callback function which is called to
+ * write qlog |data| of length |datalen| bytes. |flags| is bitwise OR
+ * of zero or more of :type:`ngtcp2_qlog_write_flag`.
+ */
+typedef void (*ngtcp2_qlog_write)(void *user_data, uint32_t flags,
+ const void *data, size_t datalen);
typedef struct ngtcp2_qlog_settings {
/* odcid is Original Destination Connection ID sent by client. It
@@ -699,6 +739,8 @@ typedef struct ngtcp2_settings {
ngtcp2_cc *cc;
/* initial_ts is an initial timestamp given to the library. */
ngtcp2_tstamp initial_ts;
+ /* initial_rtt is an initial RTT. */
+ ngtcp2_duration initial_rtt;
/* log_printf is a function that the library uses to write logs.
NULL means no logging output. */
ngtcp2_printf log_printf;
@@ -730,9 +772,9 @@ typedef struct ngtcp2_settings {
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. It must not be NULL. */
- uint8_t *addr;
+ /* addr points to the buffer which contains endpoint address. It
+ must not be NULL. */
+ struct sockaddr *addr;
/* user_data is an arbitrary data and opaque to the library. */
void *user_data;
} ngtcp2_addr;
@@ -757,8 +799,8 @@ typedef struct ngtcp2_path {
* the longest addresses.
*/
typedef struct ngtcp2_path_storage {
- uint8_t local_addrbuf[128];
- uint8_t remote_addrbuf[128];
+ struct sockaddr_storage local_addrbuf;
+ struct sockaddr_storage remote_addrbuf;
ngtcp2_path path;
} ngtcp2_path_storage;
@@ -800,6 +842,30 @@ typedef struct ngtcp2_crypto_cipher {
} ngtcp2_crypto_cipher;
/**
+ * @struct
+ *
+ * `ngtcp2_crypto_aead_ctx` is a wrapper around native AEAD cipher
+ * context object. It should be initialized with a specific key.
+ * ngtcp2 library reuses this context object to encrypt or decrypt
+ * multiple packets.
+ */
+typedef struct ngtcp2_crypto_aead_ctx {
+ void *native_handle;
+} ngtcp2_crypto_aead_ctx;
+
+/**
+ * @struct
+ *
+ * `ngtcp2_crypto_cipher_ctx` is a wrapper around native cipher
+ * context object. It should be initialized with a specific key.
+ * ngtcp2 library reuses this context object to encrypt or decrypt
+ * multiple packet headers.
+ */
+typedef struct ngtcp2_crypto_cipher_ctx {
+ void *native_handle;
+} ngtcp2_crypto_cipher_ctx;
+
+/**
* @function
*
* `ngtcp2_crypto_ctx` is a convenient structure to bind all crypto
@@ -1200,9 +1266,10 @@ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
* :type:`ngtcp2_encrypt` is invoked when the ngtcp2 library asks the
* application to encrypt packet payload. The packet payload to
* encrypt is passed as |plaintext| of length |plaintextlen|. The
- * encryption key is passed as |key|. The nonce is passed as |nonce|
- * of length |noncelen|. The ad, Additional Data to AEAD, is passed
- * as |ad| of length |adlen|.
+ * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context
+ * object which is initialized with encryption key. The nonce is
+ * passed as |nonce| of length |noncelen|. The ad, Additional Data to
+ * AEAD, is passed as |ad| of length |adlen|.
*
* The implementation of this callback must encrypt |plaintext| using
* the negotiated cipher suite and write the ciphertext into the
@@ -1216,9 +1283,10 @@ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
* return immediately.
*/
typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *plaintext, size_t plaintextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen);
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen);
/**
* @functypedef
@@ -1226,7 +1294,8 @@ typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead,
* :type:`ngtcp2_decrypt` is invoked when the ngtcp2 library asks the
* application to decrypt packet payload. The packet payload to
* decrypt is passed as |ciphertext| of length |ciphertextlen|. The
- * decryption key is passed as |key| of length |keylen|. The nonce is
+ * AEAD cipher is |aead|. |aead_ctx| is the AEAD cipher context
+ * object which is initialized with decryption key. The nonce is
* passed as |nonce| of length |noncelen|. The ad, Additional Data to
* AEAD, is passed as |ad| of length |adlen|.
*
@@ -1243,16 +1312,19 @@ typedef int (*ngtcp2_encrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead,
* makes the library call return immediately.
*/
typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *ciphertext, size_t ciphertextlen,
- const uint8_t *key, const uint8_t *nonce,
- size_t noncelen, const uint8_t *ad, size_t adlen);
+ const uint8_t *nonce, size_t noncelen,
+ const uint8_t *ad, size_t adlen);
/**
* @functypedef
*
* :type:`ngtcp2_hp_mask` is invoked when the ngtcp2 library asks the
* application to produce mask to encrypt or decrypt packet header.
- * The key is passed as |hp_key|. The sample is passed as |sample|.
+ * The encryption cipher is |hp|. |hp_ctx| is the cipher context
+ * object which is initialized with header protection key. The sample
+ * is passed as |sample|.
*
* The implementation of this callback must produce a mask using the
* header protection cipher suite specified by QUIC specification and
@@ -1265,7 +1337,8 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead,
* return immediately.
*/
typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
- const uint8_t *hp_key, const uint8_t *sample);
+ const ngtcp2_crypto_cipher_ctx *hp_ctx,
+ const uint8_t *sample);
/**
* @enum
@@ -1457,8 +1530,7 @@ typedef int (*ngtcp2_extend_max_stream_data)(ngtcp2_conn *conn,
* :enum:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
* immediately.
*/
-typedef int (*ngtcp2_rand)(ngtcp2_conn *conn, uint8_t *dest, size_t destlen,
- ngtcp2_rand_ctx ctx, void *user_data);
+typedef int (*ngtcp2_rand)(uint8_t *dest, size_t destlen, ngtcp2_rand_ctx ctx);
/**
* @functypedef
@@ -1500,28 +1572,31 @@ typedef int (*ngtcp2_remove_connection_id)(ngtcp2_conn *conn,
*
* :type:`ngtcp2_update_key` is a callback function which tells the
* application that it must generate new packet protection keying
- * materials. The current set of secrets are given as
- * |current_rx_secret| and |current_tx_secret| of length |secretlen|.
- * They are decryption and encryption secrets respectively.
+ * materials and AEAD cipher context objects with new keys. The
+ * current set of secrets are given as |current_rx_secret| and
+ * |current_tx_secret| of length |secretlen|. They are decryption and
+ * encryption secrets respectively.
*
* The application has to generate new secrets and keys for both
- * encryption and decryption, and write decryption secret, key and IV
- * to the buffer pointed by |rx_secret|, |rx_key| and |rx_iv|
- * respectively. Similarly, write encryption secret, key and IV to
- * the buffer pointed by |tx_secret|, |tx_key| and |tx_iv|. All given
+ * encryption and decryption, and write decryption secret and IV to
+ * the buffer pointed by |rx_secret| and |rx_iv| respectively. It
+ * also has to create new AEAD cipher context object with new
+ * decryption key and initialize |rx_aead_ctx| with it. Similarly,
+ * write encryption secret and IV to the buffer pointed by |tx_secret|
+ * and |tx_iv|. Create new AEAD cipher context object with new
+ * encryption key and initialize |tx_aead_ctx| with it. All given
* buffers have the enough capacity to store secret, key and IV.
*
* The callback function must return 0 if it succeeds. Returning
* :enum:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
* immediately.
*/
-typedef int (*ngtcp2_update_key)(ngtcp2_conn *conn, uint8_t *rx_secret,
- uint8_t *tx_secret, uint8_t *rx_key,
- uint8_t *rx_iv, uint8_t *tx_key,
- uint8_t *tx_iv,
- const uint8_t *current_rx_secret,
- const uint8_t *current_tx_secret,
- size_t secretlen, void *user_data);
+typedef int (*ngtcp2_update_key)(
+ ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
+ ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
+ ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
+ const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
+ size_t secretlen, void *user_data);
/**
* @functypedef
@@ -1608,6 +1683,26 @@ typedef int (*ngtcp2_connection_id_status)(ngtcp2_conn *conn, int type,
typedef int (*ngtcp2_recv_new_token)(ngtcp2_conn *conn, const ngtcp2_vec *token,
void *user_data);
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_delete_crypto_aead_ctx` is a callback function which
+ * must delete the native object pointed by |aead_ctx|->native_handle.
+ */
+typedef void (*ngtcp2_delete_crypto_aead_ctx)(ngtcp2_conn *conn,
+ ngtcp2_crypto_aead_ctx *aead_ctx,
+ void *user_data);
+
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_delete_crypto_cipher_ctx` is a callback function
+ * which must delete the native object pointed by
+ * |cipher_ctx|->native_handle.
+ */
+typedef void (*ngtcp2_delete_crypto_cipher_ctx)(
+ ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data);
+
typedef struct ngtcp2_conn_callbacks {
/**
* client_initial is a callback function which is invoked when
@@ -1794,6 +1889,16 @@ typedef struct ngtcp2_conn_callbacks {
* token is received from server. This field is ignored by server.
*/
ngtcp2_recv_new_token recv_new_token;
+ /**
+ * delete_crypto_aead_ctx is a callback function which deletes a
+ * given AEAD cipher context object.
+ */
+ ngtcp2_delete_crypto_aead_ctx delete_crypto_aead_ctx;
+ /**
+ * delete_crypto_cipher_ctx is a callback function which deletes a
+ * given cipher context object.
+ */
+ ngtcp2_delete_crypto_cipher_ctx delete_crypto_cipher_ctx;
} ngtcp2_conn_callbacks;
/**
@@ -1820,9 +1925,9 @@ typedef struct ngtcp2_conn_callbacks {
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close(
uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid,
const ngtcp2_cid *scid, uint64_t error_code, ngtcp2_encrypt encrypt,
- const ngtcp2_crypto_aead *aead, const uint8_t *key, const uint8_t *iv,
- ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp,
- const uint8_t *hp_key);
+ const ngtcp2_crypto_aead *aead, const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx);
/**
* @function
@@ -1831,6 +1936,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close(
* by |dest| whose length is |destlen|. |odcid| specifies Original
* Destination Connection ID. |token| specifies Retry Token, and
* |tokenlen| specifies its length. |aead| must be AEAD_AES_128_GCM.
+ * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as an
+ * encryption key.
*
* This function returns the number of bytes written to the buffer, or
* one of the following negative error codes:
@@ -1843,7 +1950,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close(
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_retry(
uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid,
const ngtcp2_cid *scid, const ngtcp2_cid *odcid, const uint8_t *token,
- size_t tokenlen, ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead);
+ size_t tokenlen, ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx);
/**
* @function
@@ -1983,12 +2091,21 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn);
* @function
*
* `ngtcp2_conn_install_initial_key` installs packet protection keying
- * materials for Initial 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 Initial packets.
- * Similarly, |tx_key|, |tx_iv| and |tx_hp_key| are for encrypt
- * outgoing packets and are the same length with the rx counterpart .
- * If they have already been set, they are overwritten.
+ * materials for Initial packets. |rx_aead_ctx| is AEAD cipher
+ * context object and must be initialized with decryption key, IV
+ * |rx_iv| of length |rx_ivlen|, and packet header protection cipher
+ * context object |rx_hp_ctx| to decrypt incoming Initial packets.
+ * Similarly, |tx_aead_ctx|, |tx_iv| and |tx_hp_ctx| are for
+ * encrypting outgoing packets and are the same length with the
+ * decryption counterpart . If they have already been set, they are
+ * overwritten.
+ *
+ * If this function succeeds, |conn| takes ownership of |rx_aead_ctx|,
+ * |rx_hp_ctx|, |tx_aead_ctx|, and |tx_hp_ctx|.
+ * :type:`ngtcp2_delete_crypto_aead_ctx` and
+ * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete
+ * these objects when they are no longer used. If this function
+ * fails, the caller is responsible to delete them.
*
* After receiving Retry packet, the DCID most likely changes. In
* that case, client application must generate these keying materials
@@ -2001,49 +2118,62 @@ NGTCP2_EXTERN int ngtcp2_conn_get_handshake_completed(ngtcp2_conn *conn);
* Out of memory.
*/
NGTCP2_EXTERN int ngtcp2_conn_install_initial_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_conn *conn, const ngtcp2_crypto_aead_ctx *rx_aead_ctx,
+ const uint8_t *rx_iv, const ngtcp2_crypto_cipher_ctx *rx_hp_ctx,
+ const ngtcp2_crypto_aead_ctx *tx_aead_ctx, const uint8_t *tx_iv,
+ const ngtcp2_crypto_cipher_ctx *tx_hp_ctx, size_t ivlen);
/**
* @function
*
* `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
+ * keying materials for decrypting incoming Handshake packets.
+ * |aead_ctx| is AEAD cipher context object which must be initialized
+ * with decryption key, IV |iv| of length |ivlen|, and packet header
+ * protection cipher context object |hp_ctx| to decrypt incoming
* Handshake packets.
*
+ * If this function succeeds, |conn| takes ownership of |aead_ctx|,
+ * and |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and
+ * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete
+ * these objects when they are no longer used. If this function
+ * fails, the caller is responsible to delete them.
+ *
* 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_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_EXTERN int ngtcp2_conn_install_rx_handshake_key(
+ ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx);
/**
* @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
+ * keying materials for encrypting outgoing Handshake packets.
+ * |aead_ctx| is AEAD cipher context object which must be initialized
+ * with encryption key, IV |iv| of length |ivlen|, and packet header
+ * protection cipher context object |hp_ctx| to encrypt outgoing
* Handshake packets.
*
+ * If this function succeeds, |conn| takes ownership of |aead_ctx| and
+ * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and
+ * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete
+ * these objects when they are no longer used. If this function
+ * fails, the caller is responsible to delete them.
+ *
* 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);
+NGTCP2_EXTERN int ngtcp2_conn_install_tx_handshake_key(
+ ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx);
/**
* @function
@@ -2068,10 +2198,16 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_aead_overhead(ngtcp2_conn *conn);
/**
* @function
*
- * `ngtcp2_conn_install_early_key` installs packet protection key
- * |key| of length |keylen|, IV |iv| of length |ivlen|, and packet
- * header protection key |hp_key| of length |keylen| to encrypt (for
- * client)or decrypt (for server) 0RTT packets.
+ * `ngtcp2_conn_install_early_key` installs packet protection AEAD
+ * cipher context object |aead_ctx|, IV |iv| of length |ivlen|, and
+ * packet header protection cipher context object |hp_ctx| to encrypt
+ * (for client) or decrypt (for server) 0RTT packets.
+ *
+ * If this function succeeds, |conn| takes ownership of |aead_ctx| and
+ * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and
+ * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete
+ * these objects when they are no longer used. If this function
+ * fails, the caller is responsible to delete them.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -2079,11 +2215,9 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_aead_overhead(ngtcp2_conn *conn);
* :enum:`NGTCP2_ERR_NOMEM`
* Out of memory.
*/
-NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn,
- const uint8_t *key,
- const uint8_t *iv,
- const uint8_t *hp_key,
- size_t keylen, size_t ivlen);
+NGTCP2_EXTERN int ngtcp2_conn_install_early_key(
+ ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx);
/**
* @function
@@ -2091,9 +2225,16 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn,
* `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.
+ * materials passed to this function. |aead_ctx| is AEAD cipher
+ * context object which must be initialized with decryption key, IV
+ * |iv| of length |ivlen|, and packet header protection cipher context
+ * object |hp_ctx| to decrypt incoming Short packets.
+ *
+ * If this function succeeds, |conn| takes ownership of |aead_ctx| and
+ * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and
+ * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete
+ * these objects when they are no longer used. If this function
+ * fails, the caller is responsible to delete them.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -2101,11 +2242,10 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key(ngtcp2_conn *conn,
* :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);
+NGTCP2_EXTERN int ngtcp2_conn_install_rx_key(
+ ngtcp2_conn *conn, const uint8_t *secret, size_t secretlen,
+ const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx);
/**
* @function
@@ -2113,9 +2253,16 @@ ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret,
* `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.
+ * materials passed to this function. |aead_ctx| is AEAD cipher
+ * context object which must be initialized with encryption key, IV
+ * |iv| of length |ivlen|, and packet header protection cipher context
+ * object |hp_ctx| to encrypt outgoing Short packets.
+ *
+ * If this function succeeds, |conn| takes ownership of |aead_ctx| and
+ * |hp_ctx|. :type:`ngtcp2_delete_crypto_aead_ctx` and
+ * :type:`ngtcp2_delete_crypto_cipher_ctx` will be called to delete
+ * these objects when they are no longer used. If this function
+ * fails, the caller is responsible to delete them.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -2123,11 +2270,10 @@ ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret,
* :enum:`NGTCP2_ERR_NOMEM`
* Out of memory.
*/
-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);
+NGTCP2_EXTERN int ngtcp2_conn_install_tx_key(
+ ngtcp2_conn *conn, const uint8_t *secret, size_t secretlen,
+ const ngtcp2_crypto_aead_ctx *aead_ctx, const uint8_t *iv, size_t ivlen,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx);
/**
* @function
@@ -2288,6 +2434,27 @@ NGTCP2_EXTERN void ngtcp2_conn_set_early_remote_transport_params(
/**
* @function
*
+ * `ngtcp2_conn_set_local_transport_params` sets the local transport
+ * parameters |params|. This function can only be called by server.
+ * Although the local transport parameters are passed to
+ * `ngtcp2_conn_server_new`, server might want to update them after
+ * ALPN is chosen. In that case, server can update the transport
+ * parameter with this function. Server must call this function
+ * before calling `ngtcp2_conn_install_tx_handshake_key`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGTCP2_ERR_INVALID_STATE`
+ * `ngtcp2_conn_install_tx_handshake_key` has been called.
+ */
+NGTCP2_EXTERN int
+ngtcp2_conn_set_local_transport_params(ngtcp2_conn *conn,
+ const ngtcp2_transport_params *params);
+
+/**
+ * @function
+ *
* `ngtcp2_conn_get_local_transport_params` fills settings values in
* |params|.
*/
@@ -2483,8 +2650,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream(
* packet is nearly full and the library decided to make a complete
* packet. In this case, |*pdatalen| == -1 is asserted.
*
- * - The function returns :enum:`NGTCP2_ERR_WRITE_STREAM_MORE`. In
- * this case, |*pdatalen| >= 0 is asserted. This indicates that
+ * - The function returns :enum:`NGTCP2_ERR_WRITE_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|
@@ -2497,14 +2664,14 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream(
* - The other error might be returned just like without
* :enum:`NGTCP2_WRITE_STREAM_FLAG_MORE`.
*
- * When application sees :enum:`NGTCP2_ERR_WRITE_STREAM_MORE`, it must
- * not call other ngtcp2 API functions (application can still call
+ * When application sees :enum:`NGTCP2_ERR_WRITE_MORE`, it must not
+ * call other ngtcp2 API functions (application can still call
* `ngtcp2_conn_write_connection_close` or
* `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). If |*pdatalen| >= 0, the
- * function always return :enum:`NGTCP2_ERR_WRITE_STREAM_MORE`.
+ * function always return :enum:`NGTCP2_ERR_WRITE_MORE`.
*
* This function returns 0 if it cannot write any frame because buffer
* is too small, or packet is congestion limited. Application should
@@ -2528,7 +2695,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream(
* User callback failed
* :enum:`NGTCP2_ERR_STREAM_DATA_BLOCKED`
* Stream is blocked because of flow control.
- * :enum:`NGTCP2_ERR_WRITE_STREAM_MORE`
+ * :enum:`NGTCP2_ERR_WRITE_MORE`
* (Only when :enum:`NGTCP2_WRITE_STREAM_FLAG_MORE` is specified)
* Application can call this function to pack more stream data
* into the same packet. See above to know how it works.
@@ -2549,8 +2716,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream(
* @function
*
* `ngtcp2_conn_write_connection_close` writes a packet which contains
- * a CONNECTION_CLOSE frame in the buffer pointed by |dest| whose
- * capacity is |datalen|.
+ * a CONNECTION_CLOSE frame (type 0x1c) in the buffer pointed by
+ * |dest| whose capacity is |datalen|.
*
* If |path| is not NULL, this function stores the network path with
* which the packet should be sent. Each addr field must point to the
@@ -2584,8 +2751,8 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_connection_close(
* @function
*
* `ngtcp2_conn_write_application_close` writes a packet which
- * contains a APPLICATION_CLOSE frame in the buffer pointed by |dest|
- * whose capacity is |datalen|.
+ * contains a CONNECTION_CLOSE frame (type 0x1d) in the buffer pointed
+ * by |dest| whose capacity is |datalen|.
*
* If |path| is not NULL, this function stores the network path with
* which the packet should be sent. Each addr field must point to the
@@ -2593,6 +2760,10 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_connection_close(
* sockaddr_storage)`` is enough. The assignment might not be done if
* nothing is written to |dest|.
*
+ * If handshake has not been confirmed yet, CONNECTION_CLOSE (type
+ * 0x1c) with error code :macro:`NGTCP2_APPLICATION_ERROR` is written
+ * instead.
+ *
* This function must not be called from inside the callback
* functions.
*
@@ -2605,7 +2776,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_connection_close(
* :enum:`NGTCP2_ERR_NOBUF`
* Buffer is too small
* :enum:`NGTCP2_ERR_INVALID_STATE`
- * The current state does not allow sending APPLICATION_CLOSE.
+ * The current state does not allow sending CONNECTION_CLOSE.
* :enum:`NGTCP2_ERR_PKT_NUM_EXHAUSTED`
* Packet number is exhausted, and cannot send any more packet.
* :enum:`NGTCP2_ERR_CALLBACK_FAILURE`
@@ -2974,13 +3145,21 @@ NGTCP2_EXTERN void ngtcp2_conn_set_tls_native_handle(ngtcp2_conn *conn,
/**
* @function
*
- * `ngtcp2_conn_set_retry_aead` sets |aead| for Retry integrity tag
- * verification. It must be AEAD_AES_128_GCM. This function must be
- * called if |conn| is initialized as client. Server does not verify
- * the tag and has no need to call this function.
+ * `ngtcp2_conn_set_retry_aead` sets |aead| and |aead_ctx| for Retry
+ * integrity tag verification. |aead| must be AEAD_AES_128_GCM.
+ * |aead_ctx| must be initialized with :macro:`NGTCP2_RETRY_KEY` as
+ * encryption key. This function must be called if |conn| is
+ * initialized as client. Server does not verify the tag and has no
+ * need to call this function.
+ *
+ * If this function succeeds, |conn| takes ownership of |aead_ctx|.
+ * :type:`ngtcp2_delete_crypto_aead_ctx` will be called to delete this
+ * object when it is no longer used. If this function fails, the
+ * caller is responsible to delete it.
*/
-NGTCP2_EXTERN void ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn,
- const ngtcp2_crypto_aead *aead);
+NGTCP2_EXTERN void
+ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx);
/**
* @function
@@ -3036,6 +3215,30 @@ NGTCP2_EXTERN int ngtcp2_conn_is_server(ngtcp2_conn *conn);
/**
* @function
*
+ * `ngtcp2_conn_after_retry` returns nonzero if |conn| as a client has
+ * received Retry packet from server and successfully validated it.
+ */
+NGTCP2_EXTERN int ngtcp2_conn_after_retry(ngtcp2_conn *conn);
+
+/**
+ * @function
+ *
+ * `ngtcp2_conn_set_stream_user_data` sets |stream_user_data| to the
+ * stream identified by |stream_id|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGTCP2_ERR_STREAM_NOT_FOUND`
+ * Stream does not exist
+ */
+NGTCP2_EXTERN int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn,
+ int64_t stream_id,
+ void *stream_user_data);
+
+/**
+ * @function
+ *
* `ngtcp2_strerror` returns the text representation of |liberr|.
*/
NGTCP2_EXTERN const char *ngtcp2_strerror(int liberr);
@@ -3061,7 +3264,8 @@ NGTCP2_EXTERN uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr);
* `ngtcp2_addr_init` initializes |dest| with the given arguments and
* returns |dest|.
*/
-NGTCP2_EXTERN ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const void *addr,
+NGTCP2_EXTERN ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest,
+ const struct sockaddr *addr,
size_t addrlen, void *user_data);
/**
@@ -3070,11 +3274,13 @@ NGTCP2_EXTERN ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const void *addr,
* `ngtcp2_path_storage_init` initializes |ps| with the given
* arguments. This function copies |local_addr| and |remote_addr|.
*/
-NGTCP2_EXTERN void
-ngtcp2_path_storage_init(ngtcp2_path_storage *ps, const void *local_addr,
- size_t local_addrlen, void *local_user_data,
- const void *remote_addr, size_t remote_addrlen,
- void *remote_user_data);
+NGTCP2_EXTERN void ngtcp2_path_storage_init(ngtcp2_path_storage *ps,
+ const struct sockaddr *local_addr,
+ size_t local_addrlen,
+ void *local_user_data,
+ const struct sockaddr *remote_addr,
+ size_t remote_addrlen,
+ void *remote_user_data);
/**
* @function
@@ -3092,6 +3298,7 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps);
* default value to the following fields:
*
* * cc_algo = NGTCP2_CC_ALGO_CUBIC
+ * * initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT
* * 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
diff --git a/deps/ngtcp2/lib/ngtcp2_acktr.c b/deps/ngtcp2/lib/ngtcp2_acktr.c
index 85113716b1c..7a7f3e469a2 100644
--- a/deps/ngtcp2/lib/ngtcp2_acktr.c
+++ b/deps/ngtcp2/lib/ngtcp2_acktr.c
@@ -297,8 +297,6 @@ void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr) {
return;
}
}
-
- return;
}
void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) {
diff --git a/deps/ngtcp2/lib/ngtcp2_addr.c b/deps/ngtcp2/lib/ngtcp2_addr.c
index 13a787bdea0..cfc91c41e2c 100644
--- a/deps/ngtcp2/lib/ngtcp2_addr.c
+++ b/deps/ngtcp2/lib/ngtcp2_addr.c
@@ -25,11 +25,24 @@
#include "ngtcp2_addr.h"
#include <string.h>
+#include <assert.h>
-ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const void *addr,
+#ifdef WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netinet/ip.h>
+# include <netinet/tcp.h>
+# include <arpa/inet.h>
+#endif
+
+ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const struct sockaddr *addr,
size_t addrlen, void *user_data) {
dest->addrlen = addrlen;
- dest->addr = (uint8_t *)addr;
+ dest->addr = (struct sockaddr *)addr;
dest->user_data = user_data;
return dest;
}
@@ -42,7 +55,7 @@ void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src) {
dest->user_data = src->user_data;
}
-void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const void *addr,
+void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const struct sockaddr *addr,
size_t addrlen) {
dest->addrlen = addrlen;
if (addrlen) {
@@ -50,8 +63,30 @@ void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const void *addr,
}
}
+static int sockaddr_eq(const struct sockaddr *a, const struct sockaddr *b) {
+ assert(a->sa_family == b->sa_family);
+
+ switch (a->sa_family) {
+ case AF_INET: {
+ const struct sockaddr_in *ai = (const struct sockaddr_in *)(void *)a,
+ *bi = (const struct sockaddr_in *)(void *)b;
+ return ai->sin_port == bi->sin_port &&
+ memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr)) == 0;
+ }
+ case AF_INET6: {
+ const struct sockaddr_in6 *ai = (const struct sockaddr_in6 *)(void *)a,
+ *bi = (const struct sockaddr_in6 *)(void *)b;
+ return ai->sin6_port == bi->sin6_port &&
+ memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0;
+ }
+ default:
+ assert(0);
+ }
+}
+
int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b) {
- return a->addrlen == b->addrlen && memcmp(a->addr, b->addr, a->addrlen) == 0;
+ return a->addr->sa_family == b->addr->sa_family &&
+ sockaddr_eq(a->addr, b->addr);
}
int ngtcp2_addr_empty(const ngtcp2_addr *addr) { return addr->addrlen == 0; }
diff --git a/deps/ngtcp2/lib/ngtcp2_addr.h b/deps/ngtcp2/lib/ngtcp2_addr.h
index db8b7144082..238bb435183 100644
--- a/deps/ngtcp2/lib/ngtcp2_addr.h
+++ b/deps/ngtcp2/lib/ngtcp2_addr.h
@@ -44,7 +44,8 @@ void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src);
* |addrlen|. This function assumes that dest->addr points to a
* buffer which have sufficient size to store the copy.
*/
-void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const void *addr, size_t addrlen);
+void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const struct sockaddr *addr,
+ size_t addrlen);
/*
* ngtcp2_addr_eq returns nonzero if |a| equals |b|.
diff --git a/deps/ngtcp2/lib/ngtcp2_cc.c b/deps/ngtcp2/lib/ngtcp2_cc.c
index 3aed4dd759d..ef2e63a0efd 100644
--- a/deps/ngtcp2/lib/ngtcp2_cc.c
+++ b/deps/ngtcp2/lib/ngtcp2_cc.c
@@ -26,24 +26,15 @@
#include <assert.h>
+#if defined(_MSC_VER)
+# include <intrin.h>
+#endif
+
#include "ngtcp2_log.h"
#include "ngtcp2_macro.h"
#include "ngtcp2_mem.h"
#include "ngtcp2_rcvry.h"
-#ifdef _MSC_VER
-#include <intrin.h>
-static inline int __builtin_clzll(unsigned long long x) {
-#if defined(_WIN64) || defined(_LP64)
- return (int)__lzcnt64(x);
-#else
- // TODO(@jasnell): Determine if there's an alternative available for x86
- assert(0);
-#endif
-
-}
-#endif
-
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);
@@ -245,16 +236,35 @@ void ngtcp2_cc_cubic_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) {
static uint64_t ngtcp2_cbrt(uint64_t n) {
int d;
uint64_t a;
- int i;
if (n == 0) {
return 0;
}
+#if defined(_MSC_VER)
+# if defined(_M_X64)
+ d = (int)__lzcnt64(n);
+# elif defined(_M_ARM64)
+ {
+ unsigned long index;
+ d = sizeof(uint64_t) * CHAR_BIT;
+ if (_BitScanReverse64(&index, n)) {
+ d = d - 1 - index;
+ }
+ }
+# else
+ if ((n >> 32) != 0) {
+ d = __lzcnt((unsigned int)(n >> 32));
+ } else {
+ d = 32 + __lzcnt((unsigned int)n);
+ }
+# endif
+#else
d = __builtin_clzll(n);
+#endif
a = 1ULL << ((64 - d) / 3 + 1);
- for (i = 0; a * a * a > n; ++i) {
+ for (; a * a * a > n;) {
a = (2 * a + n / a / a) / 3;
}
return a;
@@ -274,6 +284,7 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
uint64_t target;
uint64_t tx, kx, time_delta, delta;
uint64_t add, tcp_add;
+ uint64_t m;
if (pkt->pktns_id == NGTCP2_PKTNS_ID_APP && cc->window_end != -1 &&
cc->window_end <= pkt->pkt_num) {
@@ -339,10 +350,12 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
"cubic-ca epoch_start=%" PRIu64 " k=%" PRIu64
" origin_point=%" PRIu64,
cc->epoch_start, cc->k, cc->origin_point);
+
+ cc->pending_add = 0;
+ cc->pending_w_add = 0;
}
- min_rtt = cstat->min_rtt == UINT64_MAX ? NGTCP2_DEFAULT_INITIAL_RTT
- : cstat->min_rtt;
+ min_rtt = cstat->min_rtt == UINT64_MAX ? cstat->initial_rtt : cstat->min_rtt;
t = ts + min_rtt - cc->epoch_start;
@@ -365,13 +378,19 @@ void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
}
if (target > cstat->cwnd) {
- add = cstat->max_udp_payload_size * (target - cstat->cwnd) / cstat->cwnd;
+ m = cc->pending_add + cstat->max_udp_payload_size * (target - cstat->cwnd);
+ add = m / cstat->cwnd;
+ cc->pending_add = m % cstat->cwnd;
} else {
- /* TODO too small, no increment at all */
- add = cstat->max_udp_payload_size / (100 * cstat->cwnd);
+ m = cc->pending_add + cstat->max_udp_payload_size;
+ add = m / (100 * cstat->cwnd);
+ cc->pending_add = m % (100 * cstat->cwnd);
}
- cc->w_tcp += cstat->max_udp_payload_size * pkt->pktlen * 9 / 17 / cstat->cwnd;
+ m = cc->pending_w_add + cstat->max_udp_payload_size * pkt->pktlen;
+
+ cc->w_tcp += m / cstat->cwnd;
+ cc->pending_w_add = m % cstat->cwnd;
if (cc->w_tcp > cstat->cwnd) {
tcp_add =
diff --git a/deps/ngtcp2/lib/ngtcp2_cc.h b/deps/ngtcp2/lib/ngtcp2_cc.h
index c3886a6e6b4..05010d57251 100644
--- a/deps/ngtcp2/lib/ngtcp2_cc.h
+++ b/deps/ngtcp2/lib/ngtcp2_cc.h
@@ -95,6 +95,8 @@ typedef struct ngtcp2_cubic_cc {
uint64_t current_round_min_rtt;
uint64_t last_round_min_rtt;
int64_t window_end;
+ uint64_t pending_add;
+ uint64_t pending_w_add;
} ngtcp2_cubic_cc;
int ngtcp2_cc_cubic_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
diff --git a/deps/ngtcp2/lib/ngtcp2_cid.c b/deps/ngtcp2/lib/ngtcp2_cid.c
index b0670a9c6f0..126e3c4a512 100644
--- a/deps/ngtcp2/lib/ngtcp2_cid.c
+++ b/deps/ngtcp2/lib/ngtcp2_cid.c
@@ -105,7 +105,6 @@ void ngtcp2_dcid_copy_no_path(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
int ngtcp2_dcid_verify_uniqueness(ngtcp2_dcid *dcid, uint64_t seq,
const ngtcp2_cid *cid, const uint8_t *token) {
-
if (dcid->seq == seq) {
return ngtcp2_cid_eq(&dcid->cid, cid) &&
memcmp(dcid->token, token,
diff --git a/deps/ngtcp2/lib/ngtcp2_conn.c b/deps/ngtcp2/lib/ngtcp2_conn.c
index 41e5f4d915e..ff8c608b776 100644
--- a/deps/ngtcp2/lib/ngtcp2_conn.c
+++ b/deps/ngtcp2/lib/ngtcp2_conn.c
@@ -359,6 +359,29 @@ static int conn_call_deactivate_dcid(ngtcp2_conn *conn,
conn, NGTCP2_CONNECTION_ID_STATUS_TYPE_DEACTIVATE, dcid);
}
+static void conn_call_delete_crypto_aead_ctx(ngtcp2_conn *conn,
+ ngtcp2_crypto_aead_ctx *aead_ctx) {
+ if (!aead_ctx->native_handle) {
+ return;
+ }
+
+ assert(conn->callbacks.delete_crypto_aead_ctx);
+
+ conn->callbacks.delete_crypto_aead_ctx(conn, aead_ctx, conn->user_data);
+}
+
+static void
+conn_call_delete_crypto_cipher_ctx(ngtcp2_conn *conn,
+ ngtcp2_crypto_cipher_ctx *cipher_ctx) {
+ if (!cipher_ctx->native_handle) {
+ return;
+ }
+
+ assert(conn->callbacks.delete_crypto_cipher_ctx);
+
+ conn->callbacks.delete_crypto_cipher_ctx(conn, cipher_ctx, conn->user_data);
+}
+
static int crypto_offset_less(const ngtcp2_ksl_key *lhs,
const ngtcp2_ksl_key *rhs) {
return *(int64_t *)lhs < *(int64_t *)rhs;
@@ -458,9 +481,6 @@ static void pktns_free(ngtcp2_pktns *pktns, const ngtcp2_mem *mem) {
ngtcp2_frame_chain_list_del(pktns->tx.frq, mem);
- ngtcp2_vec_del(pktns->crypto.rx.hp_key, mem);
- ngtcp2_vec_del(pktns->crypto.tx.hp_key, mem);
-
ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, mem);
ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, mem);
@@ -513,25 +533,46 @@ static int ts_retired_less(const ngtcp2_pq_entry *lhs,
return a->ts_retired < b->ts_retired;
}
-static void conn_reset_conn_stat(ngtcp2_conn *conn, ngtcp2_conn_stat *cstat) {
+/*
+ * conn_reset_conn_stat_cc resets congestion state in |cstat|.
+ */
+static void conn_reset_conn_stat_cc(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->smoothed_rtt = conn->local.settings.initial_rtt;
+ cstat->rttvar = conn->local.settings.initial_rtt / 2;
cstat->pto_count = 0;
cstat->loss_detection_timer = 0;
- // Initializes them with UINT64_MAX.
- 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;
}
+/*
+ * reset_conn_stat_recovery resets the fields related to the recovery
+ * function
+ */
+static void reset_conn_stat_recovery(ngtcp2_conn_stat *cstat) {
+ // Initializes them with UINT64_MAX.
+ memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time));
+ memset(cstat->last_tx_pkt_ts, 0xff, sizeof(cstat->last_tx_pkt_ts));
+}
+
+/*
+ * conn_reset_conn_stat resets |cstat|. The following fields are not
+ * reset: initial_rtt, max_udp_payload_size, bytes_sent, and
+ * bytes_recv.
+ */
+static void conn_reset_conn_stat(ngtcp2_conn *conn, ngtcp2_conn_stat *cstat) {
+ conn_reset_conn_stat_cc(conn, cstat);
+ reset_conn_stat_recovery(cstat);
+}
+
static void conn_reset_rx_rate(ngtcp2_conn *conn) {
conn->rx.rate.start_ts = UINT64_MAX;
conn->rx.rate.received = 0;
@@ -551,9 +592,15 @@ static void conn_update_recv_rate(ngtcp2_conn *conn, size_t datalen,
assert(conn->cstat.min_rtt);
- window = conn->cstat.min_rtt == UINT64_MAX ? NGTCP2_DEFAULT_INITIAL_RTT
+ window = conn->cstat.min_rtt == UINT64_MAX ? conn->cstat.initial_rtt
: conn->cstat.min_rtt * 2;
+ /* If settings.initial_rtt is zero for whatever reason then window
+ can be zero and we can end up with a division by zero error when
+ bps is set below. If this assert fails, check that
+ settings.initial_rtt is not zero. */
+ assert(window);
+
if (window > ts - conn->rx.rate.start_ts) {
return;
}
@@ -621,6 +668,11 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
goto fail_dcid_retired_init;
}
+ rv = ngtcp2_gaptr_init(&(*pconn)->dcid.seqgap, mem);
+ if (rv != 0) {
+ goto fail_seqgap_init;
+ }
+
rv = ngtcp2_ksl_init(&(*pconn)->scid.set, cid_less, sizeof(ngtcp2_cid), mem);
if (rv != 0) {
goto fail_scid_set_init;
@@ -677,22 +729,14 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
(*pconn)->local.settings.token.len = 0;
}
- if (params->active_connection_id_limit == 0) {
- (*pconn)->local.settings.transport_params.active_connection_id_limit =
- 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);
+ (*pconn)->cstat.initial_rtt = settings->initial_rtt;
+ (*pconn)->cstat.max_udp_payload_size =
+ (*pconn)->local.settings.max_udp_payload_size;
ngtcp2_rst_init(&(*pconn)->rst);
@@ -746,10 +790,9 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
goto fail_scident;
}
- ngtcp2_scid_init(scident, 0, scid,
- params->stateless_reset_token_present
- ? params->stateless_reset_token
- : NULL);
+ /* Set stateless reset token later if it is available in the local
+ transport parameters */
+ ngtcp2_scid_init(scident, 0, scid, NULL);
rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident);
if (rv != 0) {
@@ -758,52 +801,29 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
scident = NULL;
- if (server && params->preferred_address_present) {
- scident = ngtcp2_mem_malloc(mem, sizeof(*scident));
- if (scident == NULL) {
- rv = NGTCP2_ERR_NOMEM;
- goto fail_scident;
- }
-
- ngtcp2_scid_init(scident, 1, &params->preferred_address.cid,
- params->preferred_address.stateless_reset_token);
-
- rv = ngtcp2_ksl_insert(&(*pconn)->scid.set, NULL, &scident->cid, scident);
- if (rv != 0) {
- goto fail_scid_set_insert;
- }
-
- scident = NULL;
-
- (*pconn)->scid.last_seq = 1;
- }
-
ngtcp2_dcid_init(&(*pconn)->dcid.current, 0, dcid, NULL);
ngtcp2_path_copy(&(*pconn)->dcid.current.ps.path, path);
+ rv = ngtcp2_gaptr_push(&(*pconn)->dcid.seqgap, 0, 1);
+ if (rv != 0) {
+ goto fail_seqgap_push;
+ }
+
+ (*pconn)->server = server;
(*pconn)->oscid = *scid;
(*pconn)->callbacks = *callbacks;
(*pconn)->version = version;
(*pconn)->mem = mem;
(*pconn)->user_data = user_data;
- (*pconn)->rx.unsent_max_offset = (*pconn)->rx.max_offset =
- params->initial_max_data;
- (*pconn)->remote.bidi.unsent_max_streams = params->initial_max_streams_bidi;
- (*pconn)->remote.bidi.max_streams = params->initial_max_streams_bidi;
- (*pconn)->remote.uni.unsent_max_streams = params->initial_max_streams_uni;
- (*pconn)->remote.uni.max_streams = params->initial_max_streams_uni;
(*pconn)->idle_ts = settings->initial_ts;
(*pconn)->crypto.key_update.confirmed_ts = UINT64_MAX;
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;
+fail_seqgap_push:
fail_scid_set_insert:
ngtcp2_mem_free(mem, scident);
fail_scident:
@@ -830,6 +850,8 @@ fail_strms_init:
delete_scid(&(*pconn)->scid.set, mem);
ngtcp2_ksl_free(&(*pconn)->scid.set);
fail_scid_set_init:
+ ngtcp2_gaptr_free(&(*pconn)->dcid.seqgap);
+fail_seqgap_init:
ngtcp2_ringbuf_free(&(*pconn)->dcid.retired);
fail_dcid_retired_init:
ngtcp2_ringbuf_free(&(*pconn)->dcid.unused);
@@ -856,6 +878,16 @@ int ngtcp2_conn_client_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
(*pconn)->local.bidi.next_stream_id = 0;
(*pconn)->local.uni.next_stream_id = 2;
+ rv = ngtcp2_conn_commit_local_transport_params(*pconn);
+ if (rv != 0) {
+ ngtcp2_conn_del(*pconn);
+ return rv;
+ }
+
+ ngtcp2_qlog_parameters_set_transport_params(
+ &(*pconn)->qlog, &(*pconn)->local.settings.transport_params,
+ (*pconn)->server, NGTCP2_QLOG_SIDE_LOCAL);
+
return 0;
}
@@ -866,24 +898,15 @@ int ngtcp2_conn_server_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
const ngtcp2_settings *settings,
const ngtcp2_mem *mem, void *user_data) {
int rv;
- ngtcp2_transport_params *params;
-
rv = conn_new(pconn, dcid, scid, path, version, callbacks, settings, mem,
user_data, 1);
if (rv != 0) {
return rv;
}
- (*pconn)->server = 1;
(*pconn)->state = NGTCP2_CS_SERVER_INITIAL;
(*pconn)->local.bidi.next_stream_id = 1;
(*pconn)->local.uni.next_stream_id = 3;
- params = &(*pconn)->local.settings.transport_params;
- if (dcid->datalen == 0) {
- /* Client uses zero-length Connection ID */
- 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;
@@ -930,13 +953,71 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) {
ngtcp2_qlog_end(&conn->qlog);
+ if (conn->early.ckm) {
+ conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx);
+ }
+ conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx);
+
+ if (conn->crypto.key_update.old_rx_ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx);
+ }
+ if (conn->crypto.key_update.new_rx_ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->crypto.key_update.new_rx_ckm->aead_ctx);
+ }
+ if (conn->crypto.key_update.new_tx_ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->crypto.key_update.new_tx_ckm->aead_ctx);
+ }
+
+ if (conn->pktns.crypto.rx.ckm) {
+ conn_call_delete_crypto_aead_ctx(conn,
+ &conn->pktns.crypto.rx.ckm->aead_ctx);
+ }
+ conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.rx.hp_ctx);
+
+ if (conn->pktns.crypto.tx.ckm) {
+ conn_call_delete_crypto_aead_ctx(conn,
+ &conn->pktns.crypto.tx.ckm->aead_ctx);
+ }
+ conn_call_delete_crypto_cipher_ctx(conn, &conn->pktns.crypto.tx.hp_ctx);
+
+ if (conn->hs_pktns) {
+ if (conn->hs_pktns->crypto.rx.ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->hs_pktns->crypto.rx.ckm->aead_ctx);
+ }
+ conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.rx.hp_ctx);
+
+ if (conn->hs_pktns->crypto.tx.ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->hs_pktns->crypto.tx.ckm->aead_ctx);
+ }
+ conn_call_delete_crypto_cipher_ctx(conn, &conn->hs_pktns->crypto.tx.hp_ctx);
+ }
+ if (conn->in_pktns) {
+ if (conn->in_pktns->crypto.rx.ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->in_pktns->crypto.rx.ckm->aead_ctx);
+ }
+ conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.rx.hp_ctx);
+
+ if (conn->in_pktns->crypto.tx.ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->in_pktns->crypto.tx.ckm->aead_ctx);
+ }
+ conn_call_delete_crypto_cipher_ctx(conn, &conn->in_pktns->crypto.tx.hp_ctx);
+ }
+
+ conn_call_delete_crypto_aead_ctx(conn, &conn->crypto.retry_aead_ctx);
+
ngtcp2_mem_free(conn->mem, conn->crypto.decrypt_buf.base);
ngtcp2_mem_free(conn->mem, conn->local.settings.token.base);
ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem);
ngtcp2_crypto_km_del(conn->crypto.key_update.new_rx_ckm, conn->mem);
ngtcp2_crypto_km_del(conn->crypto.key_update.new_tx_ckm, conn->mem);
- ngtcp2_vec_del(conn->early.hp_key, conn->mem);
ngtcp2_crypto_km_del(conn->early.ckm, conn->mem);
pktns_free(&conn->pktns, conn->mem);
@@ -961,6 +1042,7 @@ void ngtcp2_conn_del(ngtcp2_conn *conn) {
ngtcp2_pq_free(&conn->scid.used);
delete_scid(&conn->scid.set, conn->mem);
ngtcp2_ksl_free(&conn->scid.set);
+ ngtcp2_gaptr_free(&conn->dcid.seqgap);
ngtcp2_ringbuf_free(&conn->dcid.retired);
ngtcp2_ringbuf_free(&conn->dcid.unused);
@@ -1031,18 +1113,20 @@ static ngtcp2_duration conn_compute_ack_delay(ngtcp2_conn *conn) {
* Out of memory.
*/
static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
- ngtcp2_acktr *acktr, uint8_t type,
+ ngtcp2_pktns *pktns, uint8_t type,
ngtcp2_tstamp ts, ngtcp2_duration ack_delay,
uint64_t ack_delay_exponent) {
- /* TODO Measure an actual size of ACK bloks to find the best default
- value. */
+ /* TODO Measure an actual size of ACK blocks to find the best
+ default value. */
const size_t initial_max_ack_blks = 8;
int64_t last_pkt_num;
+ ngtcp2_acktr *acktr = &pktns->acktr;
ngtcp2_ack_blk *blk;
ngtcp2_ksl_it it;
ngtcp2_acktr_entry *rpkt;
ngtcp2_ack *ack;
size_t blk_idx;
+ ngtcp2_tstamp largest_ack_ts;
int rv;
if (acktr->flags & NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK) {
@@ -1071,22 +1155,35 @@ static int conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
ack = &conn->tx.ack->ack;
- rpkt = ngtcp2_ksl_it_get(&it);
- last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
ack->type = NGTCP2_FRAME_ACK;
- ack->largest_ack = rpkt->pkt_num;
- ack->first_ack_blklen = rpkt->len - 1;
+ ack->num_blks = 0;
+
+ rpkt = ngtcp2_ksl_it_get(&it);
+
+ if (rpkt->pkt_num == pktns->rx.max_pkt_num) {
+ last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
+ largest_ack_ts = rpkt->tstamp;
+ ack->largest_ack = rpkt->pkt_num;
+ ack->first_ack_blklen = rpkt->len - 1;
+
+ ngtcp2_ksl_it_next(&it);
+ } else {
+ assert(rpkt->pkt_num < pktns->rx.max_pkt_num);
+
+ last_pkt_num = pktns->rx.max_pkt_num;
+ largest_ack_ts = pktns->rx.max_pkt_ts;
+ ack->largest_ack = pktns->rx.max_pkt_num;
+ ack->first_ack_blklen = 0;
+ }
+
if (type == NGTCP2_PKT_SHORT) {
- ack->ack_delay_unscaled = ts - rpkt->tstamp;
+ ack->ack_delay_unscaled = ts - largest_ack_ts;
ack->ack_delay = ack->ack_delay_unscaled / NGTCP2_MICROSECONDS /
(1UL << ack_delay_exponent);
} else {
ack->ack_delay_unscaled = 0;
ack->ack_delay = 0;
}
- ack->num_blks = 0;
-
- ngtcp2_ksl_it_next(&it);
for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {
if (ack->num_blks == NGTCP2_MAX_ACK_BLKS) {
@@ -1189,11 +1286,10 @@ static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_rtb *rtb,
if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) {
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;
}
@@ -1264,19 +1360,52 @@ static size_t conn_retry_early_payloadlen(ngtcp2_conn *conn) {
return 0;
}
+static void conn_cryptofrq_clear(ngtcp2_conn *conn, ngtcp2_pktns *pktns) {
+ ngtcp2_frame_chain *frc;
+ ngtcp2_ksl_it it;
+
+ for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it);
+ ngtcp2_ksl_it_next(&it)) {
+ frc = ngtcp2_ksl_it_get(&it);
+ ngtcp2_frame_chain_del(frc, conn->mem);
+ }
+ ngtcp2_ksl_clear(&pktns->crypto.tx.frq);
+}
+
/*
- * conn_cryptofrq_top returns the element which sits on top of the
- * queue. The queue must not be empty.
+ * conn_cryptofrq_unacked_offset returns the CRYPTO frame offset by
+ * taking into account acknowledged offset. If there is no data to
+ * send, this function returns (uint64_t)-1.
*/
-static ngtcp2_frame_chain *conn_cryptofrq_top(ngtcp2_conn *conn,
+static uint64_t conn_cryptofrq_unacked_offset(ngtcp2_conn *conn,
ngtcp2_pktns *pktns) {
+ ngtcp2_frame_chain *frc;
+ ngtcp2_crypto *fr;
+ ngtcp2_range gap;
+ ngtcp2_rtb *rtb = &pktns->rtb;
ngtcp2_ksl_it it;
+ size_t datalen;
+
(void)conn;
- assert(ngtcp2_ksl_len(&pktns->crypto.tx.frq));
+ for (it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq); !ngtcp2_ksl_it_end(&it);
+ ngtcp2_ksl_it_next(&it)) {
+ frc = ngtcp2_ksl_it_get(&it);
+ fr = &frc->fr.crypto;
+
+ gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->offset);
+
+ datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
+
+ if (gap.begin <= fr->offset) {
+ return fr->offset;
+ }
+ if (gap.begin < fr->offset + datalen) {
+ return gap.begin;
+ }
+ }
- it = ngtcp2_ksl_begin(&pktns->crypto.tx.frq);
- return ngtcp2_ksl_it_get(&it);
+ return (uint64_t)-1;
}
static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
@@ -1286,7 +1415,6 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
uint64_t offset, end_offset;
size_t idx, end_idx;
uint64_t base_offset, end_base_offset;
- ngtcp2_ksl_it gapit;
ngtcp2_range gap;
ngtcp2_rtb *rtb = &pktns->rtb;
ngtcp2_vec *v;
@@ -1305,9 +1433,7 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
offset = fr->offset;
base_offset = 0;
- gapit =
- ngtcp2_gaptr_get_first_gap_after(&rtb->crypto->tx.acked_offset, offset);
- gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit);
+ gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, offset);
if (gap.begin < offset) {
gap.begin = offset;
}
@@ -1370,6 +1496,7 @@ static int conn_cryptofrq_unacked_pop(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
}
nfr = &nfrc->fr.crypto;
+ nfr->type = NGTCP2_FRAME_CRYPTO;
memcpy(nfr->data, fr->data + end_idx,
sizeof(nfr->data[0]) * (fr->datacnt - end_idx));
@@ -1707,6 +1834,8 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
int pkt_empty = 1;
int padded = 0;
int hd_logged = 0;
+ uint64_t crypto_offset;
+ ngtcp2_ssize num_reclaimed;
switch (type) {
case NGTCP2_PKT_INITIAL:
@@ -1731,7 +1860,7 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
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;
+ cc.hp_ctx = pktns->crypto.tx.hp_ctx;
cc.encrypt = conn->callbacks.encrypt;
cc.hp_mask = conn->callbacks.hp_mask;
@@ -1757,7 +1886,7 @@ 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,
+ rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts,
/* ack_delay = */ 0,
NGTCP2_DEFAULT_ACK_DELAY_EXPONENT);
if (rv != 0) {
@@ -1776,11 +1905,17 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
}
+build_pkt:
for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) {
left = ngtcp2_ppe_left(&ppe);
- left = ngtcp2_pkt_crypto_max_datalen(
- conn_cryptofrq_top(conn, pktns)->fr.crypto.offset, left, left);
+ crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns);
+ if (crypto_offset == (size_t)-1) {
+ conn_cryptofrq_clear(conn, pktns);
+ break;
+ }
+
+ left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
if (left == (size_t)-1) {
break;
}
@@ -1806,7 +1941,33 @@ static ngtcp2_ssize conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
pkt_empty = 0;
rtb_entry_flags |=
- NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_CRYPTO_PKT;
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
+ }
+
+ if (!(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) &&
+ pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) {
+ num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns,
+ pktns->rtb.probe_pkt_left + 1);
+ if (num_reclaimed < 0) {
+ ngtcp2_frame_chain_list_del(frq, conn->mem);
+ return rv;
+ }
+ if (num_reclaimed) {
+ goto build_pkt;
+ }
+ /* We had pktns->rtb.num_retransmittable > 0 but the contents of
+ those packets have been acknowledged (i.e., retransmission in
+ another packet). For server, in this case, we don't have to
+ send any probe packet. Client needs to send probe packets
+ until it knows that server has completed address validation or
+ handshake has been confirmed. */
+ if (pktns->rtb.num_retransmittable == 0 &&
+ (conn->server ||
+ (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED |
+ NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) {
+ pktns->rtb.probe_pkt_left = 0;
+ ngtcp2_conn_set_loss_detection_timer(conn, ts);
+ }
}
/* Don't send any PING frame if client Initial has not been
@@ -1961,7 +2122,7 @@ static ngtcp2_ssize conn_write_ack_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
ackfr = NULL;
- rv = conn_create_ack_frame(conn, &ackfr, &pktns->acktr, type, ts, ack_delay,
+ rv = conn_create_ack_frame(conn, &ackfr, pktns, type, ts, ack_delay,
ack_delay_exponent);
if (rv != 0) {
return rv;
@@ -1990,6 +2151,11 @@ static void conn_discard_pktns(ngtcp2_conn *conn, ngtcp2_pktns **ppktns,
conn->cstat.last_tx_pkt_ts[pktns->rtb.pktns_id] = UINT64_MAX;
conn->cstat.loss_time[pktns->rtb.pktns_id] = UINT64_MAX;
+ conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx);
+ conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx);
+ conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx);
+ conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx);
+
pktns_del(pktns, conn->mem);
*ppktns = NULL;
@@ -2386,9 +2552,9 @@ typedef enum {
/* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING indicates that packet
should be padded */
NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING = 0x01,
- /* NGTCP2_WRITE_PKT_FLAG_STREAM_MORE indicates that more stream DATA
- may come and it should be encoded into the current packet. */
- NGTCP2_WRITE_PKT_FLAG_STREAM_MORE = 0x02,
+ /* NGTCP2_WRITE_PKT_FLAG_MORE indicates that more frames might come
+ and it should be encoded into the current packet. */
+ NGTCP2_WRITE_PKT_FLAG_MORE = 0x02,
} ngtcp2_write_pkt_flag;
/*
@@ -2397,13 +2563,14 @@ typedef enum {
* packet. It can be NGTCP2_PKT_SHORT or NGTCP2_PKT_0RTT.
*
* This function can send new stream data. In order to send stream
- * data, specify the underlying stream to |data_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.
+ * data, specify the underlying stream and parameters to
+ * |vmsg|->stream. If |vmsg|->stream.fin is set to nonzero, it
+ * signals that the given data is the final portion of the stream.
+ * |vmsg|->stream.data vector of length |vmsg|->stream.datacnt
+ * specifies stream data to send. The number of bytes sent to the
+ * stream is assigned to *|vmsg|->stream.pdatalen. If 0 length STREAM
+ * data is sent, 0 is assigned to it. The caller should initialize
+ * *|vmsg|->stream.pdatalen to -1.
*
* If |require_padding| is nonzero, padding bytes are added to occupy
* the remaining packet payload.
@@ -2419,10 +2586,8 @@ typedef enum {
* Stream data could not be written because of flow control.
*/
static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
- size_t destlen, ngtcp2_ssize *pdatalen,
- uint8_t type, ngtcp2_strm *data_strm,
- int fin, const ngtcp2_vec *datav,
- size_t datavcnt, uint8_t flags,
+ size_t destlen, ngtcp2_vmsg *vmsg,
+ uint8_t type, uint8_t flags,
ngtcp2_tstamp ts) {
int rv = 0;
ngtcp2_crypto_cc *cc = &conn->pkt.cc;
@@ -2439,7 +2604,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
int stream_blocked = 0;
ngtcp2_pktns *pktns = &conn->pktns;
size_t left;
- size_t datalen = ngtcp2_vec_len(datav, datavcnt);
+ size_t datalen = 0;
ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT];
size_t datacnt;
uint8_t rtb_entry_flags = NGTCP2_RTB_FLAG_NONE;
@@ -2447,12 +2612,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
ngtcp2_path_challenge_entry *pcent;
uint8_t hd_flags;
int require_padding = (flags & NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING) != 0;
- int stream_more = (flags & NGTCP2_WRITE_PKT_FLAG_STREAM_MORE) != 0;
+ int write_more = (flags & NGTCP2_WRITE_PKT_FLAG_MORE) != 0;
int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0;
size_t min_pktlen = conn_min_short_pktlen(conn);
int padded = 0;
int credit_expanded = 0;
ngtcp2_cc_pkt cc_pkt;
+ uint64_t crypto_offset;
+ uint64_t stream_offset;
+ ngtcp2_ssize num_reclaimed;
+ int fin;
/* Return 0 if destlen is less than minimum packet length which can
trigger Stateless Reset */
@@ -2460,13 +2629,20 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
return 0;
}
- if (data_strm) {
- ndatalen = conn_enforce_flow_control(conn, data_strm, datalen);
- /* 0 length STREAM frame is allowed */
- if (ndatalen || datalen == 0) {
- send_stream = 1;
- } else {
- stream_blocked = 1;
+ if (vmsg) {
+ switch (vmsg->type) {
+ case NGTCP2_VMSG_TYPE_STREAM:
+ datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt);
+ ndatalen = conn_enforce_flow_control(conn, vmsg->stream.strm, datalen);
+ /* 0 length STREAM frame is allowed */
+ if (ndatalen || datalen == 0) {
+ send_stream = 1;
+ } else {
+ stream_blocked = 1;
+ }
+ break;
+ default:
+ break;
}
}
@@ -2478,7 +2654,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
? NGTCP2_PKT_FLAG_KEY_PHASE
: NGTCP2_PKT_FLAG_NONE;
cc->ckm = pktns->crypto.tx.ckm;
- cc->hp_key = pktns->crypto.tx.hp_key;
+ cc->hp_ctx = pktns->crypto.tx.hp_ctx;
/* transport parameter is only valid after handshake completion
which means we don't know how many connection ID that remote
@@ -2499,7 +2675,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
hd_flags = NGTCP2_PKT_FLAG_LONG_FORM;
cc->ckm = conn->early.ckm;
- cc->hp_key = conn->early.hp_key;
+ cc->hp_ctx = conn->early.hp_ctx;
break;
default:
/* Unreachable */
@@ -2566,7 +2742,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
rv = conn_create_ack_frame(
- conn, &ackfr, &pktns->acktr, type, ts, conn_compute_ack_delay(conn),
+ conn, &ackfr, pktns, type, ts, conn_compute_ack_delay(conn),
conn->local.settings.transport_params.ack_delay_exponent);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
@@ -2585,7 +2761,16 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
}
+ build_pkt:
for (pfrc = &pktns->tx.frq; *pfrc;) {
+ if ((*pfrc)->binder &&
+ ((*pfrc)->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK)) {
+ frc = *pfrc;
+ *pfrc = (*pfrc)->next;
+ ngtcp2_frame_chain_del(frc, conn->mem);
+ continue;
+ }
+
switch ((*pfrc)->fr.type) {
case NGTCP2_FRAME_STOP_SENDING:
strm =
@@ -2649,7 +2834,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING;
+ rtb_entry_flags |=
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
pfrc = &(*pfrc)->next;
}
@@ -2657,8 +2843,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
for (; ngtcp2_ksl_len(&pktns->crypto.tx.frq);) {
left = ngtcp2_ppe_left(ppe);
- left = ngtcp2_pkt_crypto_max_datalen(
- conn_cryptofrq_top(conn, pktns)->fr.crypto.offset, left, left);
+ crypto_offset = conn_cryptofrq_unacked_offset(conn, pktns);
+ if (crypto_offset == (size_t)-1) {
+ conn_cryptofrq_clear(conn, pktns);
+ break;
+ }
+
+ left = ngtcp2_pkt_crypto_max_datalen(crypto_offset, left, left);
if (left == (size_t)-1) {
break;
@@ -2683,7 +2874,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
pfrc = &(*pfrc)->next;
pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING;
+ rtb_entry_flags |=
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
}
}
@@ -2714,7 +2906,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
assert(NGTCP2_ERR_NOBUF == rv);
} else {
pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING;
+ rtb_entry_flags |=
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
pfrc = &(*pfrc)->next;
}
}
@@ -2745,7 +2938,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
assert(NGTCP2_ERR_NOBUF == rv);
} else {
pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING;
+ rtb_entry_flags |=
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
pfrc = &(*pfrc)->next;
}
}
@@ -2776,7 +2970,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
pkt_empty = 0;
credit_expanded = 1;
- rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING;
+ rtb_entry_flags |=
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
pfrc = &(*pfrc)->next;
strm->rx.max_offset = strm->rx.unsent_max_offset;
}
@@ -2786,11 +2981,17 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
continue;
}
+ stream_offset = ngtcp2_strm_streamfrq_unacked_offset(strm);
+ if (stream_offset == (uint64_t)-1) {
+ ngtcp2_strm_streamfrq_clear(strm);
+ ngtcp2_conn_tx_strmq_pop(conn);
+ continue;
+ }
+
left = ngtcp2_ppe_left(ppe);
- left = ngtcp2_pkt_stream_max_datalen(
- strm->stream_id, ngtcp2_strm_streamfrq_top(strm)->fr.stream.offset,
- left, left);
+ left = ngtcp2_pkt_stream_max_datalen(strm->stream_id, stream_offset,
+ left, left);
if (left == (size_t)-1) {
break;
@@ -2816,7 +3017,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
pfrc = &(*pfrc)->next;
pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING;
+ rtb_entry_flags |=
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
if (ngtcp2_strm_streamfrq_empty(strm)) {
ngtcp2_conn_tx_strmq_pop(conn);
@@ -2837,7 +3039,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
decrease packet count. */
if (ackfr == NULL && credit_expanded) {
rv = conn_create_ack_frame(
- conn, &ackfr, &pktns->acktr, type, ts, /* ack_delay = */ 0,
+ conn, &ackfr, pktns, type, ts, /* ack_delay = */ 0,
conn->local.settings.transport_params.ack_delay_exponent);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
@@ -2855,6 +3057,29 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
}
}
+
+ if (rv != NGTCP2_ERR_NOBUF && !send_stream &&
+ !(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) &&
+ pktns->rtb.num_retransmittable && pktns->tx.frq == NULL &&
+ pktns->rtb.probe_pkt_left) {
+ num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns,
+ pktns->rtb.probe_pkt_left + 1);
+ if (num_reclaimed < 0) {
+ return rv;
+ }
+ if (num_reclaimed) {
+ goto build_pkt;
+ }
+
+ /* We had pktns->rtb.num_retransmittable > 0 but the contents of
+ those packets have been acknowledged (i.e., retransmission in
+ another packet). In this case, we don't have to send any
+ probe packet. */
+ if (pktns->rtb.num_retransmittable == 0) {
+ pktns->rtb.probe_pkt_left = 0;
+ ngtcp2_conn_set_loss_detection_timer(conn, ts);
+ }
+ }
} else {
pfrc = conn->pkt.pfrc;
rtb_entry_flags |= conn->pkt.rtb_entry_flags;
@@ -2865,12 +3090,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
left = ngtcp2_ppe_left(ppe);
if (rv != NGTCP2_ERR_NOBUF && send_stream && *pfrc == NULL &&
- (ndatalen = ngtcp2_pkt_stream_max_datalen(data_strm->stream_id,
- data_strm->tx.offset, ndatalen,
- left)) != (size_t)-1 &&
+ (ndatalen = ngtcp2_pkt_stream_max_datalen(
+ vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen,
+ left)) != (size_t)-1 &&
(ndatalen || datalen == 0)) {
datacnt = ngtcp2_vec_copy_at_most(
- data, &ndatalen, NGTCP2_MAX_STREAM_DATACNT, datav, datavcnt, ndatalen);
+ data, &ndatalen, NGTCP2_MAX_STREAM_DATACNT, vmsg->stream.data,
+ vmsg->stream.datacnt, ndatalen);
rv = ngtcp2_frame_chain_stream_datacnt_new(&nfrc, datacnt, conn->mem);
if (rv != 0) {
@@ -2880,12 +3106,13 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
nfrc->fr.stream.type = NGTCP2_FRAME_STREAM;
nfrc->fr.stream.flags = 0;
- nfrc->fr.stream.stream_id = data_strm->stream_id;
- nfrc->fr.stream.offset = data_strm->tx.offset;
+ nfrc->fr.stream.stream_id = vmsg->stream.strm->stream_id;
+ nfrc->fr.stream.offset = vmsg->stream.strm->tx.offset;
nfrc->fr.stream.datacnt = datacnt;
ngtcp2_vec_copy(nfrc->fr.stream.data, data, datacnt);
- fin = fin && ndatalen == datalen;
+ fin = (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_FIN) &&
+ ndatalen == datalen;
nfrc->fr.stream.fin = (uint8_t)fin;
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
@@ -2897,17 +3124,18 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
pfrc = &(*pfrc)->next;
pkt_empty = 0;
- rtb_entry_flags |= NGTCP2_RTB_FLAG_ACK_ELICITING;
+ rtb_entry_flags |=
+ NGTCP2_RTB_FLAG_ACK_ELICITING | NGTCP2_RTB_FLAG_RETRANSMITTABLE;
- data_strm->tx.offset += ndatalen;
+ vmsg->stream.strm->tx.offset += ndatalen;
conn->tx.offset += ndatalen;
if (fin) {
- ngtcp2_strm_shutdown(data_strm, NGTCP2_STRM_FLAG_SHUT_WR);
+ ngtcp2_strm_shutdown(vmsg->stream.strm, NGTCP2_STRM_FLAG_SHUT_WR);
}
- if (pdatalen) {
- *pdatalen = (ngtcp2_ssize)ndatalen;
+ if (vmsg->stream.pdatalen) {
+ *vmsg->stream.pdatalen = (ngtcp2_ssize)ndatalen;
}
} else {
send_stream = 0;
@@ -2922,7 +3150,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
if (conn->pktns.rtb.probe_pkt_left == 0) {
return 0;
}
- } else if (stream_more) {
+ } else if (write_more) {
conn->pkt.pfrc = pfrc;
conn->pkt.pkt_empty = pkt_empty;
conn->pkt.rtb_entry_flags = rtb_entry_flags;
@@ -2930,7 +3158,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
conn->flags |= NGTCP2_CONN_FLAG_PPE_PENDING;
if (send_stream) {
- return NGTCP2_ERR_WRITE_STREAM_MORE;
+ return NGTCP2_ERR_WRITE_MORE;
}
if (ngtcp2_conn_get_max_data_left(conn) && stream_blocked) {
@@ -2939,8 +3167,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
}
if (!(rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING)) {
- if (pktns->rtb.probe_pkt_left ||
- pktns->tx.num_non_ack_pkt >= NGTCP2_MAX_NON_ACK_TX_PKT) {
+ if (pktns->tx.num_non_ack_pkt >= NGTCP2_MAX_NON_ACK_TX_PKT) {
lfr.type = NGTCP2_FRAME_PING;
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr);
@@ -2950,9 +3177,6 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
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 {
@@ -2966,6 +3190,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
before ngtcp2_rtb_entry is safely created and added. */
lfr.type = NGTCP2_FRAME_PADDING;
if ((require_padding ||
+ /* Making full sized packet will help GSO a bit */
+ ngtcp2_ppe_left(ppe) < 10 ||
(type == NGTCP2_PKT_0RTT && conn->state == NGTCP2_CS_CLIENT_INITIAL)) &&
ngtcp2_ppe_left(ppe)) {
lfr.padding.len = ngtcp2_ppe_padding(ppe);
@@ -2989,6 +3215,8 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, uint8_t *dest,
ngtcp2_qlog_pkt_sent_end(&conn->qlog, hd, (size_t)nwrite);
+ /* TODO ack-eliciting vs needs-tracking */
+ /* probe packet needs tracking but it does not need ACK, could be lost. */
if ((rtb_entry_flags & NGTCP2_RTB_FLAG_ACK_ELICITING) || padded) {
rv = ngtcp2_rtb_entry_new(&ent, hd, NULL, ts, (size_t)nwrite,
rtb_entry_flags, conn->mem);
@@ -3090,7 +3318,7 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest,
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;
+ cc.hp_ctx = pktns->crypto.tx.hp_ctx;
cc.encrypt = conn->callbacks.encrypt;
cc.hp_mask = conn->callbacks.hp_mask;
@@ -3206,9 +3434,9 @@ static int conn_handshake_remnants_left(ngtcp2_conn *conn) {
ngtcp2_pktns *hs_pktns = conn->hs_pktns;
return !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED) ||
- (in_pktns && (in_pktns->rtb.num_ack_eliciting ||
+ (in_pktns && (in_pktns->rtb.num_retransmittable ||
ngtcp2_ksl_len(&in_pktns->crypto.tx.frq))) ||
- (hs_pktns && (hs_pktns->rtb.num_ack_eliciting ||
+ (hs_pktns && (hs_pktns->rtb.num_retransmittable ||
ngtcp2_ksl_len(&hs_pktns->crypto.tx.frq)));
}
@@ -3388,9 +3616,9 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn,
}
assert(conn->callbacks.rand);
- rv = conn->callbacks.rand(conn, lfr.path_challenge.data,
+ rv = conn->callbacks.rand(lfr.path_challenge.data,
sizeof(lfr.path_challenge.data),
- NGTCP2_RAND_CTX_PATH_CHALLENGE, conn->user_data);
+ NGTCP2_RAND_CTX_PATH_CHALLENGE);
if (rv != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -3399,7 +3627,7 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn,
/* TODO reconsider this. This might get larger pretty quickly than
validation timeout which is just around 3*PTO. */
- expiry = ts + 6ULL * NGTCP2_DEFAULT_INITIAL_RTT * (1ULL << pv->loss_count);
+ expiry = ts + 6ULL * conn->cstat.initial_rtt * (1ULL << pv->loss_count);
ngtcp2_pv_add_entry(pv, lfr.path_challenge.data, expiry);
@@ -3505,17 +3733,18 @@ static uint64_t conn_tx_strmq_first_cycle(ngtcp2_conn *conn) {
return strm->cycle;
}
-/*
- * conn_resched_frames reschedules frames linked from |*pfrc| for
- * retransmission.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
-static int conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
+uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn) {
+ ngtcp2_strm *strm;
+
+ if (ngtcp2_pq_empty(&conn->tx.strmq)) {
+ return 0;
+ }
+
+ strm = ngtcp2_struct_of(ngtcp2_pq_top(&conn->tx.strmq), ngtcp2_strm, pe);
+ return strm->cycle;
+}
+
+int ngtcp2_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
ngtcp2_frame_chain **pfrc) {
ngtcp2_frame_chain **first = pfrc;
ngtcp2_frame_chain *frc;
@@ -3605,7 +3834,6 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
ngtcp2_rtb *rtb = &conn->pktns.rtb;
ngtcp2_rtb *in_rtb;
uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1];
- ngtcp2_frame_chain *frc = NULL;
ngtcp2_vec *token;
if (!in_pktns || conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) {
@@ -3622,7 +3850,8 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
retry.odcid = conn->dcid.current.cid;
rv = ngtcp2_pkt_verify_retry_tag(&retry, pkt, pktlen, conn->callbacks.encrypt,
- &conn->crypto.retry_aead);
+ &conn->crypto.retry_aead,
+ &conn->crypto.retry_aead_ctx);
if (rv != 0) {
ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT,
"unable to verify Retry packet integrity");
@@ -3659,22 +3888,13 @@ 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, &conn->cstat);
-
- rv = conn_resched_frames(conn, &conn->pktns, &frc);
+ rv = ngtcp2_rtb_remove_all(rtb, conn, &conn->pktns, &conn->cstat);
if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- ngtcp2_frame_chain_list_del(frc, conn->mem);
return rv;
}
- frc = NULL;
- ngtcp2_rtb_remove_all(in_rtb, &frc, &conn->cstat);
-
- rv = conn_resched_frames(conn, in_pktns, &frc);
+ rv = ngtcp2_rtb_remove_all(in_rtb, conn, in_pktns, &conn->cstat);
if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- ngtcp2_frame_chain_list_del(frc, conn->mem);
return rv;
}
@@ -3692,6 +3912,7 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
ngtcp2_cpymem(token->base, retry.token.base, retry.token.len);
+ reset_conn_stat_recovery(&conn->cstat);
conn_reset_congestion_state(conn);
return 0;
@@ -3699,15 +3920,11 @@ 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_conn_stat *cstat, ngtcp2_tstamp ts) {
- ngtcp2_frame_chain *frc = NULL;
int rv;
ngtcp2_duration pto = conn_compute_pto(conn, pktns);
- ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, &frc, cstat, pto, ts);
-
- rv = conn_resched_frames(conn, pktns, &frc);
+ rv = ngtcp2_rtb_detect_lost_pkt(&pktns->rtb, conn, pktns, cstat, pto, ts);
if (rv != 0) {
- ngtcp2_frame_chain_list_del(frc, conn->mem);
return rv;
}
@@ -3983,7 +4200,7 @@ static ngtcp2_ssize decrypt_pkt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
ngtcp2_crypto_create_nonce(nonce, ckm->iv.base, ckm->iv.len, pkt_num);
- rv = decrypt(dest, aead, payload, payloadlen, ckm->key.base, nonce,
+ rv = decrypt(dest, aead, &ckm->aead_ctx, payload, payloadlen, nonce,
ckm->iv.len, ad, adlen);
if (rv != 0) {
@@ -4017,7 +4234,7 @@ static ngtcp2_ssize decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, size_t destlen,
const ngtcp2_crypto_cipher *hp,
const uint8_t *pkt, size_t pktlen,
size_t pkt_num_offset, ngtcp2_crypto_km *ckm,
- const ngtcp2_vec *hp_key,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx,
ngtcp2_hp_mask hp_mask) {
size_t sample_offset;
uint8_t *p = dest;
@@ -4037,7 +4254,7 @@ static ngtcp2_ssize decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, size_t destlen,
sample_offset = pkt_num_offset + 4;
- rv = hp_mask(mask, hp, hp_key->base, pkt + sample_offset);
+ rv = hp_mask(mask, hp, hp_ctx, pkt + sample_offset);
if (rv != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -4083,8 +4300,12 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn,
int rv;
uint64_t offset;
+ if (!strm->rx.rob) {
+ return 0;
+ }
+
for (;;) {
- datalen = ngtcp2_rob_data_at(&strm->rx.rob, &data, rx_offset);
+ datalen = ngtcp2_rob_data_at(strm->rx.rob, &data, rx_offset);
if (datalen == 0) {
assert(rx_offset == ngtcp2_strm_rx_offset(strm));
return 0;
@@ -4098,7 +4319,7 @@ static int conn_emit_pending_crypto_data(ngtcp2_conn *conn,
return rv;
}
- ngtcp2_rob_pop(&strm->rx.rob, rx_offset - datalen, datalen);
+ ngtcp2_rob_pop(strm->rx.rob, rx_offset - datalen, datalen);
}
}
@@ -4129,7 +4350,7 @@ 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) {
- conn_reset_conn_stat(conn, &conn->cstat);
+ conn_reset_conn_stat_cc(conn, &conn->cstat);
conn_reset_rx_rate(conn);
@@ -4210,16 +4431,16 @@ static int pktns_pkt_num_is_duplicate(ngtcp2_pktns *pktns, int64_t pkt_num) {
* pktns_commit_recv_pkt_num marks packet number |pkt_num| as
* received.
*/
-static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num) {
+static int pktns_commit_recv_pkt_num(ngtcp2_pktns *pktns, int64_t pkt_num,
+ ngtcp2_tstamp ts) {
int rv;
- ngtcp2_ksl_it it;
- ngtcp2_range range;
if (pktns->rx.max_pkt_num + 1 != pkt_num) {
ngtcp2_acktr_immediate_ack(&pktns->acktr);
}
if (pktns->rx.max_pkt_num < pkt_num) {
pktns->rx.max_pkt_num = pkt_num;
+ pktns->rx.max_pkt_ts = ts;
}
rv = ngtcp2_gaptr_push(&pktns->rx.pngap, (uint64_t)pkt_num, 1);
@@ -4228,9 +4449,7 @@ 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);
- ngtcp2_ksl_remove(&pktns->rx.pngap.gap, NULL, &range);
+ ngtcp2_gaptr_drop_first_gap(&pktns->rx.pngap);
}
return 0;
@@ -4310,7 +4529,7 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn,
ngtcp2_crypto_aead *aead;
ngtcp2_crypto_cipher *hp;
ngtcp2_crypto_km *ckm;
- const ngtcp2_vec *hp_key;
+ ngtcp2_crypto_cipher_ctx *hp_ctx;
ngtcp2_hp_mask hp_mask;
ngtcp2_decrypt decrypt;
size_t aead_overhead;
@@ -4539,14 +4758,14 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn,
aead = &pktns->crypto.ctx.aead;
hp = &pktns->crypto.ctx.hp;
ckm = pktns->crypto.rx.ckm;
- hp_key = pktns->crypto.rx.hp_key;
+ hp_ctx = &pktns->crypto.rx.hp_ctx;
assert(ckm);
assert(hp_mask);
assert(decrypt);
nwrite = decrypt_hp(&hd, plain_hdpkt, sizeof(plain_hdpkt), hp, pkt, pktlen,
- (size_t)nread, ckm, hp_key, hp_mask);
+ (size_t)nread, ckm, hp_ctx, hp_mask);
if (nwrite < 0) {
if (ngtcp2_err_is_fatal((int)nwrite)) {
return nwrite;
@@ -4712,7 +4931,7 @@ static ngtcp2_ssize conn_recv_handshake_pkt(ngtcp2_conn *conn,
ngtcp2_qlog_pkt_received_end(&conn->qlog, &hd, pktlen);
- rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num);
+ rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num, pkt_ts);
if (rv != 0) {
return rv;
}
@@ -4886,6 +5105,10 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm,
uint32_t sdflags;
int handshake_completed = conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED;
+ if (!strm->rx.rob) {
+ return 0;
+ }
+
for (;;) {
/* Stop calling callback if application has called
ngtcp2_conn_shutdown_stream_read() inside the callback.
@@ -4894,7 +5117,7 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm,
return 0;
}
- datalen = ngtcp2_rob_data_at(&strm->rx.rob, &data, rx_offset);
+ datalen = ngtcp2_rob_data_at(strm->rx.rob, &data, rx_offset);
if (datalen == 0) {
assert(rx_offset == ngtcp2_strm_rx_offset(strm));
return 0;
@@ -4917,12 +5140,10 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm,
return rv;
}
- ngtcp2_rob_pop(&strm->rx.rob, rx_offset - datalen, datalen);
+ ngtcp2_rob_pop(strm->rx.rob, rx_offset - datalen, datalen);
}
}
-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.
@@ -4975,16 +5196,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level,
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;
@@ -5004,7 +5216,7 @@ static int conn_recv_crypto(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level,
uint64_t offset = rx_offset;
rx_offset += datalen;
- rv = ngtcp2_rob_remove_prefix(&crypto->rx.rob, rx_offset);
+ rv = ngtcp2_strm_update_rx_offset(crypto, rx_offset);
if (rv != 0) {
return rv;
}
@@ -5216,7 +5428,7 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr,
datalen -= ncut;
rx_offset += datalen;
- rv = ngtcp2_rob_remove_prefix(&strm->rx.rob, rx_offset);
+ rv = ngtcp2_strm_update_rx_offset(strm, rx_offset);
if (rv != 0) {
return rv;
}
@@ -5803,39 +6015,53 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn,
return 0;
}
- if (!found) {
- len = ngtcp2_ringbuf_len(&conn->dcid.unused);
+ if (found) {
+ return 0;
+ }
+
+ if (ngtcp2_gaptr_is_pushed(&conn->dcid.seqgap, fr->seq, 1)) {
+ return 0;
+ }
+
+ rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, fr->seq, 1);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (ngtcp2_ksl_len(&conn->dcid.seqgap.gap) > 32) {
+ ngtcp2_gaptr_drop_first_gap(&conn->dcid.seqgap);
+ }
+
+ len = ngtcp2_ringbuf_len(&conn->dcid.unused);
- if (conn->dcid.current.seq >= conn->dcid.retire_prior_to) {
+ if (conn->dcid.current.seq >= conn->dcid.retire_prior_to) {
+ ++extra_dcid;
+ }
+ if (pv) {
+ if (pv->dcid.seq != conn->dcid.current.seq &&
+ pv->dcid.seq >= conn->dcid.retire_prior_to) {
++extra_dcid;
}
- if (pv) {
- if (pv->dcid.seq != conn->dcid.current.seq &&
- pv->dcid.seq >= conn->dcid.retire_prior_to) {
- ++extra_dcid;
- }
- if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
- pv->fallback_dcid.seq != conn->dcid.current.seq &&
- pv->fallback_dcid.seq >= conn->dcid.retire_prior_to) {
- ++extra_dcid;
- }
- }
-
- if (conn->local.settings.transport_params.active_connection_id_limit <=
- len + extra_dcid) {
- return NGTCP2_ERR_CONNECTION_ID_LIMIT;
+ if ((pv->flags & NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE) &&
+ pv->fallback_dcid.seq != conn->dcid.current.seq &&
+ pv->fallback_dcid.seq >= conn->dcid.retire_prior_to) {
+ ++extra_dcid;
}
+ }
- if (len >= NGTCP2_MAX_DCID_POOL_SIZE) {
- ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
- "too many connection ID");
- return 0;
- }
+ if (conn->local.settings.transport_params.active_connection_id_limit <=
+ len + extra_dcid) {
+ return NGTCP2_ERR_CONNECTION_ID_LIMIT;
+ }
- dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused);
- ngtcp2_dcid_init(dcid, fr->seq, &fr->cid, fr->stateless_reset_token);
+ if (len >= NGTCP2_MAX_DCID_POOL_SIZE) {
+ ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "too many connection ID");
+ return 0;
}
+ dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused);
+ ngtcp2_dcid_init(dcid, fr->seq, &fr->cid, fr->stateless_reset_token);
+
return 0;
}
@@ -6042,14 +6268,14 @@ static int conn_recv_new_token(ngtcp2_conn *conn, const ngtcp2_new_token *fr) {
* User-defined callback function failed.
*/
static int conn_select_preferred_addr(ngtcp2_conn *conn) {
- uint8_t buf[128];
+ struct sockaddr_storage buf;
ngtcp2_addr addr;
int rv;
ngtcp2_duration timeout;
ngtcp2_pv *pv;
ngtcp2_dcid *dcid;
- ngtcp2_addr_init(&addr, buf, 0, NULL);
+ ngtcp2_addr_init(&addr, (struct sockaddr *)&buf, 0, NULL);
if (ngtcp2_ringbuf_len(&conn->dcid.unused) == 0) {
return 0;
@@ -6069,8 +6295,7 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) {
dcid = ngtcp2_ringbuf_get(&conn->dcid.unused, 0);
timeout = 3 * conn_compute_pto(conn, &conn->pktns);
- timeout =
- ngtcp2_max(timeout, (ngtcp2_duration)(6ULL * NGTCP2_DEFAULT_INITIAL_RTT));
+ timeout = ngtcp2_max(timeout, 6 * conn->cstat.initial_rtt);
rv = ngtcp2_pv_new(&pv, dcid, timeout, NGTCP2_PV_FLAG_NONE, &conn->log,
conn->mem);
@@ -6116,8 +6341,17 @@ static int conn_recv_handshake_done(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
conn->flags |= NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED |
NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED;
+ conn->pktns.rtb.persistent_congestion_start_ts = ts;
+
conn_discard_handshake_state(conn, ts);
+ if (conn->remote.transport_params.preferred_address_present) {
+ rv = conn_select_preferred_addr(conn);
+ if (rv != 0) {
+ return rv;
+ }
+ }
+
if (conn->callbacks.handshake_confirmed) {
rv = conn->callbacks.handshake_confirmed(conn, conn->user_data);
if (rv != 0) {
@@ -6154,7 +6388,8 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
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;
+ ngtcp2_crypto_aead_ctx rx_aead_ctx = {0}, tx_aead_ctx = {0};
+ size_t secretlen, ivlen;
if ((conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) &&
(tx_ckm->use_count >= pktns->crypto.ctx.max_encryption ||
@@ -6175,17 +6410,16 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
}
secretlen = rx_ckm->secret.len;
- keylen = rx_ckm->key.len;
ivlen = rx_ckm->iv.len;
rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_rx_ckm,
- secretlen, keylen, ivlen, conn->mem);
+ secretlen, ivlen, conn->mem);
if (rv != 0) {
return rv;
}
rv = ngtcp2_crypto_km_nocopy_new(&conn->crypto.key_update.new_tx_ckm,
- secretlen, keylen, ivlen, conn->mem);
+ secretlen, ivlen, conn->mem);
if (rv != 0) {
return rv;
}
@@ -6196,21 +6430,27 @@ static int conn_prepare_key_update(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
assert(conn->callbacks.update_key);
rv = conn->callbacks.update_key(
- conn, new_rx_ckm->secret.base, new_tx_ckm->secret.base,
- new_rx_ckm->key.base, new_rx_ckm->iv.base, new_tx_ckm->key.base,
- new_tx_ckm->iv.base, rx_ckm->secret.base, tx_ckm->secret.base, secretlen,
- conn->user_data);
+ conn, new_rx_ckm->secret.base, new_tx_ckm->secret.base, &rx_aead_ctx,
+ new_rx_ckm->iv.base, &tx_aead_ctx, new_tx_ckm->iv.base,
+ rx_ckm->secret.base, tx_ckm->secret.base, secretlen, conn->user_data);
if (rv != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
+ new_rx_ckm->aead_ctx = rx_aead_ctx;
+ new_tx_ckm->aead_ctx = tx_aead_ctx;
+
if (!(rx_ckm->flags & NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE)) {
new_rx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE;
new_tx_ckm->flags |= NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE;
}
- ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem);
- conn->crypto.key_update.old_rx_ckm = NULL;
+ if (conn->crypto.key_update.old_rx_ckm) {
+ conn_call_delete_crypto_aead_ctx(
+ conn, &conn->crypto.key_update.old_rx_ckm->aead_ctx);
+ ngtcp2_crypto_km_del(conn->crypto.key_update.old_rx_ckm, conn->mem);
+ conn->crypto.key_update.old_rx_ckm = NULL;
+ }
return 0;
}
@@ -6233,7 +6473,11 @@ static void conn_rotate_keys(ngtcp2_conn *conn, int64_t pkt_num) {
conn->crypto.key_update.new_rx_ckm = NULL;
pktns->crypto.rx.ckm->pkt_num = pkt_num;
+ assert(pktns->crypto.tx.ckm);
+
+ conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx);
ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
+
pktns->crypto.tx.ckm = conn->crypto.key_update.new_tx_ckm;
conn->crypto.key_update.new_tx_ckm = NULL;
pktns->crypto.tx.ckm->pkt_num = pktns->tx.last_pkt_num + 1;
@@ -6318,8 +6562,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
"non-probing packet was received from new remote address");
timeout = 3 * conn_compute_pto(conn, &conn->pktns);
- timeout =
- ngtcp2_max(timeout, (ngtcp2_duration)(6ULL * NGTCP2_DEFAULT_INITIAL_RTT));
+ timeout = ngtcp2_max(timeout, 6 * conn->cstat.initial_rtt);
if (require_new_cid) {
dcid = *(ngtcp2_dcid *)ngtcp2_ringbuf_get(&conn->dcid.unused, 0);
@@ -6457,7 +6700,7 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
ngtcp2_qlog_pkt_received_end(&conn->qlog, hd, pktlen);
- rv = pktns_commit_recv_pkt_num(pktns, hd->pkt_num);
+ rv = pktns_commit_recv_pkt_num(pktns, hd->pkt_num, pkt_ts);
if (rv != 0) {
return rv;
}
@@ -6466,7 +6709,8 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
ngtcp2_acktr_immediate_ack(&pktns->acktr);
}
- rv = ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd->pkt_num, require_ack, ts);
+ rv = ngtcp2_conn_sched_ack(conn, &pktns->acktr, hd->pkt_num, require_ack,
+ pkt_ts);
if (rv != 0) {
return rv;
}
@@ -6529,7 +6773,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
ngtcp2_crypto_aead *aead;
ngtcp2_crypto_cipher *hp;
ngtcp2_crypto_km *ckm;
- const ngtcp2_vec *hp_key;
+ ngtcp2_crypto_cipher_ctx *hp_ctx;
uint8_t plain_hdpkt[1500];
ngtcp2_hp_mask hp_mask;
ngtcp2_decrypt decrypt;
@@ -6578,7 +6822,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
pktns = conn->hs_pktns;
ckm = pktns->crypto.rx.ckm;
- hp_key = pktns->crypto.rx.hp_key;
+ hp_ctx = &pktns->crypto.rx.hp_ctx;
hp_mask = conn->callbacks.hp_mask;
decrypt = conn->callbacks.decrypt;
aead_overhead = conn->crypto.aead_overhead;
@@ -6590,7 +6834,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
pktns = &conn->pktns;
ckm = conn->early.ckm;
- hp_key = conn->early.hp_key;
+ hp_ctx = &conn->early.hp_ctx;
hp_mask = conn->callbacks.hp_mask;
decrypt = conn->callbacks.decrypt;
aead_overhead = conn->crypto.aead_overhead;
@@ -6611,7 +6855,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
pktns = &conn->pktns;
ckm = pktns->crypto.rx.ckm;
- hp_key = pktns->crypto.rx.hp_key;
+ hp_ctx = &pktns->crypto.rx.hp_ctx;
hp_mask = conn->callbacks.hp_mask;
decrypt = conn->callbacks.decrypt;
aead_overhead = conn->crypto.aead_overhead;
@@ -6621,7 +6865,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
hp = &pktns->crypto.ctx.hp;
nwrite = decrypt_hp(&hd, plain_hdpkt, sizeof(plain_hdpkt), hp, pkt, pktlen,
- (size_t)nread, ckm, hp_key, hp_mask);
+ (size_t)nread, ckm, hp_ctx, hp_mask);
if (nwrite < 0) {
if (ngtcp2_err_is_fatal((int)nwrite)) {
return nwrite;
@@ -6993,7 +7237,7 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path,
}
}
- rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num);
+ rv = pktns_commit_recv_pkt_num(pktns, hd.pkt_num, pkt_ts);
if (rv != 0) {
return rv;
}
@@ -7287,8 +7531,9 @@ static int conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path,
* packet buffered, perform address validation in order to buffer
* validated data only.
*/
- if (ngtcp2_rob_first_gap_offset(&conn->in_pktns->crypto.strm.rx.rob) == 0) {
- if (ngtcp2_rob_data_buffered(&conn->in_pktns->crypto.strm.rx.rob)) {
+ if (ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm) == 0) {
+ if (conn->in_pktns->crypto.strm.rx.rob &&
+ ngtcp2_rob_data_buffered(conn->in_pktns->crypto.strm.rx.rob)) {
/* Address has been validated with token */
if (conn->local.settings.token.len) {
return 0;
@@ -7386,6 +7631,8 @@ static int conn_read_handshake(ngtcp2_conn *conn, const ngtcp2_path *path,
return rv;
}
+ conn->pktns.rtb.persistent_congestion_start_ts = ts;
+
/* Re-arm loss detection timer here after handshake has been
confirmed. */
ngtcp2_conn_set_loss_detection_timer(conn, ts);
@@ -7482,8 +7729,8 @@ static size_t conn_server_hs_tx_left(ngtcp2_conn *conn) {
static ngtcp2_ssize conn_retransmit_retry_early(ngtcp2_conn *conn,
uint8_t *dest, size_t destlen,
ngtcp2_tstamp ts) {
- return conn_write_pkt(conn, dest, destlen, NULL, NGTCP2_PKT_0RTT, NULL, 0,
- NULL, 0, NGTCP2_WRITE_PKT_FLAG_NONE, ts);
+ return conn_write_pkt(conn, dest, destlen, NULL, NGTCP2_PKT_0RTT,
+ NGTCP2_WRITE_PKT_FLAG_NONE, ts);
}
/*
@@ -7628,6 +7875,11 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest,
paddr = &conn->remote.transport_params.preferred_address;
dcid = ngtcp2_ringbuf_push_back(&conn->dcid.unused);
ngtcp2_dcid_init(dcid, 1, &paddr->cid, paddr->stateless_reset_token);
+
+ rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, 1, 1);
+ if (rv != 0) {
+ return (ngtcp2_ssize)rv;
+ }
}
if (conn->remote.transport_params.stateless_reset_token_present) {
@@ -7649,13 +7901,6 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest,
return (ngtcp2_ssize)rv;
}
- if (conn->remote.transport_params.preferred_address_present) {
- rv = conn_select_preferred_addr(conn);
- if (rv != 0) {
- return rv;
- }
- }
-
cstat->bytes_sent += (size_t)res;
return res;
@@ -7728,14 +7973,15 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest,
* `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|.
+ * In order to send STREAM data in 0RTT packet, specify
+ * |vmsg|->stream. |vmsg|->stream.strm, |vmsg|->stream.fin,
+ * |vmsg|->stream.data, and |vmsg|->stream.datacnt are stream 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.
+ * The amount of 0RTT data sent is assigned to
+ * *|vmsg|->stream.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 *|vmsg|->stream.pdatalen.
*
* This function returns 0 if it cannot write any frame because buffer
* is too small, or packet is congestion limited. Application should
@@ -7745,16 +7991,14 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, uint8_t *dest,
* 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;
+static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn,
+ uint8_t *dest, size_t destlen,
+ ngtcp2_vmsg *vmsg,
+ ngtcp2_tstamp ts) {
int send_stream = 0;
ngtcp2_ssize spktlen, early_spktlen;
int was_client_initial;
- size_t datalen = ngtcp2_vec_len(datav, datavcnt);
+ size_t datalen;
size_t early_datalen = 0;
uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE;
int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0;
@@ -7763,35 +8007,26 @@ conn_client_write_handshake(ngtcp2_conn *conn, uint8_t *dest, size_t destlen,
/* conn->early.ckm might be created in the first call of
conn_handshake(). Check it later. */
- if (stream_id != -1 &&
+ if (vmsg && vmsg->type == NGTCP2_VMSG_TYPE_STREAM &&
!(conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED)) {
- strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return NGTCP2_ERR_STREAM_NOT_FOUND;
- }
-
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
- return NGTCP2_ERR_STREAM_SHUT_WR;
- }
-
- send_stream = conn_retry_early_payloadlen(conn) == 0 &&
- /* 0 length STREAM frame is allowed */
- (datalen == 0 ||
- (datalen > 0 && (strm->tx.max_offset - strm->tx.offset) &&
- (conn->tx.max_offset - conn->tx.offset)));
+ datalen = ngtcp2_vec_len(vmsg->stream.data, vmsg->stream.datacnt);
+ send_stream =
+ conn_retry_early_payloadlen(conn) == 0 &&
+ /* 0 length STREAM frame is allowed */
+ (datalen == 0 ||
+ (datalen > 0 &&
+ (vmsg->stream.strm->tx.max_offset - vmsg->stream.strm->tx.offset) &&
+ (conn->tx.max_offset - conn->tx.offset)));
if (send_stream) {
- early_datalen = (size_t)ngtcp2_min((uint64_t)datalen,
- strm->tx.max_offset - strm->tx.offset);
early_datalen =
- (size_t)ngtcp2_min((uint64_t)early_datalen,
- conn->tx.max_offset - conn->tx.offset) +
+ conn_enforce_flow_control(conn, vmsg->stream.strm, datalen) +
NGTCP2_STREAM_OVERHEAD;
- if (flags & NGTCP2_WRITE_STREAM_FLAG_MORE) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_STREAM_MORE;
+ if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) {
+ wflags |= NGTCP2_WRITE_PKT_FLAG_MORE;
}
} else {
- strm = NULL;
+ vmsg = NULL;
}
}
@@ -7828,14 +8063,14 @@ conn_client_write_handshake(ngtcp2_conn *conn, uint8_t *dest, size_t destlen,
return spktlen;
}
- early_spktlen = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_0RTT,
- strm, fin, datav, datavcnt, wflags, ts);
+ early_spktlen =
+ conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_0RTT, wflags, ts);
if (early_spktlen < 0) {
switch (early_spktlen) {
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
return spktlen;
- case NGTCP2_ERR_WRITE_STREAM_MORE:
+ case NGTCP2_ERR_WRITE_MORE:
conn->pkt.was_client_initial = was_client_initial;
conn->pkt.hs_spktlen = spktlen;
break;
@@ -7928,155 +8163,162 @@ size_t ngtcp2_conn_get_aead_overhead(ngtcp2_conn *conn) {
return conn->crypto.aead_overhead;
}
-int ngtcp2_conn_install_initial_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_initial_key(
+ ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *rx_aead_ctx,
+ const uint8_t *rx_iv, const ngtcp2_crypto_cipher_ctx *rx_hp_ctx,
+ const ngtcp2_crypto_aead_ctx *tx_aead_ctx, const uint8_t *tx_iv,
+ const ngtcp2_crypto_cipher_ctx *tx_hp_ctx, size_t ivlen) {
ngtcp2_pktns *pktns = conn->in_pktns;
int rv;
assert(pktns);
- if (pktns->crypto.rx.hp_key) {
- ngtcp2_vec_del(pktns->crypto.rx.hp_key, conn->mem);
- pktns->crypto.rx.hp_key = NULL;
- }
+ conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.rx.hp_ctx);
+ pktns->crypto.rx.hp_ctx.native_handle = NULL;
+
if (pktns->crypto.rx.ckm) {
+ conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.rx.ckm->aead_ctx);
ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
pktns->crypto.rx.ckm = NULL;
}
- if (pktns->crypto.tx.hp_key) {
- ngtcp2_vec_del(pktns->crypto.tx.hp_key, conn->mem);
- pktns->crypto.tx.hp_key = NULL;
- }
+
+ conn_call_delete_crypto_cipher_ctx(conn, &pktns->crypto.tx.hp_ctx);
+ pktns->crypto.tx.hp_ctx.native_handle = NULL;
+
if (pktns->crypto.tx.ckm) {
+ conn_call_delete_crypto_aead_ctx(conn, &pktns->crypto.tx.ckm->aead_ctx);
ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
pktns->crypto.tx.ckm = NULL;
}
- 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, NULL, rx_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_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
+ conn->mem);
if (rv != 0) {
return rv;
}
- rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, tx_key, keylen,
- tx_iv, ivlen, conn->mem);
- if (rv != 0) {
- return rv;
- }
+ /* Take owner ship after we are sure that no failure occurs, so that
+ caller can delete these contexts on failure. */
+ pktns->crypto.rx.ckm->aead_ctx = *rx_aead_ctx;
+ pktns->crypto.rx.hp_ctx = *rx_hp_ctx;
+ pktns->crypto.tx.ckm->aead_ctx = *tx_aead_ctx;
+ pktns->crypto.tx.hp_ctx = *tx_hp_ctx;
- return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, tx_hp_key, keylen, conn->mem);
+ return 0;
}
-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) {
+int ngtcp2_conn_install_rx_handshake_key(
+ ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) {
ngtcp2_pktns *pktns = conn->hs_pktns;
int rv;
assert(pktns);
- assert(!pktns->crypto.rx.hp_key);
+ assert(!pktns->crypto.rx.hp_ctx.native_handle);
assert(!pktns->crypto.rx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, key, keylen, iv,
- ivlen, conn->mem);
+ rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, NULL, 0, aead_ctx, iv, ivlen,
+ conn->mem);
if (rv != 0) {
return rv;
}
- return ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem);
+ pktns->crypto.rx.hp_ctx = *hp_ctx;
+
+ return 0;
}
-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) {
+int ngtcp2_conn_install_tx_handshake_key(
+ ngtcp2_conn *conn, const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen, const ngtcp2_crypto_cipher_ctx *hp_ctx) {
ngtcp2_pktns *pktns = conn->hs_pktns;
int rv;
assert(pktns);
- assert(!pktns->crypto.tx.hp_key);
+ assert(!pktns->crypto.tx.hp_ctx.native_handle);
assert(!pktns->crypto.tx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, key, keylen, iv,
- ivlen, conn->mem);
+ rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, aead_ctx, iv, ivlen,
+ conn->mem);
if (rv != 0) {
return rv;
}
- return ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem);
+ pktns->crypto.tx.hp_ctx = *hp_ctx;
+
+ if (conn->server) {
+ return ngtcp2_conn_commit_local_transport_params(conn);
+ }
+
+ return 0;
}
-int ngtcp2_conn_install_early_key(ngtcp2_conn *conn, const uint8_t *key,
- const uint8_t *iv, const uint8_t *hp_key,
- size_t keylen, size_t ivlen) {
+int ngtcp2_conn_install_early_key(ngtcp2_conn *conn,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx) {
int rv;
- assert(!conn->early.hp_key);
+ assert(!conn->early.hp_ctx.native_handle);
assert(!conn->early.ckm);
- rv = ngtcp2_crypto_km_new(&conn->early.ckm, NULL, 0, key, keylen, iv, ivlen,
+ rv = ngtcp2_crypto_km_new(&conn->early.ckm, NULL, 0, aead_ctx, iv, ivlen,
conn->mem);
if (rv != 0) {
return rv;
}
- return ngtcp2_vec_new(&conn->early.hp_key, hp_key, keylen, conn->mem);
+ conn->early.hp_ctx = *hp_ctx;
+
+ return 0;
}
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) {
+ size_t secretlen,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx) {
ngtcp2_pktns *pktns = &conn->pktns;
int rv;
- assert(!pktns->crypto.rx.hp_key);
+ assert(!pktns->crypto.rx.hp_ctx.native_handle);
assert(!pktns->crypto.rx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, key,
- keylen, iv, ivlen, conn->mem);
+ rv = ngtcp2_crypto_km_new(&pktns->crypto.rx.ckm, secret, secretlen, aead_ctx,
+ iv, ivlen, conn->mem);
if (rv != 0) {
return rv;
}
- rv = ngtcp2_vec_new(&pktns->crypto.rx.hp_key, hp_key, keylen, conn->mem);
- if (rv != 0) {
- return rv;
- }
+ pktns->crypto.rx.hp_ctx = *hp_ctx;
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) {
+ size_t secretlen,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, size_t ivlen,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx) {
ngtcp2_pktns *pktns = &conn->pktns;
int rv;
- assert(!pktns->crypto.tx.hp_key);
+ assert(!pktns->crypto.tx.hp_ctx.native_handle);
assert(!pktns->crypto.tx.ckm);
- rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, key,
- keylen, iv, ivlen, conn->mem);
+ rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, secret, secretlen, aead_ctx,
+ iv, ivlen, conn->mem);
if (rv != 0) {
return rv;
}
- rv = ngtcp2_vec_new(&pktns->crypto.tx.hp_key, hp_key, keylen, conn->mem);
- if (rv != 0) {
- return rv;
- }
+ pktns->crypto.tx.hp_ctx = *hp_ctx;
conn->remote.transport_params = conn->remote.pending_transport_params;
conn_sync_stream_id_limit(conn);
@@ -8150,8 +8392,10 @@ ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn) {
ngtcp2_tstamp t1 = ngtcp2_conn_loss_detection_expiry(conn);
ngtcp2_tstamp t2 = ngtcp2_conn_ack_delay_expiry(conn);
ngtcp2_tstamp t3 = ngtcp2_conn_internal_expiry(conn);
+ ngtcp2_tstamp t4 = ngtcp2_conn_lost_pkt_expiry(conn);
ngtcp2_tstamp res = ngtcp2_min(t1, t2);
- return ngtcp2_min(res, t3);
+ res = ngtcp2_min(res, t3);
+ return ngtcp2_min(res, t4);
}
int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
@@ -8159,6 +8403,8 @@ int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
ngtcp2_conn_cancel_expired_ack_delay_timer(conn, ts);
+ ngtcp2_conn_remove_lost_pkt(conn, ts);
+
if (ngtcp2_conn_loss_detection_expiry(conn) <= ts) {
rv = ngtcp2_conn_on_loss_detection_timer(conn, ts);
if (rv != 0) {
@@ -8188,6 +8434,49 @@ void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn,
acktr_cancel_expired_ack_delay_timer(&conn->pktns.acktr, ts);
}
+ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn) {
+ ngtcp2_tstamp res = UINT64_MAX, ts;
+
+ if (conn->in_pktns) {
+ ts = ngtcp2_rtb_lost_pkt_ts(&conn->in_pktns->rtb);
+ if (ts != UINT64_MAX) {
+ ts += conn_compute_pto(conn, conn->in_pktns);
+ res = ngtcp2_min(res, ts);
+ }
+ }
+
+ if (conn->hs_pktns) {
+ ts = ngtcp2_rtb_lost_pkt_ts(&conn->hs_pktns->rtb);
+ if (ts != UINT64_MAX) {
+ ts += conn_compute_pto(conn, conn->hs_pktns);
+ res = ngtcp2_min(res, ts);
+ }
+ }
+
+ ts = ngtcp2_rtb_lost_pkt_ts(&conn->pktns.rtb);
+ if (ts != UINT64_MAX) {
+ ts += conn_compute_pto(conn, &conn->pktns);
+ res = ngtcp2_min(res, ts);
+ }
+
+ return res;
+}
+
+void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
+ ngtcp2_tstamp pto;
+
+ if (conn->in_pktns) {
+ pto = conn_compute_pto(conn, conn->in_pktns);
+ ngtcp2_rtb_remove_expired_lost_pkt(&conn->in_pktns->rtb, pto, ts);
+ }
+ if (conn->hs_pktns) {
+ pto = conn_compute_pto(conn, conn->hs_pktns);
+ ngtcp2_rtb_remove_expired_lost_pkt(&conn->hs_pktns->rtb, pto, ts);
+ }
+ pto = conn_compute_pto(conn, &conn->pktns);
+ ngtcp2_rtb_remove_expired_lost_pkt(&conn->pktns.rtb, pto, ts);
+}
+
/*
* conn_client_validate_transport_params validates |params| as client.
* |params| must be sent with Encrypted Extensions.
@@ -8262,7 +8551,7 @@ int ngtcp2_conn_set_remote_transport_params(
params);
ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server,
- /* local = */ 0);
+ NGTCP2_QLOG_SIDE_REMOTE);
if (conn->pktns.crypto.tx.ckm) {
conn->remote.transport_params = *params;
@@ -8308,20 +8597,86 @@ 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, conn->server,
- /* local = */ 0);
+ NGTCP2_QLOG_SIDE_REMOTE);
+}
+
+int ngtcp2_conn_set_local_transport_params(
+ ngtcp2_conn *conn, const ngtcp2_transport_params *params) {
+ assert(conn->server);
+ assert(params->active_connection_id_limit <= NGTCP2_MAX_DCID_POOL_SIZE);
+
+ if (conn->hs_pktns == NULL || conn->hs_pktns->crypto.tx.ckm) {
+ return NGTCP2_ERR_INVALID_STATE;
+ }
+
+ conn->local.settings.transport_params = *params;
+
+ return 0;
+}
+
+int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn) {
+ const ngtcp2_mem *mem = conn->mem;
+ ngtcp2_transport_params *params = &conn->local.settings.transport_params;
+ ngtcp2_scid *scident;
+ ngtcp2_ksl_it it;
+ int rv;
+
+ assert(1 == ngtcp2_ksl_len(&conn->scid.set));
+
+ if (params->active_connection_id_limit == 0) {
+ params->active_connection_id_limit =
+ NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
+ }
+
+ params->initial_scid = conn->oscid;
+
+ if (conn->oscid.datalen == 0) {
+ params->preferred_address_present = 0;
+ }
+
+ if (conn->server) {
+ if (params->stateless_reset_token_present) {
+ it = ngtcp2_ksl_begin(&conn->scid.set);
+ scident = ngtcp2_ksl_it_get(&it);
+
+ memcpy(scident->token, params->stateless_reset_token,
+ NGTCP2_STATELESS_RESET_TOKENLEN);
+ }
+
+ if (params->preferred_address_present) {
+ scident = ngtcp2_mem_malloc(mem, sizeof(*scident));
+ if (scident == NULL) {
+ return NGTCP2_ERR_NOMEM;
+ }
+
+ ngtcp2_scid_init(scident, 1, &params->preferred_address.cid,
+ params->preferred_address.stateless_reset_token);
+
+ rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scident->cid, scident);
+ if (rv != 0) {
+ ngtcp2_mem_free(mem, scident);
+ return rv;
+ }
+
+ conn->scid.last_seq = 1;
+ }
+ }
+
+ conn->rx.unsent_max_offset = conn->rx.max_offset = params->initial_max_data;
+ conn->remote.bidi.unsent_max_streams = params->initial_max_streams_bidi;
+ conn->remote.bidi.max_streams = params->initial_max_streams_bidi;
+ conn->remote.uni.unsent_max_streams = params->initial_max_streams_uni;
+ conn->remote.uni.max_streams = params->initial_max_streams_uni;
+
+ ngtcp2_qlog_parameters_set_transport_params(&conn->qlog, params, conn->server,
+ NGTCP2_QLOG_SIDE_LOCAL);
+
+ return 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,
@@ -8410,7 +8765,41 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path,
int64_t stream_id,
const ngtcp2_vec *datav, size_t datavcnt,
ngtcp2_tstamp ts) {
- ngtcp2_strm *strm = NULL;
+ ngtcp2_vmsg vmsg, *pvmsg;
+ ngtcp2_strm *strm;
+
+ if (pdatalen) {
+ *pdatalen = -1;
+ }
+
+ if (stream_id != -1) {
+ strm = ngtcp2_conn_find_stream(conn, stream_id);
+ if (strm == NULL) {
+ return NGTCP2_ERR_STREAM_NOT_FOUND;
+ }
+
+ if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
+ return NGTCP2_ERR_STREAM_SHUT_WR;
+ }
+
+ vmsg.type = NGTCP2_VMSG_TYPE_STREAM;
+ vmsg.stream.strm = strm;
+ vmsg.stream.flags = flags;
+ vmsg.stream.data = datav;
+ vmsg.stream.datacnt = datavcnt;
+ vmsg.stream.pdatalen = pdatalen;
+
+ pvmsg = &vmsg;
+ } else {
+ pvmsg = NULL;
+ }
+
+ return ngtcp2_conn_write_vmsg(conn, path, dest, destlen, pvmsg, ts);
+}
+
+ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
+ uint8_t *dest, size_t destlen,
+ ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts) {
ngtcp2_ssize nwrite;
ngtcp2_pktns *pktns = &conn->pktns;
size_t origlen = destlen;
@@ -8419,15 +8808,10 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path,
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;
- if (pdatalen) {
- *pdatalen = -1;
- }
-
if (path) {
ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
}
@@ -8436,8 +8820,7 @@ 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 = conn_client_write_handshake(conn, dest, destlen, pdatalen, flags,
- stream_id, fin, datav, datavcnt, ts);
+ nwrite = conn_client_write_handshake(conn, dest, destlen, vmsg, ts);
if (nwrite < 0 || conn->state != NGTCP2_CS_POST_HANDSHAKE) {
return nwrite;
}
@@ -8494,18 +8877,15 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path,
return rv;
}
- if (stream_id != -1) {
- strm = ngtcp2_conn_find_stream(conn, stream_id);
- if (strm == NULL) {
- return NGTCP2_ERR_STREAM_NOT_FOUND;
- }
-
- if (strm->flags & NGTCP2_STRM_FLAG_SHUT_WR) {
- return NGTCP2_ERR_STREAM_SHUT_WR;
- }
-
- if (flags & NGTCP2_WRITE_STREAM_FLAG_MORE) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_STREAM_MORE;
+ if (vmsg) {
+ switch (vmsg->type) {
+ case NGTCP2_VMSG_TYPE_STREAM:
+ if (vmsg->stream.flags & NGTCP2_WRITE_STREAM_FLAG_MORE) {
+ wflags |= NGTCP2_WRITE_PKT_FLAG_MORE;
+ }
+ break;
+ default:
+ break;
}
}
@@ -8514,8 +8894,8 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path,
conn->pkt.hs_spktlen = 0;
/* dest and destlen have already been adjusted in ppe in the first
run. They are adjusted for probe packet later. */
- nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT,
- strm, fin, datav, datavcnt, wflags, ts);
+ nwrite =
+ conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_SHORT, wflags, ts);
goto fin;
} else {
if (conn->state == NGTCP2_CS_POST_HANDSHAKE) {
@@ -8557,14 +8937,14 @@ ngtcp2_ssize ngtcp2_conn_writev_stream(ngtcp2_conn *conn, ngtcp2_path *path,
"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);
+ nwrite =
+ conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_SHORT, wflags, ts);
goto fin;
}
- nwrite = conn_write_pkt(conn, dest, destlen, pdatalen, NGTCP2_PKT_SHORT, strm,
- fin, datav, datavcnt, wflags, ts);
+ nwrite =
+ conn_write_pkt(conn, dest, destlen, vmsg, NGTCP2_PKT_SHORT, wflags, ts);
if (nwrite) {
assert(nwrite != NGTCP2_ERR_NOBUF);
goto fin;
@@ -8590,36 +8970,15 @@ fin:
return nwrite;
}
-ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn,
- ngtcp2_path *path,
+static ngtcp2_ssize conn_write_connection_close(ngtcp2_conn *conn,
uint8_t *dest, size_t destlen,
+ uint8_t pkt_type,
uint64_t error_code,
ngtcp2_tstamp ts) {
ngtcp2_pktns *in_pktns = conn->in_pktns;
ngtcp2_pktns *hs_pktns = conn->hs_pktns;
ngtcp2_ssize res = 0, nwrite;
ngtcp2_frame fr;
- uint8_t pkt_type;
-
- conn->log.last_ts = ts;
- conn->qlog.last_ts = ts;
-
- if (conn_check_pkt_num_exhausted(conn)) {
- return NGTCP2_ERR_PKT_NUM_EXHAUSTED;
- }
-
- switch (conn->state) {
- case NGTCP2_CS_CLIENT_INITIAL:
- case NGTCP2_CS_CLOSING:
- case NGTCP2_CS_DRAINING:
- return NGTCP2_ERR_INVALID_STATE;
- default:
- break;
- }
-
- if (path) {
- ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
- }
fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
fr.connection_close.error_code = error_code;
@@ -8627,18 +8986,6 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn,
fr.connection_close.reasonlen = 0;
fr.connection_close.reason = NULL;
- if (conn->state == NGTCP2_CS_POST_HANDSHAKE) {
- pkt_type = NGTCP2_PKT_SHORT;
- } else if (hs_pktns && hs_pktns->crypto.tx.ckm) {
- pkt_type = NGTCP2_PKT_HANDSHAKE;
- } else if (in_pktns && in_pktns->crypto.tx.ckm) {
- pkt_type = NGTCP2_PKT_INITIAL;
- } else {
- /* This branch is taken if server has not read any Initial packet
- from client. */
- return NGTCP2_ERR_INVALID_STATE;
- }
-
if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) &&
pkt_type != NGTCP2_PKT_INITIAL) {
if (in_pktns && conn->server) {
@@ -8683,9 +9030,61 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn,
return NGTCP2_ERR_NOBUF;
}
+ return res;
+}
+
+ngtcp2_ssize ngtcp2_conn_write_connection_close(ngtcp2_conn *conn,
+ ngtcp2_path *path,
+ uint8_t *dest, size_t destlen,
+ uint64_t error_code,
+ ngtcp2_tstamp ts) {
+ ngtcp2_pktns *in_pktns = conn->in_pktns;
+ ngtcp2_pktns *hs_pktns = conn->hs_pktns;
+ uint8_t pkt_type;
+ ngtcp2_ssize nwrite;
+
+ conn->log.last_ts = ts;
+ conn->qlog.last_ts = ts;
+
+ if (conn_check_pkt_num_exhausted(conn)) {
+ return NGTCP2_ERR_PKT_NUM_EXHAUSTED;
+ }
+
+ switch (conn->state) {
+ case NGTCP2_CS_CLIENT_INITIAL:
+ case NGTCP2_CS_CLOSING:
+ case NGTCP2_CS_DRAINING:
+ return NGTCP2_ERR_INVALID_STATE;
+ default:
+ break;
+ }
+
+ if (path) {
+ ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
+ }
+
+ if (conn->state == NGTCP2_CS_POST_HANDSHAKE ||
+ (conn->server && conn->pktns.crypto.tx.ckm)) {
+ pkt_type = NGTCP2_PKT_SHORT;
+ } else if (hs_pktns && hs_pktns->crypto.tx.ckm) {
+ pkt_type = NGTCP2_PKT_HANDSHAKE;
+ } else if (in_pktns && in_pktns->crypto.tx.ckm) {
+ pkt_type = NGTCP2_PKT_INITIAL;
+ } else {
+ /* This branch is taken if server has not read any Initial packet
+ from client. */
+ return NGTCP2_ERR_INVALID_STATE;
+ }
+
+ nwrite = conn_write_connection_close(conn, dest, destlen, pkt_type,
+ error_code, ts);
+ if (nwrite < 0) {
+ return nwrite;
+ }
+
conn->state = NGTCP2_CS_CLOSING;
- return res;
+ return nwrite;
}
ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn,
@@ -8694,6 +9093,7 @@ ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn,
uint64_t app_error_code,
ngtcp2_tstamp ts) {
ngtcp2_ssize nwrite;
+ ngtcp2_ssize res = 0;
ngtcp2_frame fr;
conn->log.last_ts = ts;
@@ -8704,12 +9104,38 @@ ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn,
}
switch (conn->state) {
- case NGTCP2_CS_POST_HANDSHAKE:
- break;
- default:
+ case NGTCP2_CS_CLIENT_INITIAL:
+ case NGTCP2_CS_CLOSING:
+ case NGTCP2_CS_DRAINING:
return NGTCP2_ERR_INVALID_STATE;
+ default:
+ break;
+ }
+
+ if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)) {
+ nwrite = conn_write_connection_close(conn, dest, destlen,
+ conn->hs_pktns->crypto.tx.ckm
+ ? NGTCP2_PKT_HANDSHAKE
+ : NGTCP2_PKT_INITIAL,
+ NGTCP2_APPLICATION_ERROR, ts);
+ if (nwrite < 0) {
+ return nwrite;
+ }
+ res = nwrite;
+ dest += nwrite;
+ destlen -= (size_t)nwrite;
}
+ if (conn->state != NGTCP2_CS_POST_HANDSHAKE) {
+ assert(res);
+
+ if (!conn->server || !conn->pktns.crypto.tx.ckm) {
+ return res;
+ }
+ }
+
+ assert(conn->pktns.crypto.tx.ckm);
+
if (path) {
ngtcp2_path_copy(path, &conn->dcid.current.ps.path);
}
@@ -8728,13 +9154,15 @@ ngtcp2_ssize ngtcp2_conn_write_application_close(ngtcp2_conn *conn,
return nwrite;
}
- if (nwrite == 0) {
+ res += nwrite;
+
+ if (res == 0) {
return NGTCP2_ERR_NOBUF;
}
conn->state = NGTCP2_CS_CLOSING;
- return nwrite;
+ return res;
}
int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn) {
@@ -8780,7 +9208,7 @@ int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, ngtcp2_strm *strm,
if ((strm->flags & NGTCP2_STRM_FLAG_SHUT_RDWR) ==
NGTCP2_STRM_FLAG_SHUT_RDWR &&
((strm->flags & NGTCP2_STRM_FLAG_RECV_RST) ||
- ngtcp2_rob_first_gap_offset(&strm->rx.rob) == strm->rx.last_offset) &&
+ ngtcp2_strm_rx_offset(strm) == strm->rx.last_offset) &&
(((strm->flags & NGTCP2_STRM_FLAG_SENT_RST) &&
(strm->flags & NGTCP2_STRM_FLAG_RST_ACKED)) ||
(!(strm->flags & NGTCP2_STRM_FLAG_SENT_RST) &&
@@ -8974,17 +9402,12 @@ uint32_t ngtcp2_conn_get_negotiated_version(ngtcp2_conn *conn) {
int ngtcp2_conn_early_data_rejected(ngtcp2_conn *conn) {
ngtcp2_pktns *pktns = &conn->pktns;
ngtcp2_rtb *rtb = &conn->pktns.rtb;
- ngtcp2_frame_chain *frc = NULL;
int rv;
conn->flags |= NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED;
- ngtcp2_rtb_remove_all(rtb, &frc, &conn->cstat);
-
- rv = conn_resched_frames(conn, pktns, &frc);
+ rv = ngtcp2_rtb_remove_all(rtb, conn, pktns, &conn->cstat);
if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- ngtcp2_frame_chain_list_del(frc, conn->mem);
return rv;
}
@@ -8997,8 +9420,9 @@ void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
rtt = ngtcp2_max(rtt, NGTCP2_GRANULARITY);
+ cstat->latest_rtt = rtt;
+
if (cstat->min_rtt == UINT64_MAX) {
- cstat->latest_rtt = rtt;
cstat->min_rtt = rtt;
cstat->smoothed_rtt = rtt;
cstat->rttvar = rtt / 2;
@@ -9014,8 +9438,6 @@ void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
rtt -= ack_delay;
}
- cstat->latest_rtt = rtt;
-
cstat->rttvar = (cstat->rttvar * 3 + (cstat->smoothed_rtt < rtt
? rtt - cstat->smoothed_rtt
: cstat->smoothed_rtt - rtt)) /
@@ -9047,7 +9469,7 @@ static ngtcp2_pktns *conn_get_earliest_pktns(ngtcp2_conn *conn,
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 ||
+ if (ns[i] == NULL || ns[i]->rtb.num_retransmittable == 0 ||
(times[i] == UINT64_MAX ||
(earliest_ts != UINT64_MAX && times[i] >= earliest_ts) ||
(i == NGTCP2_PKTNS_ID_APP &&
@@ -9096,9 +9518,9 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
return;
}
- 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 ||
+ if ((!in_pktns || in_pktns->rtb.num_retransmittable == 0) &&
+ (!hs_pktns || hs_pktns->rtb.num_retransmittable == 0) &&
+ (pktns->rtb.num_retransmittable == 0 ||
!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED)) &&
(conn->server ||
(conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED |
@@ -9132,36 +9554,6 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
(uint64_t)(timeout / NGTCP2_MILLISECONDS));
}
-/*
- * 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
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory.
- */
-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, &conn->cstat);
- if (rv != 0) {
- assert(ngtcp2_err_is_fatal(rv));
- ngtcp2_frame_chain_list_del(frc, conn->mem);
- return rv;
- }
-
- rv = conn_resched_frames(conn, pktns, &frc);
- if (rv != 0) {
- ngtcp2_frame_chain_list_del(frc, conn->mem);
- return rv;
- }
-
- return 0;
-}
-
int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
ngtcp2_conn_stat *cstat = &conn->cstat;
int rv;
@@ -9203,16 +9595,8 @@ 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 {
- rv = conn_on_crypto_timeout(conn, in_pktns);
- if (rv != 0) {
- return rv;
- }
in_pktns->rtb.probe_pkt_left = 1;
}
} else {
@@ -9223,10 +9607,6 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
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) {
- return rv;
- }
in_pktns->rtb.probe_pkt_left = 1;
if (!conn->server) {
break;
@@ -9235,10 +9615,6 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) {
/* fall through */
case NGTCP2_PKTNS_ID_HANDSHAKE:
assert(hs_pktns);
- rv = conn_on_crypto_timeout(conn, hs_pktns);
- if (rv != 0) {
- return rv;
- }
hs_pktns->rtb.probe_pkt_left = 1;
break;
case NGTCP2_PKTNS_ID_APP:
@@ -9580,8 +9956,12 @@ const ngtcp2_crypto_ctx *ngtcp2_conn_get_initial_crypto_ctx(ngtcp2_conn *conn) {
}
void ngtcp2_conn_set_retry_aead(ngtcp2_conn *conn,
- const ngtcp2_crypto_aead *aead) {
+ const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx) {
+ assert(!conn->crypto.retry_aead_ctx.native_handle);
+
conn->crypto.retry_aead = *aead;
+ conn->crypto.retry_aead_ctx = *aead_ctx;
}
void ngtcp2_conn_set_crypto_ctx(ngtcp2_conn *conn,
@@ -9623,6 +10003,23 @@ int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn, int64_t stream_id) {
int ngtcp2_conn_is_server(ngtcp2_conn *conn) { return conn->server; }
+int ngtcp2_conn_after_retry(ngtcp2_conn *conn) {
+ return (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY) != 0;
+}
+
+int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn, int64_t stream_id,
+ void *stream_user_data) {
+ ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id);
+
+ if (strm == NULL) {
+ return NGTCP2_ERR_STREAM_NOT_FOUND;
+ }
+
+ strm->stream_user_data = stream_user_data;
+
+ return 0;
+}
+
void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
const uint8_t *data) {
memcpy(pcent->data, data, sizeof(pcent->data));
@@ -9631,6 +10028,7 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
void ngtcp2_settings_default(ngtcp2_settings *settings) {
memset(settings, 0, sizeof(*settings));
settings->cc_algo = NGTCP2_CC_ALGO_CUBIC;
+ settings->initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT;
settings->transport_params.max_udp_payload_size =
NGTCP2_DEFAULT_MAX_UDP_PAYLOAD_SIZE;
settings->transport_params.ack_delay_exponent =
@@ -9647,13 +10045,12 @@ void ngtcp2_settings_default(ngtcp2_settings *settings) {
ngtcp2_ssize ngtcp2_pkt_write_connection_close(
uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid,
const ngtcp2_cid *scid, uint64_t error_code, ngtcp2_encrypt encrypt,
- const ngtcp2_crypto_aead *aead, const uint8_t *key, const uint8_t *iv,
- ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp,
- const uint8_t *hp_key) {
+ const ngtcp2_crypto_aead *aead, const ngtcp2_crypto_aead_ctx *aead_ctx,
+ const uint8_t *iv, ngtcp2_hp_mask hp_mask, const ngtcp2_crypto_cipher *hp,
+ const ngtcp2_crypto_cipher_ctx *hp_ctx) {
ngtcp2_pkt_hd hd;
ngtcp2_crypto_km ckm;
ngtcp2_crypto_cc cc;
- ngtcp2_vec hp_key_vec;
ngtcp2_ppe ppe;
ngtcp2_frame fr = {0};
int rv;
@@ -9663,9 +10060,8 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close(
NGTCP2_PROTO_VER, /* len = */ 0);
ngtcp2_vec_init(&ckm.secret, NULL, 0);
- ngtcp2_vec_init(&ckm.key, key, 16);
ngtcp2_vec_init(&ckm.iv, iv, 12);
- ngtcp2_vec_init(&hp_key_vec, hp_key, 16);
+ ckm.aead_ctx = *aead_ctx;
ckm.pkt_num = 0;
ckm.flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
@@ -9673,7 +10069,7 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close(
cc.aead = *aead;
cc.hp = *hp;
cc.ckm = &ckm;
- cc.hp_key = &hp_key_vec;
+ cc.hp_ctx = *hp_ctx;
cc.encrypt = encrypt;
cc.hp_mask = hp_mask;
diff --git a/deps/ngtcp2/lib/ngtcp2_conn.h b/deps/ngtcp2/lib/ngtcp2_conn.h
index 39b5b029385..d7782b1114a 100644
--- a/deps/ngtcp2/lib/ngtcp2_conn.h
+++ b/deps/ngtcp2/lib/ngtcp2_conn.h
@@ -106,7 +106,7 @@ typedef enum {
/* NGTCP2_MAX_NON_ACK_TX_PKT is the maximum number of continuous non
ACK-eliciting packets. */
-#define NGTCP2_MAX_NON_ACK_TX_PKT 10
+#define NGTCP2_MAX_NON_ACK_TX_PKT 3
/*
* ngtcp2_max_frame is defined so that it covers the largest ACK
@@ -186,7 +186,7 @@ typedef struct {
uint8_t pkt_type;
} ngtcp2_crypto_data;
-typedef struct {
+typedef struct ngtcp2_pktns {
struct {
/* last_pkt_num is the packet number which the local endpoint sent
last time.*/
@@ -203,6 +203,9 @@ typedef struct {
ngtcp2_gaptr pngap;
/* max_pkt_num is the largest packet number received so far. */
int64_t max_pkt_num;
+ /* max_pkt_ts is the timestamp when max_pkt_num packet is
+ received. */
+ ngtcp2_tstamp max_pkt_ts;
/*
* buffed_pkts is buffered packets which cannot be decrypted with
* the current encryption level.
@@ -236,16 +239,16 @@ typedef struct {
/* ckm is a cryptographic key, and iv to encrypt outgoing
packets. */
ngtcp2_crypto_km *ckm;
- /* hp_key is header protection key. */
- ngtcp2_vec *hp_key;
+ /* hp_ctx is cipher context for packet header protection. */
+ ngtcp2_crypto_cipher_ctx hp_ctx;
} tx;
struct {
/* ckm is a cryptographic key, and iv to decrypt incoming
packets. */
ngtcp2_crypto_km *ckm;
- /* hp_key is header protection key. */
- ngtcp2_vec *hp_key;
+ /* hp_ctx is cipher context for packet header protection. */
+ ngtcp2_crypto_cipher_ctx hp_ctx;
} rx;
ngtcp2_strm strm;
@@ -286,7 +289,10 @@ struct ngtcp2_conn {
/* retired is a set of CID retired by local endpoint. Keep them
in 3*PTO to catch packets in flight along the old path. */
ngtcp2_ringbuf retired;
- /* retire_prior_to is the larget retire_prior_to received so
+ /* seqgap tracks received sequence numbers in order to ignore
+ retransmitted duplicated NEW_CONNECTION_ID frame. */
+ ngtcp2_gaptr seqgap;
+ /* retire_prior_to is the largest retire_prior_to received so
far. */
uint64_t retire_prior_to;
/* num_retire_queued is the number of RETIRE_CONNECTION_ID frames
@@ -352,7 +358,7 @@ struct ngtcp2_conn {
struct {
ngtcp2_crypto_km *ckm;
- ngtcp2_vec *hp_key;
+ ngtcp2_crypto_cipher_ctx hp_ctx;
} early;
struct {
@@ -432,8 +438,12 @@ struct ngtcp2_conn {
size_t aead_overhead;
/* decrypt_buf is a buffer which is used to write decrypted data. */
ngtcp2_vec decrypt_buf;
- /* retry_aead is AEAD to verify Retry packet integrity. */
+ /* retry_aead is AEAD to verify Retry packet integrity. It is
+ used by client only. */
ngtcp2_crypto_aead retry_aead;
+ /* retry_aead_ctx is AEAD cipher context to verify Retry packet
+ integrity. It is used by client only. */
+ ngtcp2_crypto_aead_ctx retry_aead_ctx;
/* tls_error is TLS related error. */
int tls_error;
} crypto;
@@ -470,6 +480,33 @@ struct ngtcp2_conn {
int server;
};
+typedef enum ngtcp2_vmsg_type {
+ NGTCP2_VMSG_TYPE_STREAM,
+} ngtcp2_vmsg_type;
+
+typedef struct ngtcp2_vmsg_stream {
+ /* strm is a stream that data is sent to. */
+ ngtcp2_strm *strm;
+ /* flags is bitwise OR of zero or more of
+ ngtcp2_write_stream_flag. */
+ uint32_t flags;
+ /* data is the pointer to ngtcp2_vec array which contains the stream
+ data to send. */
+ const ngtcp2_vec *data;
+ /* datacnt is the number of ngtcp2_vec pointed by data. */
+ size_t datacnt;
+ /* *pdatalen is the pointer to the variable which the number of
+ bytes written is assigned to if pdatalen is not NULL. */
+ ngtcp2_ssize *pdatalen;
+} ngtcp2_vmsg_stream;
+
+typedef struct ngtcp2_vmsg {
+ ngtcp2_vmsg_type type;
+ union {
+ ngtcp2_vmsg_stream stream;
+ };
+} ngtcp2_vmsg;
+
/*
* ngtcp2_conn_sched_ack stores packet number |pkt_num| and its
* reception timestamp |ts| in order to send its ACK.
@@ -591,6 +628,10 @@ int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm);
*/
ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn);
+ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
+ uint8_t *dest, size_t destlen,
+ ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts);
+
/*
* ngtcp2_conn_write_single_frame_pkt writes a packet which contains |fr|
* frame only in the buffer pointed by |dest| whose length if
@@ -612,4 +653,46 @@ ngtcp2_conn_write_single_frame_pkt(ngtcp2_conn *conn, uint8_t *dest,
const ngtcp2_cid *dcid, ngtcp2_frame *fr,
uint8_t rtb_flags, ngtcp2_tstamp ts);
+/*
+ * ngtcp2_conn_commit_local_transport_params commits the local
+ * transport parameters, which is currently set to
+ * conn->local.settings.transport_params. This function will do some
+ * amends on transport parameters for adjusting default values.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ * Out of memory.
+ * NGTCP2_ERR_INVALID_ARGUMENT
+ * CID in preferred address equals to the original SCID.
+ */
+int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn);
+
+/*
+ * ngtcp2_conn_lost_pkt_expiry returns the earliest expiry time of
+ * lost packet.
+ */
+ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn);
+
+/*
+ * ngtcp2_conn_remove_lost_pkt removes the expired lost packet.
+ */
+void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts);
+
+/*
+ * ngtcp2_conn_resched_frames reschedules frames linked from |*pfrc|
+ * for retransmission.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ * Out of memory.
+ */
+int ngtcp2_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
+ ngtcp2_frame_chain **pfrc);
+
+uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn);
+
#endif /* NGTCP2_CONN_H */
diff --git a/deps/ngtcp2/lib/ngtcp2_conv.c b/deps/ngtcp2/lib/ngtcp2_conv.c
index 7811c84d0bc..18cf3147913 100644
--- a/deps/ngtcp2/lib/ngtcp2_conv.c
+++ b/deps/ngtcp2/lib/ngtcp2_conv.c
@@ -45,19 +45,19 @@ uint64_t ngtcp2_get_uint48(const uint8_t *p) {
uint32_t ngtcp2_get_uint32(const uint8_t *p) {
uint32_t n;
memcpy(&n, p, 4);
- return ntohl(n);
+ return ngtcp2_ntohl(n);
}
uint32_t ngtcp2_get_uint24(const uint8_t *p) {
uint32_t n = 0;
memcpy(((uint8_t *)&n) + 1, p, 3);
- return ntohl(n);
+ return ngtcp2_ntohl(n);
}
uint16_t ngtcp2_get_uint16(const uint8_t *p) {
uint16_t n;
memcpy(&n, p, 2);
- return ntohs(n);
+ return ngtcp2_ntohs(n);
}
uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p) {
@@ -76,11 +76,11 @@ uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p) {
case 2:
memcpy(&n, p, 2);
n.b[0] &= 0x3f;
- return ntohs(n.n16);
+ return ngtcp2_ntohs(n.n16);
case 4:
memcpy(&n, p, 4);
n.b[0] &= 0x3f;
- return ntohl(n.n32);
+ return ngtcp2_ntohl(n.n32);
case 8:
memcpy(&n, p, 8);
n.b[0] &= 0x3f;
@@ -116,17 +116,17 @@ uint8_t *ngtcp2_put_uint48be(uint8_t *p, uint64_t n) {
}
uint8_t *ngtcp2_put_uint32be(uint8_t *p, uint32_t n) {
- n = htonl(n);
+ n = ngtcp2_htonl(n);
return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n));
}
uint8_t *ngtcp2_put_uint24be(uint8_t *p, uint32_t n) {
- n = htonl(n);
+ n = ngtcp2_htonl(n);
return ngtcp2_cpymem(p, ((const uint8_t *)&n) + 1, 3);
}
uint8_t *ngtcp2_put_uint16be(uint8_t *p, uint16_t n) {
- n = htons(n);
+ n = ngtcp2_htons(n);
return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n));
}
diff --git a/deps/ngtcp2/lib/ngtcp2_conv.h b/deps/ngtcp2/lib/ngtcp2_conv.h
index f3336f44a92..227470b9192 100644
--- a/deps/ngtcp2/lib/ngtcp2_conv.h
+++ b/deps/ngtcp2/lib/ngtcp2_conv.h
@@ -37,6 +37,10 @@
# include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
+#ifdef HAVE_BYTESWAP_H
+# include <byteswap.h>
+#endif /* HAVE_BYTESWAP_H */
+
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif /* HAVE_ENDIAN_H */
@@ -47,15 +51,25 @@
#include <ngtcp2/ngtcp2.h>
+#if defined HAVE_BSWAP_64 || HAVE_DECL_BSWAP_64
+# define ngtcp2_bswap64 bswap_64
+#else /* !HAVE_BSWAP_64 */
+# define ngtcp2_bswap64(N) \
+ ((uint64_t)(ntohl((uint32_t)(N))) << 32 | ntohl((uint32_t)((N) >> 32)))
+#endif /* !HAVE_BSWAP_64 */
+
#if defined HAVE_BE64TOH || HAVE_DECL_BE64TOH
# define ngtcp2_ntohl64(N) be64toh(N)
# define ngtcp2_htonl64(N) htobe64(N)
#else /* !HAVE_BE64TOH */
-# define ngtcp2_bswap64(N) \
- ((uint64_t)(ntohl((uint32_t)(N))) << 32 | ntohl((uint32_t)((N) >> 32)))
-# define ngtcp2_ntohl64(N) ngtcp2_bswap64(N)
-# define ngtcp2_htonl64(N) ngtcp2_bswap64(N)
-#endif /* !HAVE_BE64TOH */
+# if defined WORDS_BIGENDIAN
+# define ngtcp2_ntohl64(N) (N)
+# define ngtcp2_htonl64(N) (N)
+# else /* !WORDS_BIGENDIAN */
+# define ngtcp2_ntohl64(N) ngtcp2_bswap64(N)
+# define ngtcp2_htonl64(N) ngtcp2_bswap64(N)
+# endif /* !WORDS_BIGENDIAN */
+#endif /* !HAVE_BE64TOH */
#if defined(WIN32)
/* Windows requires ws2_32 library for ntonl family functions. We
@@ -68,7 +82,7 @@
# define STIN static inline
# endif
-STIN uint32_t htonl(uint32_t hostlong) {
+STIN uint32_t ngtcp2_htonl(uint32_t hostlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = hostlong >> 24;
@@ -78,7 +92,7 @@ STIN uint32_t htonl(uint32_t hostlong) {
return res;
}
-STIN uint16_t htons(uint16_t hostshort) {
+STIN uint16_t ngtcp2_htons(uint16_t hostshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = hostshort >> 8;
@@ -86,7 +100,7 @@ STIN uint16_t htons(uint16_t hostshort) {
return res;
}
-STIN uint32_t ntohl(uint32_t netlong) {
+STIN uint32_t ngtcp2_ntohl(uint32_t netlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&netlong;
res = *p++ << 24;
@@ -96,7 +110,7 @@ STIN uint32_t ntohl(uint32_t netlong) {
return res;
}
-STIN uint16_t ntohs(uint16_t netshort) {
+STIN uint16_t ngtcp2_ntohs(uint16_t netshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&netshort;
res = *p++ << 8;
@@ -104,7 +118,14 @@ STIN uint16_t ntohs(uint16_t netshort) {
return res;
}
-#endif /* WIN32 */
+#else /* !WIN32 */
+
+# define ngtcp2_htonl htonl
+# define ngtcp2_htons htons
+# define ngtcp2_ntohl ntohl
+# define ngtcp2_ntohs ntohs
+
+#endif /* !WIN32 */
/*
* ngtcp2_get_uint64 reads 8 bytes from |p| as 64 bits unsigned
diff --git a/deps/ngtcp2/lib/ngtcp2_crypto.c b/deps/ngtcp2/lib/ngtcp2_crypto.c
index 26eacb87299..5cfe145ec9b 100644
--- a/deps/ngtcp2/lib/ngtcp2_crypto.c
+++ b/deps/ngtcp2/lib/ngtcp2_crypto.c
@@ -32,10 +32,11 @@
#include "ngtcp2_conn.h"
int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
- size_t secretlen, const uint8_t *key, size_t keylen,
+ size_t secretlen,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *iv, size_t ivlen,
const ngtcp2_mem *mem) {
- int rv = ngtcp2_crypto_km_nocopy_new(pckm, secretlen, keylen, ivlen, mem);
+ int rv = ngtcp2_crypto_km_nocopy_new(pckm, secretlen, ivlen, mem);
if (rv != 0) {
return rv;
}
@@ -43,19 +44,20 @@ int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
if (secretlen) {
memcpy((*pckm)->secret.base, secret, secretlen);
}
- memcpy((*pckm)->key.base, key, keylen);
+ if (aead_ctx) {
+ (*pckm)->aead_ctx = *aead_ctx;
+ }
memcpy((*pckm)->iv.base, iv, ivlen);
return 0;
}
int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
- size_t keylen, size_t ivlen,
- const ngtcp2_mem *mem) {
+ size_t ivlen, const ngtcp2_mem *mem) {
size_t len;
uint8_t *p;
- len = sizeof(ngtcp2_crypto_km) + secretlen + keylen + ivlen;
+ len = sizeof(ngtcp2_crypto_km) + secretlen + ivlen;
*pckm = ngtcp2_mem_malloc(mem, len);
if (*pckm == NULL) {
@@ -66,11 +68,9 @@ int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
(*pckm)->secret.base = p;
(*pckm)->secret.len = secretlen;
p += secretlen;
- (*pckm)->key.base = p;
- (*pckm)->key.len = keylen;
- p += keylen;
(*pckm)->iv.base = p;
(*pckm)->iv.len = ivlen;
+ (*pckm)->aead_ctx.native_handle = NULL;
(*pckm)->pkt_num = -1;
(*pckm)->use_count = 0;
(*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
diff --git a/deps/ngtcp2/lib/ngtcp2_crypto.h b/deps/ngtcp2/lib/ngtcp2_crypto.h
index 1cc144e801a..b1baf30a85f 100644
--- a/deps/ngtcp2/lib/ngtcp2_crypto.h
+++ b/deps/ngtcp2/lib/ngtcp2_crypto.h
@@ -50,7 +50,7 @@ typedef enum {
typedef struct {
ngtcp2_vec secret;
- ngtcp2_vec key;
+ ngtcp2_crypto_aead_ctx aead_ctx;
ngtcp2_vec iv;
/* pkt_num is a packet number of a packet which uses this keying
material. For encryption key, it is the lowest packet number of
@@ -75,7 +75,8 @@ typedef struct {
* store secret is update keys. Only 1RTT key can be updated.
*/
int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
- size_t secretlen, const uint8_t *key, size_t keylen,
+ size_t secretlen,
+ const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *iv, size_t ivlen,
const ngtcp2_mem *mem);
@@ -84,8 +85,7 @@ int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
* it does not copy secret, key and IV.
*/
int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
- size_t keylen, size_t ivlen,
- const ngtcp2_mem *mem);
+ size_t ivlen, const ngtcp2_mem *mem);
void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem);
@@ -93,7 +93,7 @@ typedef struct {
ngtcp2_crypto_aead aead;
ngtcp2_crypto_cipher hp;
ngtcp2_crypto_km *ckm;
- const ngtcp2_vec *hp_key;
+ ngtcp2_crypto_cipher_ctx hp_ctx;
size_t aead_overhead;
ngtcp2_encrypt encrypt;
ngtcp2_decrypt decrypt;
diff --git a/deps/ngtcp2/lib/ngtcp2_err.c b/deps/ngtcp2/lib/ngtcp2_err.c
index 6de827b0f97..5a2425367d4 100644
--- a/deps/ngtcp2/lib/ngtcp2_err.c
+++ b/deps/ngtcp2/lib/ngtcp2_err.c
@@ -94,8 +94,8 @@ const char *ngtcp2_strerror(int liberr) {
return "ERR_INTERNAL";
case NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED:
return "ERR_CRYPTO_BUFFER_EXCEEDED";
- case NGTCP2_ERR_WRITE_STREAM_MORE:
- return "ERR_WRITE_STREAM_MORE";
+ case NGTCP2_ERR_WRITE_MORE:
+ return "ERR_WRITE_MORE";
case NGTCP2_ERR_RETRY:
return "ERR_RETRY";
case NGTCP2_ERR_DROP_CONN:
diff --git a/deps/ngtcp2/lib/ngtcp2_gaptr.c b/deps/ngtcp2/lib/ngtcp2_gaptr.c
index b93cd828c21..6e7f3b7e554 100644
--- a/deps/ngtcp2/lib/ngtcp2_gaptr.c
+++ b/deps/ngtcp2/lib/ngtcp2_gaptr.c
@@ -26,6 +26,7 @@
#include "ngtcp2_range.h"
#include <string.h>
+#include <assert.h>
int ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) {
int rv;
@@ -115,3 +116,14 @@ int ngtcp2_gaptr_is_pushed(ngtcp2_gaptr *gaptr, uint64_t offset,
ngtcp2_range m = ngtcp2_range_intersect(&q, &k);
return ngtcp2_range_len(&m) == 0;
}
+
+void ngtcp2_gaptr_drop_first_gap(ngtcp2_gaptr *gaptr) {
+ ngtcp2_ksl_it it = ngtcp2_ksl_begin(&gaptr->gap);
+ ngtcp2_range r;
+
+ assert(!ngtcp2_ksl_it_end(&it));
+
+ r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
+
+ ngtcp2_ksl_remove(&gaptr->gap, NULL, &r);
+}
diff --git a/deps/ngtcp2/lib/ngtcp2_gaptr.h b/deps/ngtcp2/lib/ngtcp2_gaptr.h
index 03181449dea..9e7fa03086e 100644
--- a/deps/ngtcp2/lib/ngtcp2_gaptr.h
+++ b/deps/ngtcp2/lib/ngtcp2_gaptr.h
@@ -93,4 +93,11 @@ ngtcp2_ksl_it ngtcp2_gaptr_get_first_gap_after(ngtcp2_gaptr *gaptr,
int ngtcp2_gaptr_is_pushed(ngtcp2_gaptr *gaptr, uint64_t offset,
size_t datalen);
+/*
+ * ngtcp2_gaptr_drop_first_gap deletes the first gap entirely as if
+ * the range is pushed. This function assumes that at least one gap
+ * exists.
+ */
+void ngtcp2_gaptr_drop_first_gap(ngtcp2_gaptr *gaptr);
+
#endif /* NGTCP2_GAPTR_H */
diff --git a/deps/ngtcp2/lib/ngtcp2_ksl.c b/deps/ngtcp2/lib/ngtcp2_ksl.c
index 10c49806254..0c47150cb14 100644
--- a/deps/ngtcp2/lib/ngtcp2_ksl.c
+++ b/deps/ngtcp2/lib/ngtcp2_ksl.c
@@ -275,6 +275,13 @@ int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
i = ksl_bsearch(ksl, blk, key, ksl->compar);
if (blk->leaf) {
+ if (i < blk->n &&
+ !ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
+ if (it) {
+ *it = ngtcp2_ksl_end(ksl);
+ }
+ return NGTCP2_ERR_INVALID_ARGUMENT;
+ }
ksl_insert_node(ksl, blk, i, key, data);
++ksl->n;
if (it) {
@@ -446,8 +453,8 @@ static int key_equal(ngtcp2_ksl_compar compar, const ngtcp2_ksl_key *lhs,
return !compar(lhs, rhs) && !compar(rhs, lhs);
}
-void ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
- const ngtcp2_ksl_key *key) {
+int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
+ const ngtcp2_ksl_key *key) {
ngtcp2_ksl_blk *blk = ksl->head;
ngtcp2_ksl_node *node;
size_t i;
@@ -461,10 +468,20 @@ void ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
for (;;) {
i = ksl_bsearch(ksl, blk, key, ksl->compar);
- assert(i < blk->n);
+ if (i == blk->n) {
+ if (it) {
+ *it = ngtcp2_ksl_end(ksl);
+ }
+ return NGTCP2_ERR_INVALID_ARGUMENT;
+ }
if (blk->leaf) {
- assert(i < blk->n);
+ if (ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
+ if (it) {
+ *it = ngtcp2_ksl_end(ksl);
+ }
+ return NGTCP2_ERR_INVALID_ARGUMENT;
+ }
ksl_remove_node(ksl, blk, i);
--ksl->n;
if (it) {
@@ -474,7 +491,7 @@ void ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
ngtcp2_ksl_it_init(it, ksl, blk, i);
}
}
- return;
+ return 0;
}
node = ngtcp2_ksl_nth_node(ksl, blk, i);
diff --git a/deps/ngtcp2/lib/ngtcp2_ksl.h b/deps/ngtcp2/lib/ngtcp2_ksl.h
index ae8bb8de5b5..071e10dce1b 100644
--- a/deps/ngtcp2/lib/ngtcp2_ksl.h
+++ b/deps/ngtcp2/lib/ngtcp2_ksl.h
@@ -167,27 +167,33 @@ void ngtcp2_ksl_free(ngtcp2_ksl *ksl);
* successful insertion, the iterator points to the inserted node is
* stored in |*it|.
*
- * This function assumes that |key| does not exist in |ksl|.
- *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
+ * NGTCP2_ERR_INVALID_ARGUMENT
+ * |key| already exists.
*/
int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
const ngtcp2_ksl_key *key, void *data);
/*
- * ngtcp2_ksl_remove removes the |key| from |ksl|. It assumes such
- * the key is included in |ksl|.
+ * ngtcp2_ksl_remove removes the |key| from |ksl|.
*
* 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.
+ * is not NULL. If |key| is not found, no deletion takes place and
+ * the return value of ngtcp2_ksl_end(ksl) is assigned to |*it|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGTCP2_ERR_INVALID_ARGUMENT
+ * |key| does not exist.
*/
-void ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
- const ngtcp2_ksl_key *key);
+int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
+ const ngtcp2_ksl_key *key);
/*
* ngtcp2_ksl_lower_bound returns the iterator which points to the
diff --git a/deps/ngtcp2/lib/ngtcp2_map.c b/deps/ngtcp2/lib/ngtcp2_map.c
index bd214ff87b5..12a20283b4c 100644
--- a/deps/ngtcp2/lib/ngtcp2_map.c
+++ b/deps/ngtcp2/lib/ngtcp2_map.c
@@ -26,6 +26,7 @@
#include "ngtcp2_map.h"
#include <string.h>
+#include <assert.h>
#include "ngtcp2_conv.h"
@@ -34,8 +35,7 @@
int ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
map->mem = mem;
map->tablelen = INITIAL_TABLE_LENGTH;
- map->table =
- ngtcp2_mem_calloc(mem, map->tablelen, sizeof(ngtcp2_map_entry *));
+ map->table = ngtcp2_mem_calloc(mem, map->tablelen, sizeof(ngtcp2_map_bucket));
if (map->table == NULL) {
return NGTCP2_ERR_NOMEM;
}
@@ -45,20 +45,52 @@ int ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
return 0;
}
-void ngtcp2_map_free(ngtcp2_map *map) { ngtcp2_mem_free(map->mem, map->table); }
+void ngtcp2_map_free(ngtcp2_map *map) {
+ size_t i;
+ ngtcp2_map_bucket *bkt;
+
+ if (!map) {
+ return;
+ }
+
+ for (i = 0; i < map->tablelen; ++i) {
+ bkt = &map->table[i];
+ if (bkt->ksl) {
+ ngtcp2_ksl_free(bkt->ksl);
+ ngtcp2_mem_free(map->mem, bkt->ksl);
+ }
+ }
+
+ ngtcp2_mem_free(map->mem, map->table);
+}
void ngtcp2_map_each_free(ngtcp2_map *map,
int (*func)(ngtcp2_map_entry *entry, void *ptr),
void *ptr) {
uint32_t i;
+ ngtcp2_map_bucket *bkt;
+ ngtcp2_ksl_it it;
+
for (i = 0; i < map->tablelen; ++i) {
- ngtcp2_map_entry *entry;
- for (entry = map->table[i]; entry;) {
- ngtcp2_map_entry *next = entry->next;
- func(entry, ptr);
- entry = next;
+ bkt = &map->table[i];
+
+ if (bkt->ptr) {
+ func(bkt->ptr, ptr);
+ bkt->ptr = NULL;
+ assert(bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0);
+ continue;
+ }
+
+ if (bkt->ksl) {
+ for (it = ngtcp2_ksl_begin(bkt->ksl); !ngtcp2_ksl_it_end(&it);
+ ngtcp2_ksl_it_next(&it)) {
+ func(ngtcp2_ksl_it_get(&it), ptr);
+ }
+
+ ngtcp2_ksl_free(bkt->ksl);
+ ngtcp2_mem_free(map->mem, bkt->ksl);
+ bkt->ksl = NULL;
}
- map->table[i] = NULL;
}
}
@@ -67,15 +99,29 @@ int ngtcp2_map_each(ngtcp2_map *map,
void *ptr) {
int rv;
uint32_t i;
+ ngtcp2_map_bucket *bkt;
+ ngtcp2_ksl_it it;
+
for (i = 0; i < map->tablelen; ++i) {
- ngtcp2_map_entry *entry, *next;
- for (entry = map->table[i]; entry;) {
- next = entry->next;
- rv = func(entry, ptr);
+ bkt = &map->table[i];
+
+ if (bkt->ptr) {
+ rv = func(bkt->ptr, ptr);
if (rv != 0) {
return rv;
}
- entry = next;
+ assert(bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0);
+ continue;
+ }
+
+ if (bkt->ksl) {
+ for (it = ngtcp2_ksl_begin(bkt->ksl); !ngtcp2_ksl_it_end(&it);
+ ngtcp2_ksl_it_next(&it)) {
+ rv = func(ngtcp2_ksl_it_get(&it), ptr);
+ if (rv != 0) {
+ return rv;
+ }
+ }
}
}
return 0;
@@ -95,71 +141,124 @@ static uint32_t hash(key_type key, uint32_t mod) {
p = (uint8_t *)&key;
end = p + sizeof(key_type);
- for (; p != end; ++p) {
- h ^= *p;
- h *= 0x01000193u;
+ for (; p != end;) {
+ h ^= *p++;
+ h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
}
return h & (mod - 1);
}
-static int insert(ngtcp2_map_entry **table, uint32_t tablelen,
- ngtcp2_map_entry *entry) {
+static int less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
+ return *(key_type *)lhs < *(key_type *)rhs;
+}
+
+static int map_insert(ngtcp2_map *map, ngtcp2_map_bucket *table,
+ uint32_t tablelen, ngtcp2_map_entry *entry) {
uint32_t h = hash(entry->key, tablelen);
- if (table[h] == NULL) {
- table[h] = entry;
- } else {
- ngtcp2_map_entry *p;
- /* We won't allow duplicated key, so check it out. */
- for (p = table[h]; p; p = p->next) {
- if (p->key == entry->key) {
- return NGTCP2_ERR_INVALID_ARGUMENT;
- }
+ ngtcp2_map_bucket *bkt = &table[h];
+ const ngtcp2_mem *mem = map->mem;
+ int rv;
+
+ if (bkt->ptr == NULL && (bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0)) {
+ bkt->ptr = entry;
+ return 0;
+ }
+
+ if (!bkt->ksl) {
+ bkt->ksl = ngtcp2_mem_malloc(mem, sizeof(*bkt->ksl));
+ if (bkt->ksl == NULL) {
+ return NGTCP2_ERR_NOMEM;
}
- entry->next = table[h];
- table[h] = entry;
+ ngtcp2_ksl_init(bkt->ksl, less, sizeof(key_type), mem);
}
- return 0;
+
+ if (bkt->ptr) {
+ rv = ngtcp2_ksl_insert(bkt->ksl, NULL, &bkt->ptr->key, bkt->ptr);
+ if (rv != 0) {
+ return rv;
+ }
+
+ bkt->ptr = NULL;
+ }
+
+ return ngtcp2_ksl_insert(bkt->ksl, NULL, &entry->key, entry);
}
/* new_tablelen must be power of 2 */
-static int resize(ngtcp2_map *map, uint32_t new_tablelen) {
+static int map_resize(ngtcp2_map *map, uint32_t new_tablelen) {
uint32_t i;
- ngtcp2_map_entry **new_table;
+ ngtcp2_map_bucket *new_table;
+ ngtcp2_map_bucket *bkt;
+ ngtcp2_ksl_it it;
+ int rv;
new_table =
- ngtcp2_mem_calloc(map->mem, new_tablelen, sizeof(ngtcp2_map_entry *));
+ ngtcp2_mem_calloc(map->mem, new_tablelen, sizeof(ngtcp2_map_bucket));
if (new_table == NULL) {
return NGTCP2_ERR_NOMEM;
}
for (i = 0; i < map->tablelen; ++i) {
- ngtcp2_map_entry *entry;
- for (entry = map->table[i]; entry;) {
- ngtcp2_map_entry *next = entry->next;
- entry->next = NULL;
- /* This function must succeed */
- insert(new_table, new_tablelen, entry);
- entry = next;
+ bkt = &map->table[i];
+
+ if (bkt->ptr) {
+ rv = map_insert(map, new_table, new_tablelen, bkt->ptr);
+ if (rv != 0) {
+ goto fail;
+ }
+ assert(bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0);
+ continue;
+ }
+
+ if (bkt->ksl) {
+ for (it = ngtcp2_ksl_begin(bkt->ksl); !ngtcp2_ksl_it_end(&it);
+ ngtcp2_ksl_it_next(&it)) {
+ rv = map_insert(map, new_table, new_tablelen, ngtcp2_ksl_it_get(&it));
+ if (rv != 0) {
+ goto fail;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < map->tablelen; ++i) {
+ bkt = &map->table[i];
+ if (bkt->ksl) {
+ ngtcp2_ksl_free(bkt->ksl);
+ ngtcp2_mem_free(map->mem, bkt->ksl);
}
}
+
ngtcp2_mem_free(map->mem, map->table);
map->tablelen = new_tablelen;
map->table = new_table;
return 0;
+
+fail:
+ for (i = 0; i < new_tablelen; ++i) {
+ bkt = &new_table[i];
+ if (bkt->ksl) {
+ ngtcp2_ksl_free(bkt->ksl);
+ ngtcp2_mem_free(map->mem, bkt->ksl);
+ }
+ }
+
+ return rv;
}
int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_entry *new_entry) {
int rv;
+
/* Load factor is 0.75 */
if ((map->size + 1) * 4 > map->tablelen * 3) {
- rv = resize(map, map->tablelen * 2);
+ rv = map_resize(map, map->tablelen * 2);
if (rv != 0) {
return rv;
}
}
- rv = insert(map->table, map->tablelen, new_entry);
+ rv = map_insert(map, map->table, map->tablelen, new_entry);
if (rv != 0) {
return rv;
}
@@ -168,40 +267,64 @@ int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_entry *new_entry) {
}
ngtcp2_map_entry *ngtcp2_map_find(ngtcp2_map *map, key_type key) {
- uint32_t h;
- ngtcp2_map_entry *entry;
- h = hash(key, map->tablelen);
- for (entry = map->table[h]; entry; entry = entry->next) {
- if (entry->key == key) {
- return entry;
+ ngtcp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
+ ngtcp2_ksl_it it;
+
+ if (bkt->ptr) {
+ if (bkt->ptr->key == key) {
+ return bkt->ptr;
}
+ return NULL;
}
+
+ if (bkt->ksl) {
+ it = ngtcp2_ksl_lower_bound(bkt->ksl, &key);
+ if (ngtcp2_ksl_it_end(&it) || *(key_type *)ngtcp2_ksl_it_key(&it) != key) {
+ return NULL;
+ }
+ return ngtcp2_ksl_it_get(&it);
+ }
+
return NULL;
}
int ngtcp2_map_remove(ngtcp2_map *map, key_type key) {
- uint32_t h;
- ngtcp2_map_entry **dst;
-
- h = hash(key, map->tablelen);
+ ngtcp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
+ int rv;
- for (dst = &map->table[h]; *dst; dst = &(*dst)->next) {
- if ((*dst)->key != key) {
- continue;
+ if (bkt->ptr) {
+ if (bkt->ptr->key == key) {
+ bkt->ptr = NULL;
+ --map->size;
+ return 0;
}
+ return NGTCP2_ERR_INVALID_ARGUMENT;
+ }
- *dst = (*dst)->next;
+ if (bkt->ksl) {
+ rv = ngtcp2_ksl_remove(bkt->ksl, NULL, &key);
+ if (rv != 0) {
+ return rv;
+ }
--map->size;
return 0;
}
+
return NGTCP2_ERR_INVALID_ARGUMENT;
}
void ngtcp2_map_clear(ngtcp2_map *map) {
uint32_t i;
+ ngtcp2_map_bucket *bkt;
for (i = 0; i < map->tablelen; ++i) {
- map->table[i] = NULL;
+ bkt = &map->table[i];
+ bkt->ptr = NULL;
+ if (bkt->ksl) {
+ ngtcp2_ksl_free(bkt->ksl);
+ ngtcp2_mem_free(map->mem, bkt->ksl);
+ bkt->ksl = NULL;
+ }
}
map->size = 0;
diff --git a/deps/ngtcp2/lib/ngtcp2_map.h b/deps/ngtcp2/lib/ngtcp2_map.h
index 86f23a16a7e..20afce24e9a 100644
--- a/deps/ngtcp2/lib/ngtcp2_map.h
+++ b/deps/ngtcp2/lib/ngtcp2_map.h
@@ -33,6 +33,7 @@
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
+#include "ngtcp2_ksl.h"
/* Implementation of unordered map */
@@ -43,8 +44,13 @@ typedef struct ngtcp2_map_entry {
key_type key;
} ngtcp2_map_entry;
+typedef struct ngtcp2_map_bucket {
+ ngtcp2_map_entry *ptr;
+ ngtcp2_ksl *ksl;
+} ngtcp2_map_bucket;
+
typedef struct {
- ngtcp2_map_entry **table;
+ ngtcp2_map_bucket *table;
const ngtcp2_mem *mem;
size_t size;
uint32_t tablelen;
diff --git a/deps/ngtcp2/lib/ngtcp2_path.c b/deps/ngtcp2/lib/ngtcp2_path.c
index ebda947c6d6..3f35f28ef6a 100644
--- a/deps/ngtcp2/lib/ngtcp2_path.c
+++ b/deps/ngtcp2/lib/ngtcp2_path.c
@@ -44,12 +44,16 @@ int ngtcp2_path_eq(const ngtcp2_path *a, const ngtcp2_path *b) {
ngtcp2_addr_eq(&a->remote, &b->remote);
}
-void ngtcp2_path_storage_init(ngtcp2_path_storage *ps, const void *local_addr,
+void ngtcp2_path_storage_init(ngtcp2_path_storage *ps,
+ const struct sockaddr *local_addr,
size_t local_addrlen, void *local_user_data,
- const void *remote_addr, size_t remote_addrlen,
- void *remote_user_data) {
- ngtcp2_addr_init(&ps->path.local, ps->local_addrbuf, 0, local_user_data);
- ngtcp2_addr_init(&ps->path.remote, ps->remote_addrbuf, 0, remote_user_data);
+ const struct sockaddr *remote_addr,
+ size_t remote_addrlen, void *remote_user_data) {
+ ngtcp2_addr_init(&ps->path.local, (const struct sockaddr *)&ps->local_addrbuf,
+ 0, local_user_data);
+ ngtcp2_addr_init(&ps->path.remote,
+ (const struct sockaddr *)&ps->remote_addrbuf, 0,
+ remote_user_data);
ngtcp2_addr_copy_byte(&ps->path.local, local_addr, local_addrlen);
ngtcp2_addr_copy_byte(&ps->path.remote, remote_addr, remote_addrlen);
@@ -63,6 +67,8 @@ void ngtcp2_path_storage_init2(ngtcp2_path_storage *ps,
}
void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps) {
- ngtcp2_addr_init(&ps->path.local, ps->local_addrbuf, 0, NULL);
- ngtcp2_addr_init(&ps->path.remote, ps->remote_addrbuf, 0, NULL);
+ ngtcp2_addr_init(&ps->path.local, (const struct sockaddr *)&ps->local_addrbuf,
+ 0, NULL);
+ ngtcp2_addr_init(&ps->path.remote,
+ (const struct sockaddr *)&ps->remote_addrbuf, 0, NULL);
}
diff --git a/deps/ngtcp2/lib/ngtcp2_pkt.c b/deps/ngtcp2/lib/ngtcp2_pkt.c
index a67a376d364..905af29a822 100644
--- a/deps/ngtcp2/lib/ngtcp2_pkt.c
+++ b/deps/ngtcp2/lib/ngtcp2_pkt.c
@@ -474,6 +474,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_frame(ngtcp2_frame *dest, const uint8_t *payload,
return ngtcp2_pkt_decode_stop_sending_frame(&dest->stop_sending, payload,
payloadlen);
case NGTCP2_FRAME_ACK:
+ case NGTCP2_FRAME_ACK_ECN:
return ngtcp2_pkt_decode_ack_frame(&dest->ack, payload, payloadlen);
case NGTCP2_FRAME_PATH_CHALLENGE:
return ngtcp2_pkt_decode_path_challenge_frame(&dest->path_challenge,
@@ -2066,16 +2067,12 @@ ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen,
return p - dest;
}
-static const uint8_t retry_key[] =
- "\xcc\xce\x18\x7e\xd0\x9a\x09\xd0\x57\x28\x15\x5a\x6c\xb9\x6b\xe1";
-static const uint8_t retry_nonce[] =
- "\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,
const ngtcp2_cid *scid, const ngtcp2_cid *odcid,
const uint8_t *token, size_t tokenlen,
- ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead) {
+ ngtcp2_encrypt encrypt, const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx) {
ngtcp2_pkt_hd hd;
uint8_t pseudo_retry[1500];
ngtcp2_ssize pseudo_retrylen;
@@ -2106,8 +2103,10 @@ ngtcp2_pkt_write_retry(uint8_t *dest, size_t destlen, const ngtcp2_cid *dcid,
}
/* OpenSSL does not like NULL plaintext. */
- rv = encrypt(tag, aead, (const uint8_t *)"", 0, retry_key, retry_nonce,
- sizeof(retry_nonce) - 1, pseudo_retry, (size_t)pseudo_retrylen);
+ rv = encrypt(tag, aead, aead_ctx, (const uint8_t *)"", 0,
+ (const uint8_t *)NGTCP2_RETRY_NONCE,
+ sizeof(NGTCP2_RETRY_NONCE) - 1, pseudo_retry,
+ (size_t)pseudo_retrylen);
if (rv != 0) {
return rv;
}
@@ -2160,7 +2159,8 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_retry(
int ngtcp2_pkt_verify_retry_tag(const ngtcp2_pkt_retry *retry,
const uint8_t *pkt, size_t pktlen,
ngtcp2_encrypt encrypt,
- const ngtcp2_crypto_aead *aead) {
+ const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx) {
uint8_t pseudo_retry[1500];
size_t pseudo_retrylen;
uint8_t *p = pseudo_retry;
@@ -2181,8 +2181,9 @@ int ngtcp2_pkt_verify_retry_tag(const ngtcp2_pkt_retry *retry,
pseudo_retrylen = (size_t)(p - pseudo_retry);
/* OpenSSL does not like NULL plaintext. */
- rv = encrypt(tag, aead, (const uint8_t *)"", 0, retry_key, retry_nonce,
- sizeof(retry_nonce) - 1, pseudo_retry, pseudo_retrylen);
+ rv = encrypt(tag, aead, aead_ctx, (const uint8_t *)"", 0,
+ (const uint8_t *)NGTCP2_RETRY_NONCE,
+ sizeof(NGTCP2_RETRY_NONCE) - 1, pseudo_retry, pseudo_retrylen);
if (rv != 0) {
return rv;
}
@@ -2229,7 +2230,9 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset,
size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) {
size_t n = 1 /* type */ + ngtcp2_put_varint_len(offset);
- if (left <= n) {
+ /* CRYPTO frame must contain nonzero length data. Return -1 if
+ there is no space to write crypto data. */
+ if (left <= n + 1) {
return (size_t)-1;
}
diff --git a/deps/ngtcp2/lib/ngtcp2_pkt.h b/deps/ngtcp2/lib/ngtcp2_pkt.h
index caf4152c045..7348cb9a9d0 100644
--- a/deps/ngtcp2/lib/ngtcp2_pkt.h
+++ b/deps/ngtcp2/lib/ngtcp2_pkt.h
@@ -1120,6 +1120,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_retry(
int ngtcp2_pkt_verify_retry_tag(const ngtcp2_pkt_retry *retry,
const uint8_t *pkt, size_t pktlen,
ngtcp2_encrypt encrypt,
- const ngtcp2_crypto_aead *aead);
+ const ngtcp2_crypto_aead *aead,
+ const ngtcp2_crypto_aead_ctx *aead_ctx);
#endif /* NGTCP2_PKT_H */
diff --git a/deps/ngtcp2/lib/ngtcp2_ppe.c b/deps/ngtcp2/lib/ngtcp2_ppe.c
index c1856d0fe09..e2c47fd0c5f 100644
--- a/deps/ngtcp2/lib/ngtcp2_ppe.c
+++ b/deps/ngtcp2/lib/ngtcp2_ppe.c
@@ -123,7 +123,7 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) {
ngtcp2_crypto_create_nonce(ppe->nonce, cc->ckm->iv.base, cc->ckm->iv.len,
ppe->pkt_num);
- rv = cc->encrypt(payload, &cc->aead, payload, payloadlen, cc->ckm->key.base,
+ rv = cc->encrypt(payload, &cc->aead, &cc->ckm->aead_ctx, payload, payloadlen,
ppe->nonce, cc->ckm->iv.len, buf->begin, ppe->hdlen);
if (rv != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
@@ -134,8 +134,7 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) {
/* TODO Check that we have enough space to get sample */
assert(ppe->sample_offset + NGTCP2_HP_SAMPLELEN <= ngtcp2_buf_len(buf));
- rv = cc->hp_mask(mask, &cc->hp, cc->hp_key->base,
- buf->begin + ppe->sample_offset);
+ rv = cc->hp_mask(mask, &cc->hp, &cc->hp_ctx, buf->begin + ppe->sample_offset);
if (rv != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
diff --git a/deps/ngtcp2/lib/ngtcp2_qlog.c b/deps/ngtcp2/lib/ngtcp2_qlog.c
index f0abc8dba7c..580b6a6fe0f 100644
--- a/deps/ngtcp2/lib/ngtcp2_qlog.c
+++ b/deps/ngtcp2/lib/ngtcp2_qlog.c
@@ -230,7 +230,8 @@ void ngtcp2_qlog_start(ngtcp2_qlog *qlog, const ngtcp2_cid *odcid, int server) {
p = write_event_fields(p);
p = write_events_start(p);
- qlog->write(qlog->user_data, buf, (size_t)(p - buf));
+ qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
+ (size_t)(p - buf));
}
void ngtcp2_qlog_end(ngtcp2_qlog *qlog) {
@@ -245,7 +246,8 @@ void ngtcp2_qlog_end(ngtcp2_qlog *qlog) {
p = write_trace_end(p);
*p++ = '}';
- qlog->write(qlog->user_data, buf, (size_t)(p - buf));
+ qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_FIN, buf,
+ (size_t)(p - buf));
}
static uint8_t *write_pkt_hd(uint8_t *p, const ngtcp2_pkt_hd *hd,
@@ -814,7 +816,8 @@ static void qlog_pkt_write_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
qlog->buf.last = p;
- qlog->write(qlog->user_data, qlog->buf.pos, ngtcp2_buf_len(&qlog->buf));
+ qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, qlog->buf.pos,
+ ngtcp2_buf_len(&qlog->buf));
}
void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr) {
@@ -1015,7 +1018,7 @@ 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 server,
- int local) {
+ ngtcp2_qlog_side side) {
uint8_t buf[1024];
uint8_t *p = buf;
ngtcp2_vec name, value;
@@ -1034,20 +1037,20 @@ void ngtcp2_qlog_parameters_set_transport_params(
*p++ = ',';
*p++ = '{';
p = write_pair(p, ngtcp2_vec_lit(&name, "owner"),
- local ? ngtcp2_vec_lit(&value, "local")
- : ngtcp2_vec_lit(&value, "remote"));
+ side == NGTCP2_QLOG_SIDE_LOCAL
+ ? ngtcp2_vec_lit(&value, "local")
+ : ngtcp2_vec_lit(&value, "remote"));
*p++ = ',';
p = write_pair_cid(p, ngtcp2_vec_lit(&name, "initial_source_connection_id"),
&params->initial_scid);
*p++ = ',';
- if (!server == !local) {
+ if (side == (server ? NGTCP2_QLOG_SIDE_LOCAL : NGTCP2_QLOG_SIDE_REMOTE)) {
p = write_pair_cid(
p, ngtcp2_vec_lit(&name, "original_destination_connection_id"),
&params->original_dcid);
*p++ = ',';
}
if (params->retry_scid_present) {
- assert(!server);
p = write_pair_cid(p, ngtcp2_vec_lit(&name, "retry_source_connection_id"),
&params->retry_scid);
*p++ = ',';
@@ -1126,7 +1129,8 @@ void ngtcp2_qlog_parameters_set_transport_params(
*p++ = ']';
*p++ = ',';
- qlog->write(qlog->user_data, buf, (size_t)(p - buf));
+ qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
+ (size_t)(p - buf));
}
void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog,
@@ -1181,7 +1185,8 @@ void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog,
*p++ = ']';
*p++ = ',';
- qlog->write(qlog->user_data, buf, (size_t)(p - buf));
+ qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
+ (size_t)(p - buf));
}
void ngtcp2_qlog_pkt_lost(ngtcp2_qlog *qlog, ngtcp2_rtb_entry *ent) {
@@ -1215,5 +1220,6 @@ void ngtcp2_qlog_pkt_lost(ngtcp2_qlog *qlog, ngtcp2_rtb_entry *ent) {
*p++ = ']';
*p++ = ',';
- qlog->write(qlog->user_data, buf, (size_t)(p - buf));
+ qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf,
+ (size_t)(p - buf));
}
diff --git a/deps/ngtcp2/lib/ngtcp2_qlog.h b/deps/ngtcp2/lib/ngtcp2_qlog.h
index cd967984a74..0709f92a364 100644
--- a/deps/ngtcp2/lib/ngtcp2_qlog.h
+++ b/deps/ngtcp2/lib/ngtcp2_qlog.h
@@ -40,6 +40,11 @@
qlog. */
#define NGTCP2_QLOG_BUFLEN 4096
+typedef enum ngtcp2_qlog_side {
+ NGTCP2_QLOG_SIDE_LOCAL,
+ NGTCP2_QLOG_SIDE_REMOTE,
+} ngtcp2_qlog_side;
+
typedef struct ngtcp2_qlog {
/* write is a callback function to write qlog. */
ngtcp2_qlog_write write;
@@ -116,7 +121,7 @@ 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 server,
- int local);
+ ngtcp2_qlog_side side);
/*
* ngtcp2_qlog_metrics_updated writes metrics_updated event of
diff --git a/deps/ngtcp2/lib/ngtcp2_rcvry.h b/deps/ngtcp2/lib/ngtcp2_rcvry.h
index 0ff0bc4b6ed..e392c34ebfe 100644
--- a/deps/ngtcp2/lib/ngtcp2_rcvry.h
+++ b/deps/ngtcp2/lib/ngtcp2_rcvry.h
@@ -39,6 +39,4 @@
draft-ietf-quic-recovery-17. */
#define NGTCP2_GRANULARITY NGTCP2_MILLISECONDS
-#define NGTCP2_DEFAULT_INITIAL_RTT (333 * NGTCP2_MILLISECONDS)
-
#endif /* NGTCP2_RCVRY_H */
diff --git a/deps/ngtcp2/lib/ngtcp2_ringbuf.c b/deps/ngtcp2/lib/ngtcp2_ringbuf.c
index 6f5e61a2d69..e4deab1ff76 100644
--- a/deps/ngtcp2/lib/ngtcp2_ringbuf.c
+++ b/deps/ngtcp2/lib/ngtcp2_ringbuf.c
@@ -31,6 +31,16 @@
#include "ngtcp2_macro.h"
+#if defined(_MSC_VER) && defined(_M_ARM64)
+unsigned int __popcnt(unsigned int x) {
+ unsigned int c = 0;
+ for (; x; ++c) {
+ x &= x - 1;
+ }
+ return c;
+}
+#endif
+
int ngtcp2_ringbuf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
const ngtcp2_mem *mem) {
#ifdef WIN32
@@ -101,6 +111,4 @@ void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset) {
return &rb->buf[offset * rb->size];
}
-size_t ngtcp2_ringbuf_len(ngtcp2_ringbuf *rb) { return rb->len; }
-
int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->nmemb; }
diff --git a/deps/ngtcp2/lib/ngtcp2_ringbuf.h b/deps/ngtcp2/lib/ngtcp2_ringbuf.h
index 05e9a577f19..6d546495f2a 100644
--- a/deps/ngtcp2/lib/ngtcp2_ringbuf.h
+++ b/deps/ngtcp2/lib/ngtcp2_ringbuf.h
@@ -102,7 +102,7 @@ void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len);
void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset);
/* ngtcp2_ringbuf_len returns the number of elements stored. */
-size_t ngtcp2_ringbuf_len(ngtcp2_ringbuf *rb);
+#define ngtcp2_ringbuf_len(RB) ((RB)->len)
/* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb);
diff --git a/deps/ngtcp2/lib/ngtcp2_rtb.c b/deps/ngtcp2/lib/ngtcp2_rtb.c
index e7e6762e03d..d58a6b2ea1a 100644
--- a/deps/ngtcp2/lib/ngtcp2_rtb.c
+++ b/deps/ngtcp2/lib/ngtcp2_rtb.c
@@ -84,11 +84,53 @@ int ngtcp2_frame_chain_crypto_datacnt_new(ngtcp2_frame_chain **pfrc,
return ngtcp2_frame_chain_new(pfrc, mem);
}
+int ngtcp2_frame_chain_new_token_new(ngtcp2_frame_chain **pfrc,
+ const ngtcp2_vec *token,
+ const ngtcp2_mem *mem) {
+ size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token);
+ int rv;
+ uint8_t *p;
+ ngtcp2_frame *fr;
+
+ if (token->len > avail) {
+ rv = ngtcp2_frame_chain_extralen_new(pfrc, token->len - avail, mem);
+ } else {
+ rv = ngtcp2_frame_chain_new(pfrc, mem);
+ }
+ if (rv != 0) {
+ return rv;
+ }
+
+ fr = &(*pfrc)->fr;
+ fr->type = NGTCP2_FRAME_NEW_TOKEN;
+
+ p = (uint8_t *)(*pfrc) + sizeof(ngtcp2_new_token);
+ memcpy(p, token->base, token->len);
+
+ ngtcp2_vec_init(&fr->new_token.token, p, token->len);
+
+ return 0;
+}
+
void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) {
+ ngtcp2_frame_chain_binder *binder;
+
+ if (frc == NULL) {
+ return;
+ }
+
+ binder = frc->binder;
+ if (binder && --binder->refcount == 0) {
+ ngtcp2_mem_free(mem, binder);
+ }
+
ngtcp2_mem_free(mem, frc);
}
-void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) { frc->next = NULL; }
+void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) {
+ frc->next = NULL;
+ frc->binder = NULL;
+}
void ngtcp2_frame_chain_list_del(ngtcp2_frame_chain *frc,
const ngtcp2_mem *mem) {
@@ -96,22 +138,42 @@ void ngtcp2_frame_chain_list_del(ngtcp2_frame_chain *frc,
for (; frc;) {
next = frc->next;
- ngtcp2_mem_free(mem, frc);
+ ngtcp2_frame_chain_del(frc, mem);
frc = next;
}
}
-static void frame_chain_insert(ngtcp2_frame_chain **pfrc,
- ngtcp2_frame_chain *frc) {
- ngtcp2_frame_chain **plast;
+int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder,
+ const ngtcp2_mem *mem) {
+ *pbinder = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_frame_chain_binder));
+ if (*pbinder == NULL) {
+ return NGTCP2_ERR_NOMEM;
+ }
+
+ return 0;
+}
- assert(frc);
+int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b,
+ const ngtcp2_mem *mem) {
+ ngtcp2_frame_chain_binder *binder;
+ int rv;
+
+ assert(b->binder == NULL);
+
+ if (a->binder == NULL) {
+ rv = ngtcp2_frame_chain_binder_new(&binder, mem);
+ if (rv != 0) {
+ return rv;
+ }
+
+ a->binder = binder;
+ ++a->binder->refcount;
+ }
- for (plast = &frc; *plast; plast = &(*plast)->next)
- ;
+ b->binder = a->binder;
+ ++b->binder->refcount;
- *plast = *pfrc;
- *pfrc = frc;
+ return 0;
}
int ngtcp2_rtb_entry_new(ngtcp2_rtb_entry **pent, const ngtcp2_pkt_hd *hd,
@@ -127,8 +189,10 @@ int ngtcp2_rtb_entry_new(ngtcp2_rtb_entry **pent, const ngtcp2_pkt_hd *hd,
(*pent)->hd.flags = hd->flags;
(*pent)->frc = frc;
(*pent)->ts = ts;
+ (*pent)->lost_ts = UINT64_MAX;
(*pent)->pktlen = pktlen;
(*pent)->flags = flags;
+ (*pent)->next = NULL;
return 0;
}
@@ -160,10 +224,13 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id,
rtb->mem = mem;
rtb->largest_acked_tx_pkt_num = -1;
rtb->num_ack_eliciting = 0;
+ rtb->num_retransmittable = 0;
rtb->probe_pkt_left = 0;
rtb->pktns_id = pktns_id;
rtb->cc_pkt_num = 0;
rtb->cc_bytes_in_flight = 0;
+ rtb->persistent_congestion_start_ts = UINT64_MAX;
+ rtb->num_lost_pkts = 0;
}
void ngtcp2_rtb_free(ngtcp2_rtb *rtb) {
@@ -196,15 +263,28 @@ static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) {
++rtb->num_ack_eliciting;
}
+ if (ent->flags & NGTCP2_RTB_FLAG_RETRANSMITTABLE) {
+ ++rtb->num_retransmittable;
+ }
}
static void rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
ngtcp2_conn_stat *cstat) {
+ if (ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED) {
+ return;
+ }
+
if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) {
assert(rtb->num_ack_eliciting);
--rtb->num_ack_eliciting;
}
+ if ((ent->flags & NGTCP2_RTB_FLAG_RETRANSMITTABLE) &&
+ !(ent->flags & NGTCP2_RTB_FLAG_PTO_RECLAIMED)) {
+ assert(rtb->num_retransmittable);
+ --rtb->num_retransmittable;
+ }
+
if (rtb->cc_pkt_num <= ent->hd.pkt_num) {
assert(cstat->bytes_in_flight >= ent->pktlen);
cstat->bytes_in_flight -= ent->pktlen;
@@ -214,8 +294,154 @@ static void rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
}
}
-static void rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
- ngtcp2_rtb_entry *ent) {
+/*
+ * rtb_reclaim_frame queues unacknowledged frames included in |ent|
+ * for retransmission. The re-queued frames are not deleted from
+ * |ent|. It returns the number of frames queued.
+ */
+static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns,
+ ngtcp2_rtb_entry *ent) {
+ ngtcp2_frame_chain *frc, *nfrc, **pfrc = &pktns->tx.frq;
+ ngtcp2_frame *fr;
+ ngtcp2_strm *strm;
+ ngtcp2_range gap, range;
+ size_t num_reclaimed = 0;
+ int rv;
+
+ /* PADDING only (or PADDING + ACK ) packets will have NULL
+ ent->frc. */
+ /* TODO Reconsider the order of pfrc */
+ for (frc = ent->frc; frc; frc = frc->next) {
+ fr = &frc->fr;
+ /* Check that a late ACK acknowledged this frame. */
+ if (frc->binder &&
+ (frc->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK)) {
+ continue;
+ }
+ switch (frc->fr.type) {
+ case NGTCP2_FRAME_STREAM:
+ strm = ngtcp2_conn_find_stream(conn, fr->stream.stream_id);
+ if (strm == NULL) {
+ continue;
+ }
+
+ gap = ngtcp2_strm_get_unacked_range_after(strm, fr->stream.offset);
+
+ range.begin = fr->stream.offset;
+ range.end = fr->stream.offset +
+ ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt);
+ range = ngtcp2_range_intersect(&range, &gap);
+ if (ngtcp2_range_len(&range) == 0 &&
+ (!fr->stream.fin || (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED))) {
+ continue;
+ }
+
+ rv = ngtcp2_frame_chain_stream_datacnt_new(&nfrc, fr->stream.datacnt,
+ rtb->mem);
+ if (rv != 0) {
+ return rv;
+ }
+
+ nfrc->fr = *fr;
+ ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data,
+ fr->stream.datacnt);
+
+ rv = ngtcp2_strm_streamfrq_push(strm, nfrc);
+ if (rv != 0) {
+ ngtcp2_frame_chain_del(nfrc, conn->mem);
+ return rv;
+ }
+ if (!ngtcp2_strm_is_tx_queued(strm)) {
+ strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn);
+ rv = ngtcp2_conn_tx_strmq_push(conn, strm);
+ if (rv != 0) {
+ return rv;
+ }
+ }
+
+ ++num_reclaimed;
+
+ continue;
+ case NGTCP2_FRAME_CRYPTO:
+ /* Don't resend CRYPTO frame if the whole region it contains has
+ been acknowledged */
+ gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->crypto.offset);
+
+ range.begin = fr->crypto.offset;
+ range.end = fr->crypto.offset +
+ ngtcp2_vec_len(fr->crypto.data, fr->crypto.datacnt);
+ range = ngtcp2_range_intersect(&range, &gap);
+ if (ngtcp2_range_len(&range) == 0) {
+ continue;
+ }
+
+ rv = ngtcp2_frame_chain_crypto_datacnt_new(&nfrc, fr->crypto.datacnt,
+ rtb->mem);
+ if (rv != 0) {
+ return rv;
+ }
+
+ nfrc->fr = *fr;
+ ngtcp2_vec_copy(nfrc->fr.crypto.data, fr->crypto.data,
+ fr->crypto.datacnt);
+
+ rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL,
+ &nfrc->fr.crypto.offset, nfrc);
+ if (rv != 0) {
+ assert(ngtcp2_err_is_fatal(rv));
+ ngtcp2_frame_chain_del(nfrc, conn->mem);
+ return rv;
+ }
+
+ ++num_reclaimed;
+
+ continue;
+ case NGTCP2_FRAME_NEW_TOKEN:
+ rv = ngtcp2_frame_chain_new_token_new(&nfrc, &fr->new_token.token,
+ rtb->mem);
+ if (rv != 0) {
+ return rv;
+ }
+
+ rv = ngtcp2_bind_frame_chains(frc, nfrc, rtb->mem);
+ if (rv != 0) {
+ return rv;
+ }
+
+ break;
+ default:
+ rv = ngtcp2_frame_chain_new(&nfrc, rtb->mem);
+ if (rv != 0) {
+ return rv;
+ }
+
+ nfrc->fr = *fr;
+
+ rv = ngtcp2_bind_frame_chains(frc, nfrc, rtb->mem);
+ if (rv != 0) {
+ return rv;
+ }
+
+ break;
+ }
+
+ ++num_reclaimed;
+
+ nfrc->next = *pfrc;
+ *pfrc = nfrc;
+ pfrc = &nfrc->next;
+ }
+
+ return (ngtcp2_ssize)num_reclaimed;
+}
+
+static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it,
+ ngtcp2_rtb_entry *ent, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns, ngtcp2_tstamp ts) {
+ int rv;
+ ngtcp2_ssize reclaimed;
+
ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags,
ent->ts);
@@ -224,16 +450,42 @@ static void rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
}
if (!(ent->flags & NGTCP2_RTB_FLAG_PROBE)) {
- if (ent->flags & NGTCP2_RTB_FLAG_CRYPTO_TIMEOUT_RETRANSMITTED) {
+ if (ent->flags & NGTCP2_RTB_FLAG_PTO_RECLAIMED) {
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
- "pkn=%" PRId64 " CRYPTO has already been retransmitted",
+ "pkn=%" PRId64 " has already been reclaimed on PTO",
ent->hd.pkt_num);
- } else if (ent->frc) {
- /* PADDING only (or PADDING + ACK ) packets will have NULL
- ent->frc. */
- /* TODO Reconsider the order of pfrc */
- frame_chain_insert(pfrc, ent->frc);
- ent->frc = NULL;
+ assert(!(ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED));
+ assert(UINT64_MAX == ent->lost_ts);
+
+ ent->flags |= NGTCP2_RTB_FLAG_LOST_RETRANSMITTED;
+ ent->lost_ts = ts;
+
+ ++rtb->num_lost_pkts;
+
+ ngtcp2_ksl_it_next(it);
+
+ return 0;
+ }
+
+ if (ent->frc) {
+ assert(!(ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED));
+ assert(UINT64_MAX == ent->lost_ts);
+
+ reclaimed = rtb_reclaim_frame(rtb, conn, pktns, ent);
+ if (reclaimed < 0) {
+ return (int)reclaimed;
+ }
+
+ if (reclaimed) {
+ ent->flags |= NGTCP2_RTB_FLAG_LOST_RETRANSMITTED;
+ ent->lost_ts = ts;
+
+ ++rtb->num_lost_pkts;
+
+ ngtcp2_ksl_it_next(it);
+
+ return 0;
+ }
}
} else {
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
@@ -242,15 +494,18 @@ static void rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
ent->hd.pkt_num);
}
+ rv = ngtcp2_ksl_remove(&rtb->ents, it, &ent->hd.pkt_num);
+ assert(0 == rv);
+
ngtcp2_rtb_entry_del(ent, rtb->mem);
+
+ return 0;
}
int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
ngtcp2_conn_stat *cstat) {
int rv;
- ent->next = NULL;
-
rv = ngtcp2_ksl_insert(&rtb->ents, NULL, &ent->hd.pkt_num, ent);
if (rv != 0) {
return rv;
@@ -266,10 +521,16 @@ 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_conn_stat *cstat) {
- ngtcp2_ksl_remove(&rtb->ents, it, &ent->hd.pkt_num);
+ ngtcp2_rtb_entry **pent, ngtcp2_rtb_entry *ent,
+ ngtcp2_conn_stat *cstat) {
+ int rv;
+ rv = ngtcp2_ksl_remove(&rtb->ents, it, &ent->hd.pkt_num);
+ assert(0 == rv);
rtb_on_remove(rtb, ent, cstat);
- ngtcp2_rtb_entry_del(ent, rtb->mem);
+
+ assert(ent->next == NULL);
+
+ ngtcp2_list_insert(ent, pent);
}
static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
@@ -283,23 +544,31 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
ngtcp2_crypto_level crypto_level;
for (frc = ent->frc; frc; frc = frc->next) {
+ if (frc->binder) {
+ frc->binder->flags |= NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK;
+ }
+
switch (frc->fr.type) {
case NGTCP2_FRAME_STREAM:
strm = ngtcp2_conn_find_stream(conn, frc->fr.stream.stream_id);
if (strm == NULL) {
break;
}
- prev_stream_offset =
- ngtcp2_gaptr_first_gap_offset(&strm->tx.acked_offset);
- rv = ngtcp2_gaptr_push(
- &strm->tx.acked_offset, frc->fr.stream.offset,
+
+ if (frc->fr.stream.fin) {
+ strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED;
+ }
+
+ prev_stream_offset = ngtcp2_strm_get_acked_offset(strm);
+ rv = ngtcp2_strm_ack_data(
+ strm, frc->fr.stream.offset,
ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt));
if (rv != 0) {
return rv;
}
if (conn->callbacks.acked_stream_data_offset) {
- stream_offset = ngtcp2_gaptr_first_gap_offset(&strm->tx.acked_offset);
+ stream_offset = ngtcp2_strm_get_acked_offset(strm);
datalen = stream_offset - prev_stream_offset;
if (datalen == 0 && !frc->fr.stream.fin) {
break;
@@ -319,17 +588,16 @@ static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
}
break;
case NGTCP2_FRAME_CRYPTO:
- prev_stream_offset =
- ngtcp2_gaptr_first_gap_offset(&crypto->tx.acked_offset);
- rv = ngtcp2_gaptr_push(
- &crypto->tx.acked_offset, frc->fr.crypto.offset,
+ prev_stream_offset = ngtcp2_strm_get_acked_offset(crypto);
+ rv = ngtcp2_strm_ack_data(
+ crypto, frc->fr.crypto.offset,
ngtcp2_vec_len(frc->fr.crypto.data, frc->fr.crypto.datacnt));
if (rv != 0) {
return rv;
}
if (conn->callbacks.acked_crypto_offset) {
- stream_offset = ngtcp2_gaptr_first_gap_offset(&crypto->tx.acked_offset);
+ stream_offset = ngtcp2_strm_get_acked_offset(crypto);
datalen = stream_offset - prev_stream_offset;
if (datalen == 0) {
break;
@@ -403,11 +671,11 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
int rv;
ngtcp2_ksl_it it;
ngtcp2_ssize num_acked = 0;
- int largest_pkt_acked = 0;
- int rtt_updated = 0;
- ngtcp2_tstamp largest_pkt_sent_ts = 0;
+ ngtcp2_tstamp largest_pkt_sent_ts = UINT64_MAX;
int64_t pkt_num;
ngtcp2_cc *cc = rtb->cc;
+ ngtcp2_rtb_entry *acked_ent = NULL;
+ int ack_eliciting_pkt_acked = 0;
if (conn && (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED) &&
largest_ack >= conn->pktns.crypto.tx.ckm->pkt_num) {
@@ -430,36 +698,25 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
for (; !ngtcp2_ksl_it_end(&it);) {
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_process_acked_pkt(rtb, ent, conn);
- if (rv != 0) {
- return rv;
- }
- if (largest_ack == pkt_num) {
- largest_pkt_sent_ts = ent->ts;
- largest_pkt_acked = 1;
- }
- if (!rtt_updated && largest_pkt_acked &&
- (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING)) {
- 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, cstat, ts);
- /* At this point, it is invalided because rtb->ents might be
- modified. */
- }
- rtb_remove(rtb, &it, ent, cstat);
- ++num_acked;
- continue;
+ assert(pkt_num <= largest_ack);
+
+ if (pkt_num < min_ack) {
+ break;
+ }
+
+ ent = ngtcp2_ksl_it_get(&it);
+
+ if (largest_ack == pkt_num) {
+ largest_pkt_sent_ts = ent->ts;
}
- break;
+
+ if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) {
+ ack_eliciting_pkt_acked = 1;
+ }
+
+ rtb_remove(rtb, &it, &acked_ent, ent, cstat);
+ ++num_acked;
}
for (i = 0; i < fr->num_blks;) {
@@ -477,44 +734,65 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
break;
}
ent = ngtcp2_ksl_it_get(&it);
- if (conn) {
- rv = rtb_process_acked_pkt(rtb, ent, conn);
- if (rv != 0) {
- return rv;
- }
- if (!rtt_updated && largest_pkt_acked &&
- (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING)) {
- 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, cstat, ts);
+ if (ent->flags & NGTCP2_RTB_FLAG_ACK_ELICITING) {
+ ack_eliciting_pkt_acked = 1;
}
- rtb_remove(rtb, &it, ent, cstat);
+
+ rtb_remove(rtb, &it, &acked_ent, ent, cstat);
++num_acked;
}
++i;
}
+ if (largest_pkt_sent_ts != UINT64_MAX && ack_eliciting_pkt_acked) {
+ 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);
+ }
+ }
+
ngtcp2_rst_on_ack_recv(rtb->rst, cstat);
+
+ if (conn) {
+ for (ent = acked_ent; ent; ent = acked_ent) {
+ rv = rtb_process_acked_pkt(rtb, ent, conn);
+ if (rv != 0) {
+ goto fail;
+ }
+
+ rtb_on_pkt_acked(rtb, ent, cstat, ts);
+ acked_ent = ent->next;
+ ngtcp2_rtb_entry_del(ent, rtb->mem);
+ }
+ } else {
+ /* For unit tests */
+ for (ent = acked_ent; ent; ent = acked_ent) {
+ rtb_on_pkt_acked(rtb, ent, cstat, ts);
+ acked_ent = ent->next;
+ ngtcp2_rtb_entry_del(ent, rtb->mem);
+ }
+ }
+
cc->on_ack_recv(cc, cstat, ts);
return num_acked;
+
+fail:
+ for (ent = acked_ent; ent; ent = acked_ent) {
+ acked_ent = ent->next;
+ ngtcp2_rtb_entry_del(ent, rtb->mem);
+ }
+
+ return rv;
}
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 lost_send_time, uint64_t pkt_thres) {
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 + (int64_t)pkt_thres) {
@@ -535,8 +813,7 @@ static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat,
}
/*
- * rtb_compute_pkt_loss_delay computes delay until packet is
- * considered lost in NGTCP2_MICROSECONDS resolution.
+ * rtb_compute_pkt_loss_delay computes loss delay.
*/
static ngtcp2_duration compute_pkt_loss_delay(const ngtcp2_conn_stat *cstat) {
/* 9/8 is kTimeThreshold */
@@ -545,9 +822,9 @@ static ngtcp2_duration compute_pkt_loss_delay(const ngtcp2_conn_stat *cstat) {
return ngtcp2_max(loss_delay, NGTCP2_GRANULARITY);
}
-void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
- ngtcp2_conn_stat *cstat, ngtcp2_duration pto,
- ngtcp2_tstamp ts) {
+int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat,
+ ngtcp2_duration pto, ngtcp2_tstamp ts) {
ngtcp2_rtb_entry *ent;
ngtcp2_duration loss_delay;
ngtcp2_tstamp lost_send_time;
@@ -556,7 +833,11 @@ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
int64_t last_lost_pkt_num;
ngtcp2_duration loss_window, congestion_period;
ngtcp2_cc *cc = rtb->cc;
+ int rv;
+ uint64_t pkt_thres =
+ rtb->cc_bytes_in_flight / cstat->max_udp_payload_size / 2;
+ pkt_thres = ngtcp2_max(pkt_thres, NGTCP2_PKT_THRESHOLD);
cstat->loss_time[rtb->pktns_id] = UINT64_MAX;
loss_delay = compute_pkt_loss_delay(cstat);
lost_send_time = ts - loss_delay;
@@ -565,31 +846,55 @@ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {
ent = ngtcp2_ksl_it_get(&it);
- if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, lost_send_time)) {
+ if (ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED) {
+ break;
+ }
+
+ if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, lost_send_time, pkt_thres)) {
/* All entries from ent are considered to be lost. */
latest_ts = oldest_ts = ent->ts;
last_lost_pkt_num = ent->hd.pkt_num;
+ congestion_period = pto * NGTCP2_PERSISTENT_CONGESTION_THRESHOLD;
+
for (; !ngtcp2_ksl_it_end(&it);) {
ent = ngtcp2_ksl_it_get(&it);
- ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num);
- if (last_lost_pkt_num == ent->hd.pkt_num + 1) {
+ if (last_lost_pkt_num == ent->hd.pkt_num + 1 &&
+ ent->ts >= rtb->persistent_congestion_start_ts) {
last_lost_pkt_num = ent->hd.pkt_num;
+ oldest_ts = ent->ts;
} else {
last_lost_pkt_num = -1;
}
- oldest_ts = ent->ts;
+ if ((ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED)) {
+ if (rtb->pktns_id != NGTCP2_PKTNS_ID_APP || last_lost_pkt_num == -1 ||
+ latest_ts - oldest_ts >= congestion_period) {
+ break;
+ }
+ ngtcp2_ksl_it_next(&it);
+ continue;
+ }
+
rtb_on_remove(rtb, ent, cstat);
- rtb_on_pkt_lost(rtb, pfrc, ent);
+ rv = rtb_on_pkt_lost(rtb, &it, ent, conn, pktns, ts);
+ if (rv != 0) {
+ return rv;
+ }
}
cc->congestion_event(cc, cstat, latest_ts, ts);
- if (last_lost_pkt_num != -1) {
- loss_window = latest_ts - oldest_ts;
- congestion_period = pto * NGTCP2_PERSISTENT_CONGESTION_THRESHOLD;
+ loss_window = latest_ts - oldest_ts;
+ /* Persistent congestion situation is only evaluated for app
+ * packet number space and for the packets sent after handshake
+ * is confirmed. During handshake, there is not much packets
+ * sent and also people seem to do lots of effort not to trigger
+ * persistent congestion there, then it is a lot easier to just
+ * not enable it during handshake.
+ */
+ if (rtb->pktns_id == NGTCP2_PKTNS_ID_APP && loss_window > 0) {
if (loss_window >= congestion_period) {
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
"persistent congestion loss_window=%" PRIu64
@@ -600,100 +905,218 @@ void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
}
}
- return;
+ break;
}
}
+
+ ngtcp2_rtb_remove_excessive_lost_pkt(rtb, pkt_thres);
+
+ return 0;
}
-void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
- ngtcp2_conn_stat *cstat) {
+void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
+ ngtcp2_ksl_it it = ngtcp2_ksl_end(&rtb->ents);
ngtcp2_rtb_entry *ent;
- ngtcp2_ksl_it it;
-
- it = ngtcp2_ksl_begin(&rtb->ents);
+ int rv;
- for (; !ngtcp2_ksl_it_end(&it);) {
+ for (; rtb->num_lost_pkts > n;) {
+ assert(ngtcp2_ksl_it_end(&it));
+ ngtcp2_ksl_it_prev(&it);
ent = ngtcp2_ksl_it_get(&it);
- rtb_on_remove(rtb, ent, cstat);
- ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num);
+ assert(ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED);
- rtb_on_pkt_lost(rtb, pfrc, ent);
+ ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
+ "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
+
+ --rtb->num_lost_pkts;
+ rv = ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num);
+ assert(0 == rv);
+ ngtcp2_rtb_entry_del(ent, rtb->mem);
}
}
-int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
- ngtcp2_conn_stat *cstat) {
- ngtcp2_rtb_entry *ent;
+void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
+ ngtcp2_tstamp ts) {
ngtcp2_ksl_it it;
- ngtcp2_frame_chain *nfrc;
- ngtcp2_frame_chain *frc;
- ngtcp2_ksl_it gapit;
- ngtcp2_range gap, range;
- ngtcp2_crypto *fr;
- int all_acked;
+ ngtcp2_rtb_entry *ent;
int rv;
- it = ngtcp2_ksl_begin(&rtb->ents);
+ if (ngtcp2_ksl_len(&rtb->ents) == 0) {
+ return;
+ }
- for (; !ngtcp2_ksl_it_end(&it);) {
+ it = ngtcp2_ksl_end(&rtb->ents);
+
+ for (;;) {
+ assert(ngtcp2_ksl_it_end(&it));
+
+ ngtcp2_ksl_it_prev(&it);
ent = ngtcp2_ksl_it_get(&it);
- if ((ent->flags & NGTCP2_RTB_FLAG_PROBE) ||
- !(ent->flags & NGTCP2_RTB_FLAG_CRYPTO_PKT)) {
- ngtcp2_ksl_it_next(&it);
- continue;
+ if (!(ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED) ||
+ ts - ent->lost_ts < pto) {
+ return;
}
- all_acked = 1;
+ ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
+ "removing stale lost pkn=%" PRId64, ent->hd.pkt_num);
- for (frc = ent->frc; frc; frc = frc->next) {
- assert(frc->fr.type == NGTCP2_FRAME_CRYPTO);
+ --rtb->num_lost_pkts;
+ rv = ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num);
+ assert(0 == rv);
+ ngtcp2_rtb_entry_del(ent, rtb->mem);
- fr = &frc->fr.crypto;
+ if (ngtcp2_ksl_len(&rtb->ents) == 0) {
+ return;
+ }
+ }
+}
- /* Don't resend CRYPTO frame if the whole region it contains has
- been acknowledged */
- gapit = ngtcp2_gaptr_get_first_gap_after(&rtb->crypto->tx.acked_offset,
- fr->offset);
- gap = *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit);
+ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(ngtcp2_rtb *rtb) {
+ ngtcp2_ksl_it it;
+ ngtcp2_rtb_entry *ent;
- range.begin = fr->offset;
- range.end = fr->offset + ngtcp2_vec_len(fr->data, fr->datacnt);
- range = ngtcp2_range_intersect(&range, &gap);
- if (ngtcp2_range_len(&range) == 0) {
- continue;
- }
+ if (ngtcp2_ksl_len(&rtb->ents) == 0) {
+ return UINT64_MAX;
+ }
+
+ it = ngtcp2_ksl_end(&rtb->ents);
+ ngtcp2_ksl_it_prev(&it);
+ ent = ngtcp2_ksl_it_get(&it);
+
+ if (!(ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED)) {
+ return UINT64_MAX;
+ }
+
+ return ent->lost_ts;
+}
+
+static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns,
+ ngtcp2_rtb_entry *ent) {
+ ngtcp2_frame_chain **pfrc, *frc;
+ ngtcp2_stream *sfr;
+ ngtcp2_strm *strm;
+ int rv;
+
+ ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags,
+ ent->ts);
+
+ if (rtb->qlog) {
+ ngtcp2_qlog_pkt_lost(rtb->qlog, ent);
+ }
+
+ if (ent->flags & NGTCP2_RTB_FLAG_PROBE) {
+ ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
+ "pkn=%" PRId64
+ " is a probe packet, no retransmission is necessary",
+ ent->hd.pkt_num);
+ return 0;
+ }
+
+ if (!ent->frc) {
+ /* PADDING only (or PADDING + ACK ) packets will have NULL
+ ent->frc. */
+ assert(!(ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED));
+ assert(!(ent->flags & NGTCP2_RTB_FLAG_PTO_RECLAIMED));
+ return 0;
+ }
- all_acked = 0;
+ if (ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED) {
+ --rtb->num_lost_pkts;
+ }
- if (!(ent->flags & NGTCP2_RTB_FLAG_CRYPTO_TIMEOUT_RETRANSMITTED)) {
- rv = ngtcp2_frame_chain_crypto_datacnt_new(
- &nfrc, frc->fr.crypto.datacnt, rtb->mem);
+ if (ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED) {
+ ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
+ "pkn=%" PRId64
+ " was declared lost and has already been retransmitted",
+ ent->hd.pkt_num);
+ return 0;
+ }
+
+ if (ent->flags & NGTCP2_RTB_FLAG_PTO_RECLAIMED) {
+ ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV,
+ "pkn=%" PRId64 " has already been reclaimed on PTO",
+ ent->hd.pkt_num);
+ return 0;
+ }
+
+ pfrc = &ent->frc;
+
+ for (; *pfrc;) {
+ switch ((*pfrc)->fr.type) {
+ case NGTCP2_FRAME_STREAM:
+ frc = *pfrc;
+
+ *pfrc = frc->next;
+ frc->next = NULL;
+ sfr = &frc->fr.stream;
+
+ strm = ngtcp2_conn_find_stream(conn, sfr->stream_id);
+ if (!strm) {
+ ngtcp2_frame_chain_del(frc, conn->mem);
+ break;
+ }
+ rv = ngtcp2_strm_streamfrq_push(strm, frc);
+ if (rv != 0) {
+ ngtcp2_frame_chain_del(frc, conn->mem);
+ return rv;
+ }
+ if (!ngtcp2_strm_is_tx_queued(strm)) {
+ strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn);
+ rv = ngtcp2_conn_tx_strmq_push(conn, strm);
if (rv != 0) {
return rv;
}
+ }
+ break;
+ case NGTCP2_FRAME_CRYPTO:
+ frc = *pfrc;
- nfrc->fr = frc->fr;
- ngtcp2_vec_copy(nfrc->fr.crypto.data, frc->fr.crypto.data,
- frc->fr.crypto.datacnt);
+ *pfrc = frc->next;
+ frc->next = NULL;
- frame_chain_insert(pfrc, nfrc);
+ rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL,
+ &frc->fr.crypto.offset, frc);
+ if (rv != 0) {
+ assert(ngtcp2_err_is_fatal(rv));
+ ngtcp2_frame_chain_del(frc, conn->mem);
+ return rv;
}
+ break;
+ default:
+ pfrc = &(*pfrc)->next;
}
+ }
- 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, cstat);
- ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num);
- ngtcp2_rtb_entry_del(ent, rtb->mem);
- continue;
- }
+ *pfrc = pktns->tx.frq;
+ pktns->tx.frq = ent->frc;
+ ent->frc = NULL;
+
+ return 0;
+}
+
+int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat) {
+ ngtcp2_rtb_entry *ent;
+ ngtcp2_ksl_it it;
+ int rv;
+
+ it = ngtcp2_ksl_begin(&rtb->ents);
+
+ for (; !ngtcp2_ksl_it_end(&it);) {
+ ent = ngtcp2_ksl_it_get(&it);
- ent->flags |= NGTCP2_RTB_FLAG_CRYPTO_TIMEOUT_RETRANSMITTED;
+ rtb_on_remove(rtb, ent, cstat);
+ rv = ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num);
+ assert(0 == rv);
- ngtcp2_ksl_it_next(&it);
+ rv = rtb_on_pkt_lost_resched_move(rtb, conn, pktns, ent);
+ ngtcp2_rtb_entry_del(ent, rtb->mem);
+ if (rv != 0) {
+ return rv;
+ }
}
return 0;
@@ -707,3 +1130,43 @@ 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;
}
+
+ngtcp2_ssize ngtcp2_rtb_reclaim_on_pto(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns, size_t num_pkts) {
+ ngtcp2_ksl_it it;
+ ngtcp2_rtb_entry *ent;
+ ngtcp2_ssize reclaimed;
+ size_t atmost = num_pkts;
+
+ it = ngtcp2_ksl_end(&rtb->ents);
+ for (; !ngtcp2_ksl_it_begin(&it) && num_pkts >= 1;) {
+ ngtcp2_ksl_it_prev(&it);
+ ent = ngtcp2_ksl_it_get(&it);
+
+ if ((ent->flags & (NGTCP2_RTB_FLAG_LOST_RETRANSMITTED |
+ NGTCP2_RTB_FLAG_PTO_RECLAIMED)) ||
+ !(ent->flags & NGTCP2_RTB_FLAG_RETRANSMITTABLE)) {
+ continue;
+ }
+
+ assert(ent->frc);
+
+ reclaimed = rtb_reclaim_frame(rtb, conn, pktns, ent);
+ if (reclaimed < 0) {
+ return reclaimed;
+ }
+
+ /* Mark reclaimed even if reclaimed == 0 so that we can skip it in
+ the next run. */
+ ent->flags |= NGTCP2_RTB_FLAG_PTO_RECLAIMED;
+
+ assert(rtb->num_retransmittable);
+ --rtb->num_retransmittable;
+
+ if (reclaimed) {
+ --num_pkts;
+ }
+ }
+
+ return (ngtcp2_ssize)(atmost - num_pkts);
+}
diff --git a/deps/ngtcp2/lib/ngtcp2_rtb.h b/deps/ngtcp2/lib/ngtcp2_rtb.h
index 6dac9b6357e..0d0b738f396 100644
--- a/deps/ngtcp2/lib/ngtcp2_rtb.h
+++ b/deps/ngtcp2/lib/ngtcp2_rtb.h
@@ -38,6 +38,8 @@
struct ngtcp2_conn;
typedef struct ngtcp2_conn ngtcp2_conn;
+typedef struct ngtcp2_pktns ngtcp2_pktns;
+
struct ngtcp2_frame_chain;
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
@@ -53,11 +55,47 @@ typedef struct ngtcp2_strm ngtcp2_strm;
struct ngtcp2_rst;
typedef struct ngtcp2_rst ngtcp2_rst;
+typedef enum ngtcp2_frame_chain_binder_flag {
+ NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE = 0x00,
+ /* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information
+ which a frame carries has been acknowledged. */
+ NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK = 0x01,
+} ngtcp2_frame_chain_binder_flag;
+
+/*
+ * ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to
+ * share the acknowledgement state. In general, all
+ * ngtcp2_frame_chains bound to the same binder must have the same
+ * information.
+ */
+typedef struct ngtcp2_frame_chain_binder {
+ size_t refcount;
+ uint32_t flags;
+} ngtcp2_frame_chain_binder;
+
+int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder,
+ const ngtcp2_mem *mem);
+
+/*
+ * ngtcp2_bind_frame_chains binds two frame chains |a| and |b| using
+ * new or existing ngtcp2_frame_chain_binder. |a| might have non-NULL
+ * a->binder. |b| must not have non-NULL b->binder.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ * Out of memory
+ */
+int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b,
+ const ngtcp2_mem *mem);
+
/*
* ngtcp2_frame_chain chains frames in a single packet.
*/
struct ngtcp2_frame_chain {
ngtcp2_frame_chain *next;
+ ngtcp2_frame_chain_binder *binder;
ngtcp2_frame fr;
};
@@ -111,6 +149,10 @@ int ngtcp2_frame_chain_crypto_datacnt_new(ngtcp2_frame_chain **pfrc,
size_t datacnt,
const ngtcp2_mem *mem);
+int ngtcp2_frame_chain_new_token_new(ngtcp2_frame_chain **pfrc,
+ const ngtcp2_vec *token,
+ const ngtcp2_mem *mem);
+
/*
* ngtcp2_frame_chain_del deallocates |frc|. It also deallocates the
* memory pointed by |frc|.
@@ -134,15 +176,23 @@ typedef enum {
/* NGTCP2_RTB_FLAG_PROBE indicates that the entry includes a probe
packet. */
NGTCP2_RTB_FLAG_PROBE = 0x01,
- /* NGTCP2_RTB_FLAG_CRYPTO_PKT indicates that the entry includes
- handshake CRYPTO frame. */
- NGTCP2_RTB_FLAG_CRYPTO_PKT = 0x02,
+ /* NGTCP2_RTB_FLAG_RETRANSMITTABLE indicates that the entry includes
+ a frame which must be retransmitted until it is acknowledged. In
+ most cases, this flag is used along with
+ NGTCP2_RTB_FLAG_ACK_ELICITING. We have these 2 flags because
+ NGTCP2_RTB_FLAG_RETRANSMITTABLE triggers PTO, but just
+ NGTCP2_RTB_FLAG_ACK_ELICITING does not. */
+ NGTCP2_RTB_FLAG_RETRANSMITTABLE = 0x02,
/* NGTCP2_RTB_FLAG_ACK_ELICITING indicates that the entry elicits
acknowledgement. */
NGTCP2_RTB_FLAG_ACK_ELICITING = 0x04,
- /* NGTCP2_RTB_FLAG_CRYPTO_TIMEOUT_RETRANSMITTED indicates that the
- CRYPTO frames have been retransmitted. */
- NGTCP2_RTB_FLAG_CRYPTO_TIMEOUT_RETRANSMITTED = 0x08,
+ /* NGTCP2_RTB_FLAG_PTO_RECLAIMED indicates that the packet has been
+ reclaimed on PTO. It is not marked lost yet and still consumes
+ congestion window. */
+ NGTCP2_RTB_FLAG_PTO_RECLAIMED = 0x08,
+ /* NGTCP2_RTB_FLAG_LOST_RETRANSMITTED indicates that the entry has
+ been marked lost and scheduled to retransmit. */
+ NGTCP2_RTB_FLAG_LOST_RETRANSMITTED = 0x10,
} ngtcp2_rtb_flag;
struct ngtcp2_rtb_entry;
@@ -164,6 +214,8 @@ struct ngtcp2_rtb_entry {
/* ts is the time point when a packet included in this entry is sent
to a peer. */
ngtcp2_tstamp ts;
+ /* lost_ts is the time when this entry is marked lost. */
+ ngtcp2_tstamp lost_ts;
/* pktlen is the length of QUIC packet */
size_t pktlen;
struct {
@@ -217,6 +269,9 @@ typedef struct {
int64_t largest_acked_tx_pkt_num;
/* num_ack_eliciting is the number of ACK eliciting entries. */
size_t num_ack_eliciting;
+ /* num_retransmittable is the number of packets which contain frames
+ that must be retransmitted on loss. */
+ size_t num_retransmittable;
/* probe_pkt_left is the number of probe packet to send */
size_t probe_pkt_left;
/* pktns_id is the identifier of packet number space. */
@@ -228,6 +283,13 @@ typedef struct {
contributed to ngtcp2_conn_stat.bytes_in_flight. It only
includes the bytes after congestion state is reset. */
uint64_t cc_bytes_in_flight;
+ /* persistent_congestion_start_ts is the time when persistent
+ congestion evaluation is started. It happens roughly after
+ handshake is confirmed. */
+ ngtcp2_tstamp persistent_congestion_start_ts;
+ /* num_lost_pkts is the number entries in ents which has
+ NGTCP2_RTB_FLAG_LOST_RETRANSMITTED flag set. */
+ size_t num_lost_pkts;
} ngtcp2_rtb;
/*
@@ -286,31 +348,30 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
* some frames might be prepended to |*pfrc| and the caller should
* handle them. |pto| is PTO.
*/
-void ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
- ngtcp2_conn_stat *cstat, ngtcp2_duration pto,
- ngtcp2_tstamp ts);
+int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat,
+ ngtcp2_duration pto, ngtcp2_tstamp ts);
/*
- * ngtcp2_rtb_remove_all removes all packets from |rtb| and prepends
- * all frames to |*pfrc|. Even when this function fails, some frames
- * might be prepended to |*pfrc| and the caller should handle them.
+ * ngtcp2_rtb_remove_expired_lost_pkt removes expired lost packet.
*/
-void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
- ngtcp2_conn_stat *cstat);
+void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
+ ngtcp2_tstamp ts);
/*
- * ngtcp2_rtb_on_crypto_timeout copies all unacknowledged CRYPTO
- * frames and links them to |*pfrc|. The affected ngtcp2_rtb_entry
- * will have NGTCP2_RTB_FLAG_CRYPTO_TIMEOUT_RETRANSMITTED set.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_NOMEM
- * Out of memory
+ * ngtcp2_rtb_lost_pkt_ts returns the earliest time when the still
+ * retained packet was lost. It returns UINT64_MAX if no such packet
+ * exists.
+ */
+ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(ngtcp2_rtb *rtb);
+
+/*
+ * ngtcp2_rtb_remove_all removes all packets from |rtb| and prepends
+ * all frames to |*pfrc|. Even when this function fails, some frames
+ * might be prepended to |*pfrc| and the caller should handle them.
*/
-int ngtcp2_rtb_on_crypto_timeout(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
- ngtcp2_conn_stat *cstat);
+int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat);
/*
* ngtcp2_rtb_empty returns nonzero if |rtb| have no entry.
@@ -324,4 +385,24 @@ int ngtcp2_rtb_empty(ngtcp2_rtb *rtb);
*/
void ngtcp2_rtb_reset_cc_state(ngtcp2_rtb *rtb, int64_t cc_pkt_num);
+/*
+ * ngtcp2_rtb_remove_expired_lost_pkt ensures that the number of lost
+ * packets at most |n|.
+ */
+void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n);
+
+/*
+ * ngtcp2_rtb_reclaim_on_pto reclaims up to |num_pkts| packets which
+ * are in-flight and not marked lost to send them in PTO probe. The
+ * reclaimed frames are chained to |*pfrc|.
+ *
+ * This function returns the number of packets reclaimed if it
+ * succeeds, or one of the following negative error codes:
+ *
+ * NGTCP2_ERR_NOMEM
+ * Out of memory
+ */
+ngtcp2_ssize ngtcp2_rtb_reclaim_on_pto(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
+ ngtcp2_pktns *pktns, size_t num_pkts);
+
#endif /* NGTCP2_RTB_H */
diff --git a/deps/ngtcp2/lib/ngtcp2_strm.c b/deps/ngtcp2/lib/ngtcp2_strm.c
index 6c02e8a2274..6fb73dc0727 100644
--- a/deps/ngtcp2/lib/ngtcp2_strm.c
+++ b/deps/ngtcp2/lib/ngtcp2_strm.c
@@ -38,11 +38,14 @@ static int offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
int ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags,
uint64_t max_rx_offset, uint64_t max_tx_offset,
void *stream_user_data, const ngtcp2_mem *mem) {
- int rv;
-
strm->cycle = 0;
+ strm->tx.acked_offset = NULL;
+ strm->tx.cont_acked_offset = 0;
+ strm->tx.streamfrq = NULL;
strm->tx.offset = 0;
strm->tx.max_offset = max_tx_offset;
+ strm->rx.rob = NULL;
+ strm->rx.cont_offset = 0;
strm->rx.last_offset = 0;
strm->stream_id = stream_id;
strm->flags = flags;
@@ -54,29 +57,7 @@ int ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags,
strm->mem = mem;
strm->app_error_code = 0;
- rv = ngtcp2_gaptr_init(&strm->tx.acked_offset, mem);
- if (rv != 0) {
- goto fail_gaptr_init;
- }
-
- rv = ngtcp2_rob_init(&strm->rx.rob, 8 * 1024, mem);
- if (rv != 0) {
- goto fail_rob_init;
- }
-
- rv = ngtcp2_ksl_init(&strm->tx.streamfrq, offset_less, sizeof(uint64_t), mem);
- if (rv != 0) {
- goto fail_tx_streamfrq_init;
- }
-
return 0;
-
-fail_tx_streamfrq_init:
- ngtcp2_rob_free(&strm->rx.rob);
-fail_rob_init:
- ngtcp2_gaptr_free(&strm->tx.acked_offset);
-fail_gaptr_init:
- return rv;
}
void ngtcp2_strm_free(ngtcp2_strm *strm) {
@@ -86,37 +67,268 @@ void ngtcp2_strm_free(ngtcp2_strm *strm) {
return;
}
- for (it = ngtcp2_ksl_begin(&strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
- ngtcp2_ksl_it_next(&it)) {
- ngtcp2_frame_chain_del(ngtcp2_ksl_it_get(&it), strm->mem);
+ if (strm->tx.streamfrq) {
+ for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
+ ngtcp2_ksl_it_next(&it)) {
+ ngtcp2_frame_chain_del(ngtcp2_ksl_it_get(&it), strm->mem);
+ }
+
+ ngtcp2_ksl_free(strm->tx.streamfrq);
+ ngtcp2_mem_free(strm->mem, strm->tx.streamfrq);
+ }
+
+ ngtcp2_rob_free(strm->rx.rob);
+ ngtcp2_mem_free(strm->mem, strm->rx.rob);
+ ngtcp2_gaptr_free(strm->tx.acked_offset);
+ ngtcp2_mem_free(strm->mem, strm->tx.acked_offset);
+}
+
+static int strm_rob_init(ngtcp2_strm *strm) {
+ int rv;
+ ngtcp2_rob *rob = ngtcp2_mem_malloc(strm->mem, sizeof(*rob));
+
+ if (rob == NULL) {
+ return NGTCP2_ERR_NOMEM;
}
- ngtcp2_ksl_free(&strm->tx.streamfrq);
- ngtcp2_rob_free(&strm->rx.rob);
- ngtcp2_gaptr_free(&strm->tx.acked_offset);
+ rv = ngtcp2_rob_init(rob, 8 * 1024, strm->mem);
+ if (rv != 0) {
+ ngtcp2_mem_free(strm->mem, rob);
+ return rv;
+ }
+
+ strm->rx.rob = rob;
+
+ return 0;
}
uint64_t ngtcp2_strm_rx_offset(ngtcp2_strm *strm) {
- return ngtcp2_rob_first_gap_offset(&strm->rx.rob);
+ if (strm->rx.rob == NULL) {
+ return strm->rx.cont_offset;
+ }
+ return ngtcp2_rob_first_gap_offset(strm->rx.rob);
}
int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
size_t datalen, uint64_t offset) {
- return ngtcp2_rob_push(&strm->rx.rob, offset, data, datalen);
+ int rv;
+
+ if (strm->rx.rob == NULL) {
+ rv = strm_rob_init(strm);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (strm->rx.cont_offset) {
+ rv = ngtcp2_rob_remove_prefix(strm->rx.rob, strm->rx.cont_offset);
+ if (rv != 0) {
+ return rv;
+ }
+ }
+ }
+
+ return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
+}
+
+int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) {
+ if (strm->rx.rob == NULL) {
+ strm->rx.cont_offset = offset;
+ return 0;
+ }
+
+ return ngtcp2_rob_remove_prefix(strm->rx.rob, offset);
}
void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags) {
strm->flags |= flags & NGTCP2_STRM_FLAG_SHUT_RDWR;
}
+static int strm_streamfrq_init(ngtcp2_strm *strm) {
+ int rv;
+ ngtcp2_ksl *streamfrq = ngtcp2_mem_malloc(strm->mem, sizeof(*streamfrq));
+ if (streamfrq == NULL) {
+ return NGTCP2_ERR_NOMEM;
+ }
+
+ rv = ngtcp2_ksl_init(streamfrq, offset_less, sizeof(uint64_t), strm->mem);
+ if (rv != 0) {
+ ngtcp2_mem_free(strm->mem, streamfrq);
+ return rv;
+ }
+
+ strm->tx.streamfrq = streamfrq;
+
+ return 0;
+}
+
int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
+ int rv;
+
assert(frc->fr.type == NGTCP2_FRAME_STREAM);
assert(frc->next == NULL);
- return ngtcp2_ksl_insert(&strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
+ if (strm->tx.streamfrq == NULL) {
+ rv = strm_streamfrq_init(strm);
+ if (rv != 0) {
+ return rv;
+ }
+ }
+
+ return ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
frc);
}
+static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm,
+ ngtcp2_frame_chain **pfrc) {
+ ngtcp2_frame_chain *frc, *nfrc;
+ ngtcp2_stream *fr, *nfr;
+ uint64_t offset, end_offset;
+ size_t idx, end_idx;
+ uint64_t base_offset, end_base_offset;
+ ngtcp2_range gap;
+ ngtcp2_vec *v;
+ int rv;
+ ngtcp2_ksl_it it;
+
+ *pfrc = NULL;
+
+ assert(strm->tx.streamfrq);
+ assert(ngtcp2_ksl_len(strm->tx.streamfrq));
+
+ for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);) {
+ frc = ngtcp2_ksl_it_get(&it);
+ fr = &frc->fr.stream;
+
+ ngtcp2_ksl_remove(strm->tx.streamfrq, &it, &fr->offset);
+
+ idx = 0;
+ offset = fr->offset;
+ base_offset = 0;
+
+ gap = ngtcp2_strm_get_unacked_range_after(strm, offset);
+ if (gap.begin < offset) {
+ gap.begin = offset;
+ }
+
+ for (; idx < fr->datacnt && offset < gap.begin; ++idx) {
+ v = &fr->data[idx];
+ if (offset + v->len > gap.begin) {
+ base_offset = gap.begin - offset;
+ break;
+ }
+
+ offset += v->len;
+ }
+
+ if (idx == fr->datacnt) {
+ if (fr->fin) {
+ if (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED) {
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ assert(ngtcp2_ksl_len(strm->tx.streamfrq) == 0);
+ return 0;
+ }
+
+ fr->offset = fr->offset + ngtcp2_vec_len(fr->data, fr->datacnt);
+ fr->datacnt = 0;
+
+ *pfrc = frc;
+
+ return 0;
+ }
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ continue;
+ }
+
+ assert(gap.begin == offset + base_offset);
+
+ end_idx = idx;
+ end_offset = offset;
+ end_base_offset = 0;
+
+ for (; end_idx < fr->datacnt; ++end_idx) {
+ v = &fr->data[end_idx];
+ if (end_offset + v->len > gap.end) {
+ end_base_offset = gap.end - end_offset;
+ break;
+ }
+
+ end_offset += v->len;
+ }
+
+ if (fr->offset == offset && base_offset == 0 && fr->datacnt == end_idx) {
+ *pfrc = frc;
+ return 0;
+ }
+
+ if (fr->datacnt == end_idx) {
+ memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx));
+
+ assert(fr->data[0].len > base_offset);
+
+ fr->offset = offset + base_offset;
+ fr->datacnt = end_idx - idx;
+ fr->data[0].base += base_offset;
+ fr->data[0].len -= (size_t)base_offset;
+
+ *pfrc = frc;
+ return 0;
+ }
+
+ rv = ngtcp2_frame_chain_stream_datacnt_new(&nfrc, fr->datacnt - end_idx,
+ strm->mem);
+ if (rv != 0) {
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ return rv;
+ }
+
+ nfr = &nfrc->fr.stream;
+ memcpy(nfr->data, fr->data + end_idx,
+ sizeof(nfr->data[0]) * (fr->datacnt - end_idx));
+
+ assert(nfr->data[0].len > end_base_offset);
+
+ nfr->type = NGTCP2_FRAME_STREAM;
+ nfr->flags = 0;
+ nfr->fin = fr->fin;
+ nfr->stream_id = fr->stream_id;
+ nfr->offset = end_offset + end_base_offset;
+ nfr->datacnt = fr->datacnt - end_idx;
+ nfr->data[0].base += end_base_offset;
+ nfr->data[0].len -= (size_t)end_base_offset;
+
+ rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
+ if (rv != 0) {
+ assert(ngtcp2_err_is_fatal(rv));
+ ngtcp2_frame_chain_del(nfrc, strm->mem);
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ return rv;
+ }
+
+ if (end_base_offset) {
+ ++end_idx;
+ }
+
+ memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx));
+
+ assert(fr->data[0].len > base_offset);
+
+ fr->fin = 0;
+ fr->offset = offset + base_offset;
+ fr->datacnt = end_idx - idx;
+ if (end_base_offset) {
+ assert(fr->data[fr->datacnt - 1].len > end_base_offset);
+ fr->data[fr->datacnt - 1].len = (size_t)end_base_offset;
+ }
+ fr->data[0].base += base_offset;
+ fr->data[0].len -= (size_t)base_offset;
+
+ *pfrc = frc;
+ return 0;
+ }
+
+ return 0;
+}
+
int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
size_t left) {
ngtcp2_stream *fr, *nfr;
@@ -127,30 +339,39 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
ngtcp2_vec a[NGTCP2_MAX_STREAM_DATACNT];
ngtcp2_vec b[NGTCP2_MAX_STREAM_DATACNT];
size_t acnt, bcnt;
- ngtcp2_ksl_it it;
- uint64_t old_offset;
+ uint64_t unacked_offset;
- if (ngtcp2_ksl_len(&strm->tx.streamfrq) == 0) {
+ if (strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0) {
*pfrc = NULL;
return 0;
}
- it = ngtcp2_ksl_begin(&strm->tx.streamfrq);
- frc = ngtcp2_ksl_it_get(&it);
- fr = &frc->fr.stream;
+ rv = strm_streamfrq_unacked_pop(strm, &frc);
+ if (rv != 0) {
+ return rv;
+ }
+ if (frc == NULL) {
+ *pfrc = NULL;
+ return 0;
+ }
+ fr = &frc->fr.stream;
datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
if (left == 0) {
/* datalen could be zero if 0 length STREAM has been sent */
- if (datalen || ngtcp2_ksl_len(&strm->tx.streamfrq) > 1) {
+ if (datalen || ngtcp2_ksl_len(strm->tx.streamfrq) > 1) {
+ rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc);
+ if (rv != 0) {
+ assert(ngtcp2_err_is_fatal(rv));
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ return rv;
+ }
*pfrc = NULL;
return 0;
}
}
- ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, &fr->offset);
-
if (datalen > left) {
ngtcp2_vec_copy(a, fr->data, fr->datacnt);
acnt = fr->datacnt;
@@ -177,7 +398,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, &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);
@@ -210,19 +431,27 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
ngtcp2_vec_copy(a, fr->data, fr->datacnt);
acnt = fr->datacnt;
- for (; left && ngtcp2_ksl_len(&strm->tx.streamfrq);) {
- it = ngtcp2_ksl_begin(&strm->tx.streamfrq);
- nfrc = ngtcp2_ksl_it_get(&it);
- nfr = &nfrc->fr.stream;
+ for (; left && ngtcp2_ksl_len(strm->tx.streamfrq);) {
+ unacked_offset = ngtcp2_strm_streamfrq_unacked_offset(strm);
+ if (unacked_offset != fr->offset + datalen) {
+ assert(fr->offset + datalen < unacked_offset);
+ break;
+ }
- if (nfr->offset != fr->offset + datalen) {
- assert(fr->offset + datalen < nfr->offset);
+ rv = strm_streamfrq_unacked_pop(strm, &nfrc);
+ if (rv != 0) {
+ assert(ngtcp2_err_is_fatal(rv));
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ return rv;
+ }
+ if (nfrc == NULL) {
break;
}
+ nfr = &nfrc->fr.stream;
+
if (nfr->fin && nfr->datacnt == 0) {
fr->fin = 1;
- ngtcp2_ksl_remove(&strm->tx.streamfrq, NULL, &nfr->offset);
ngtcp2_frame_chain_del(nfrc, strm->mem);
break;
}
@@ -230,6 +459,13 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
nmerged = ngtcp2_vec_merge(a, &acnt, nfr->data, &nfr->datacnt, left,
NGTCP2_MAX_STREAM_DATACNT);
if (nmerged == 0) {
+ 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);
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ return rv;
+ }
break;
}
@@ -238,15 +474,18 @@ 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, &nfr->offset);
ngtcp2_frame_chain_del(nfrc, strm->mem);
continue;
}
- old_offset = nfr->offset;
nfr->offset += nmerged;
- ngtcp2_ksl_update_key(&strm->tx.streamfrq, &old_offset, &nfr->offset);
+ rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
+ if (rv != 0) {
+ ngtcp2_frame_chain_del(nfrc, strm->mem);
+ ngtcp2_frame_chain_del(frc, strm->mem);
+ return rv;
+ }
break;
}
@@ -280,29 +519,68 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
return 0;
}
+uint64_t ngtcp2_strm_streamfrq_unacked_offset(ngtcp2_strm *strm) {
+ ngtcp2_frame_chain *frc;
+ ngtcp2_stream *fr;
+ ngtcp2_range gap;
+ ngtcp2_ksl_it it;
+ size_t datalen;
+
+ assert(strm->tx.streamfrq);
+ assert(ngtcp2_ksl_len(strm->tx.streamfrq));
+
+ for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
+ ngtcp2_ksl_it_next(&it)) {
+ frc = ngtcp2_ksl_it_get(&it);
+ fr = &frc->fr.stream;
+
+ gap = ngtcp2_strm_get_unacked_range_after(strm, fr->offset);
+
+ datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
+
+ if (gap.begin <= fr->offset) {
+ return fr->offset;
+ }
+ if (gap.begin < fr->offset + datalen) {
+ return gap.begin;
+ }
+ if (fr->offset + datalen == gap.begin && fr->fin &&
+ !(strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED)) {
+ return fr->offset + datalen;
+ }
+ }
+
+ return (uint64_t)-1;
+}
+
ngtcp2_frame_chain *ngtcp2_strm_streamfrq_top(ngtcp2_strm *strm) {
ngtcp2_ksl_it it;
- assert(ngtcp2_ksl_len(&strm->tx.streamfrq));
+ assert(strm->tx.streamfrq);
+ assert(ngtcp2_ksl_len(strm->tx.streamfrq));
- it = ngtcp2_ksl_begin(&strm->tx.streamfrq);
+ it = ngtcp2_ksl_begin(strm->tx.streamfrq);
return ngtcp2_ksl_it_get(&it);
}
int ngtcp2_strm_streamfrq_empty(ngtcp2_strm *strm) {
- return ngtcp2_ksl_len(&strm->tx.streamfrq) == 0;
+ return strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0;
}
void ngtcp2_strm_streamfrq_clear(ngtcp2_strm *strm) {
ngtcp2_frame_chain *frc;
ngtcp2_ksl_it it;
- for (it = ngtcp2_ksl_begin(&strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
+ if (strm->tx.streamfrq == NULL) {
+ return;
+ }
+
+ for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
ngtcp2_ksl_it_next(&it)) {
frc = ngtcp2_ksl_it_get(&it);
ngtcp2_frame_chain_del(frc, strm->mem);
}
- ngtcp2_ksl_clear(&strm->tx.streamfrq);
+ ngtcp2_ksl_clear(strm->tx.streamfrq);
}
int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm) {
@@ -310,6 +588,77 @@ int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm) {
}
int ngtcp2_strm_is_all_tx_data_acked(ngtcp2_strm *strm) {
- return ngtcp2_gaptr_first_gap_offset(&strm->tx.acked_offset) ==
+ if (strm->tx.acked_offset == NULL) {
+ return strm->tx.cont_acked_offset == strm->tx.offset;
+ }
+
+ return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset) ==
strm->tx.offset;
}
+
+ngtcp2_range ngtcp2_strm_get_unacked_range_after(ngtcp2_strm *strm,
+ uint64_t offset) {
+ ngtcp2_ksl_it gapit;
+ ngtcp2_range gap;
+
+ if (strm->tx.acked_offset == NULL) {
+ gap.begin = strm->tx.cont_acked_offset;
+ gap.end = UINT64_MAX;
+ return gap;
+ }
+
+ gapit = ngtcp2_gaptr_get_first_gap_after(strm->tx.acked_offset, offset);
+ return *(ngtcp2_range *)ngtcp2_ksl_it_key(&gapit);
+}
+
+uint64_t ngtcp2_strm_get_acked_offset(ngtcp2_strm *strm) {
+ if (strm->tx.acked_offset == NULL) {
+ return strm->tx.cont_acked_offset;
+ }
+
+ return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset);
+}
+
+static int strm_acked_offset_init(ngtcp2_strm *strm) {
+ int rv;
+ ngtcp2_gaptr *acked_offset =
+ ngtcp2_mem_malloc(strm->mem, sizeof(*acked_offset));
+
+ if (acked_offset == NULL) {
+ return NGTCP2_ERR_NOMEM;
+ }
+
+ rv = ngtcp2_gaptr_init(acked_offset, strm->mem);
+ if (rv != 0) {
+ ngtcp2_mem_free(strm->mem, acked_offset);
+ return rv;
+ }
+
+ strm->tx.acked_offset = acked_offset;
+
+ return 0;
+}
+
+int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len) {
+ int rv;
+
+ if (strm->tx.acked_offset == NULL) {
+ if (strm->tx.cont_acked_offset == offset) {
+ strm->tx.cont_acked_offset += len;
+ return 0;
+ }
+
+ rv = strm_acked_offset_init(strm);
+ if (rv != 0) {
+ return rv;
+ }
+
+ rv =
+ ngtcp2_gaptr_push(strm->tx.acked_offset, 0, strm->tx.cont_acked_offset);
+ if (rv != 0) {
+ return rv;
+ }
+ }
+
+ return ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
+}
diff --git a/deps/ngtcp2/lib/ngtcp2_strm.h b/deps/ngtcp2/lib/ngtcp2_strm.h
index 67d49e519e0..7da8437e668 100644
--- a/deps/ngtcp2/lib/ngtcp2_strm.h
+++ b/deps/ngtcp2/lib/ngtcp2_strm.h
@@ -64,6 +64,9 @@ typedef enum {
/* NGTCP2_STRM_FLAG_RST_ACKED indicates that the outgoing RST_STREAM
is acknowledged by peer. */
NGTCP2_STRM_FLAG_RST_ACKED = 0x20,
+ /* NGTCP2_STRM_FLAG_FIN_ACKED indicates that a STREAM with FIN bit
+ set is acknowledged by a remote endpoint. */
+ NGTCP2_STRM_FLAG_FIN_ACKED = 0x40,
} ngtcp2_strm_flags;
struct ngtcp2_strm;
@@ -76,12 +79,17 @@ struct ngtcp2_strm {
struct {
/* acked_offset tracks acknowledged outgoing data. */
- ngtcp2_gaptr acked_offset;
+ ngtcp2_gaptr *acked_offset;
+ /* cont_acked_offset is the offset that all data up to this offset
+ is acknowledged by a remote endpoint. It is used until the
+ remote endpoint acknowledges data in out-of-order. After that,
+ acked_offset is used instead. */
+ uint64_t cont_acked_offset;
/* streamfrq contains STREAM frame for retransmission. The flow
control credits have been paid when they are transmitted first
time. There are no restriction regarding flow control for
retransmission. */
- ngtcp2_ksl streamfrq;
+ ngtcp2_ksl *streamfrq;
/* offset is the next offset of outgoing data. In other words, it
is the number of bytes sent in this stream without
duplication. */
@@ -95,7 +103,11 @@ struct ngtcp2_strm {
/* rob is the reorder buffer for incoming stream data. The data
received in out of order is buffered and sorted by its offset
in this object. */
- ngtcp2_rob rob;
+ ngtcp2_rob *rob;
+ /* cont_offset is the largest offset of consecutive data. It is
+ used until the endpoint receives out-of-order data. After
+ that, rob is used to track the offset and data. */
+ uint64_t cont_offset;
/* last_offset is the largest offset of stream data received for
this stream. */
uint64_t last_offset;
@@ -156,6 +168,15 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
size_t datalen, uint64_t offset);
/*
+ * ngtcp2_strm_update_rx_offset tells that data up to offset bytes are
+ * received in order.
+ *
+ * NGTCP2_ERR_NOMEM
+ * Out of memory
+ */
+int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset);
+
+/*
* ngtcp2_strm_shutdown shutdowns |strm|. |flags| should be
* NGTCP2_STRM_FLAG_SHUT_RD, and/or NGTCP2_STRM_FLAG_SHUT_WR.
*/
@@ -190,6 +211,12 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
size_t left);
/*
+ * ngtcp2_strm_streamfrq_unacked_offset returns the smallest offset of
+ * unacknowledged stream data held in strm->tx.streamfrq.
+ */
+uint64_t ngtcp2_strm_streamfrq_unacked_offset(ngtcp2_strm *strm);
+
+/*
* ngtcp2_strm_streamfrq_top returns the first ngtcp2_frame_chain.
* The queue must not be empty.
*/
@@ -216,4 +243,24 @@ int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm);
*/
int ngtcp2_strm_is_all_tx_data_acked(ngtcp2_strm *strm);
+/*
+ * ngtcp2_strm_get_unacked_range_after returns the range that is not
+ * acknowledged yet and intersects or comes after |offset|.
+ */
+ngtcp2_range ngtcp2_strm_get_unacked_range_after(ngtcp2_strm *strm,
+ uint64_t offset);
+
+/*
+ * ngtcp2_strm_get_acked_offset returns offset, that is the data up to
+ * this offset have been acknowledged by a remote endpoint. It
+ * returns 0 if no data is acknowledged.
+ */
+uint64_t ngtcp2_strm_get_acked_offset(ngtcp2_strm *strm);
+
+/*
+ * ngtcp2_strm_ack_data tells |strm| that the data [offset,
+ * offset+len) is acknowledged by a remote endpoint.
+ */
+int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len);
+
#endif /* NGTCP2_STRM_H */