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>
This commit is contained in:
James M Snell 2020-08-12 10:56:00 -07:00
parent bc8a4df1bb
commit c788be2e6e
37 changed files with 3516 additions and 1322 deletions

View File

@ -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

View File

@ -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_CIPHER_CTX_free(actx);
return rv;
}
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
const uint8_t *hp_key, 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;
int len;
actx = EVP_CIPHER_CTX_new();
if (actx == NULL) {
!EVP_DecryptFinal_ex(actx, dest + ciphertextlen, &len))) {
return -1;
}
if (!EVP_EncryptInit_ex(actx, cipher, NULL, hp_key, sample) ||
return 0;
}
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
const ngtcp2_crypto_cipher_ctx *hp_ctx,
const uint8_t *sample) {
static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
int len;
(void)hp;
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

View File

@ -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;
}
if (crypto_set_local_transport_params(conn, tls) != 0) {
goto fail;
}
}
rv = ngtcp2_conn_install_tx_handshake_key(conn, key, iv, hp_key, keylen,
ivlen);
if (rv != 0) {
return -1;
}
break;
case NGTCP2_CRYPTO_LEVEL_APP:
rv = ngtcp2_conn_install_tx_key(conn, secret, key, iv, hp_key, secretlen,
keylen, ivlen);
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 (rv != 0) {
return -1;
if (ngtcp2_crypto_aead_ctx_decrypt_init(&rx_aead_ctx, &ctx.aead, rx_key,
NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
goto fail;
}
ngtcp2_conn_set_retry_aead(conn, ngtcp2_crypto_aead_retry(&retry_aead));
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) {
goto fail;
}
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,72 +690,51 @@ 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;
}
spktlen =
ngtcp2_pkt_write_retry(dest, destlen, dcid, scid, odcid, token, tokenlen,
ngtcp2_crypto_encrypt_cb, &aead, &aead_ctx);
if (spktlen < 0) {
spktlen = -1;
}
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
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;
}
if (ngtcp2_crypto_set_local_transport_params(tls, buf, (size_t)nwrite) != 0) {
return -1;
}
return 0;
}
/*
* crypto_setup_initial_crypto establishes the initial secrets and
* encryption keys, and prepares local QUIC transport parameters.
*/
static int crypto_setup_initial_crypto(ngtcp2_conn *conn,
const ngtcp2_cid *dcid) {
void *tls = ngtcp2_conn_get_tls_native_handle(conn);
if (ngtcp2_crypto_derive_and_install_initial_key(conn, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
dcid) != 0) {
return -1;
}
return crypto_set_local_transport_params(conn, tls);
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);
}

View File

@ -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 */

View File

@ -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;
@ -799,6 +841,30 @@ typedef struct ngtcp2_crypto_cipher {
void *native_handle;
} 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
*
@ -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
@ -2285,6 +2431,27 @@ ngtcp2_conn_get_remote_transport_params(ngtcp2_conn *conn,
NGTCP2_EXTERN void ngtcp2_conn_set_early_remote_transport_params(
ngtcp2_conn *conn, const ngtcp2_transport_params *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
*
@ -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
@ -3033,6 +3212,30 @@ NGTCP2_EXTERN int ngtcp2_conn_is_local_stream(ngtcp2_conn *conn,
*/
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
*
@ -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

View File

@ -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) {

View File

@ -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; }

View File

@ -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|.

View File

@ -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 =

View File

@ -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,

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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));
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}
entry->next = table[h];
table[h] = entry;
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;
}
return 0;
if (!bkt->ksl) {
bkt->ksl = ngtcp2_mem_malloc(mem, sizeof(*bkt->ksl));
if (bkt->ksl == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_ksl_init(bkt->ksl, less, sizeof(key_type), mem);
}
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;
ngtcp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
int rv;
h = hash(key, map->tablelen);
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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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

View File

@ -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 */

View File

@ -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; }

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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_expired_lost_pkt removes expired lost packet.
*/
void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
ngtcp2_tstamp ts);
/*
* 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.
*/
void ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc,
ngtcp2_conn_stat *cstat);
/*
* ngtcp2_rtb_on_crypto_timeout copies all unacknowledged CRYPTO
* 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
*/
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 */

View File

@ -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_ksl_free(&strm->tx.streamfrq);
ngtcp2_rob_free(&strm->rx.rob);
ngtcp2_gaptr_free(&strm->tx.acked_offset);
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;
}
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;
if (nfr->offset != fr->offset + datalen) {
assert(fr->offset + datalen < nfr->offset);
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;
}
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);
}

View File

@ -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;
@ -155,6 +167,15 @@ uint64_t ngtcp2_strm_rx_offset(ngtcp2_strm *strm);
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.
@ -189,6 +210,12 @@ int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc);
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 */