mirror of
https://github.com/nodejs/node.git
synced 2025-12-28 07:50:41 +00:00
deps: update ngtcp2 to 1.19.0
This commit is contained in:
parent
a385bb1d70
commit
51c6dbe85b
@ -627,7 +627,10 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` is the maximum length
|
||||
* of a token generated by `ngtcp2_crypto_generate_regular_token`.
|
||||
* of a token generated by `ngtcp2_crypto_generate_regular_token`.
|
||||
* `ngtcp2_crypto_generate_regular_token2` generates a token of length
|
||||
* at most :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` bytes + the
|
||||
* length of the provided opaque data.
|
||||
*/
|
||||
#define NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN \
|
||||
(/* magic = */ 1 + sizeof(ngtcp2_tstamp) + /* aead tag = */ 16 + \
|
||||
@ -787,6 +790,77 @@ NGTCP2_EXTERN int ngtcp2_crypto_verify_regular_token(
|
||||
size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
||||
ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_generate_regular_token2` generates a token in the
|
||||
* buffer pointed by |token| that is sent with NEW_TOKEN frame. The
|
||||
* buffer pointed by |token| must have at least
|
||||
* :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` + |datalen| bytes long.
|
||||
* The successfully generated token starts with
|
||||
* :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR`. |secret| of length
|
||||
* |secretlen| is a keying material to generate keys to encrypt the
|
||||
* token. |remote_addr| of length |remote_addrlen| is an address of
|
||||
* client. |ts| is the timestamp when the token is generated. |data|
|
||||
* of length |datalen| is an opaque data embedded in the token.
|
||||
* |datalen| must be less than or equal to 256.
|
||||
*
|
||||
* Calling this function with |datalen| = 0 is equivalent to calling
|
||||
* `ngtcp2_crypto_generate_regular_token`.
|
||||
*
|
||||
* To get the opaque data after successful verification, use
|
||||
* `ngtcp2_crypto_verify_regular_token2`.
|
||||
* `ngtcp2_crypto_verify_regular_token` can verify the token with
|
||||
* |datalen| > 0, but it discards the opaque data.
|
||||
*
|
||||
* This function returns the length of generated token if it succeeds,
|
||||
* or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
|
||||
uint8_t *token, const uint8_t *secret, size_t secretlen,
|
||||
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
||||
const void *data, size_t datalen, ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_verify_regular_token2` verifies a regular token
|
||||
* stored in the buffer pointed by |token| of length |tokenlen|.
|
||||
* |secret| of length |secretlen| is a keying material to generate
|
||||
* keys to decrypt the token. |remote_addr| of length
|
||||
* |remote_addrlen| is an address of client. |timeout| is the period
|
||||
* during which the token is valid. |ts| is the current timestamp.
|
||||
* |data| is the pointer to the buffer of length at least
|
||||
* |max_datalen| bytes. If the token is verified successfully, the
|
||||
* opaque data embedded in the token is copied to the buffer pointed
|
||||
* by |data|.
|
||||
*
|
||||
* If |tokenlen| is less than
|
||||
* :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN`, this function returns
|
||||
* :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`.
|
||||
*
|
||||
* If the length of opaque data is larger than |max_datalen|, the
|
||||
* verification still succeeds, but nothing is written to the buffer
|
||||
* pointed by |data|, and this function returns 0. In other words,
|
||||
* the opaque data is discarded.
|
||||
*
|
||||
* This function returns the number of the opaque data written to the
|
||||
* buffer pointed by |data| if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`
|
||||
* A token is badly formatted; or verifying the integrity
|
||||
* protection failed.
|
||||
* :macro:`NGTCP2_CRYPTO_ERR_VERIFY_TOKEN`
|
||||
* A token validity has expired.
|
||||
* :macro:`NGTCP2_CRYPTO_ERR_INTERNAL`
|
||||
* Internal error occurred.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
|
||||
void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
|
||||
const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
||||
ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
||||
94
deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c
vendored
94
deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c
vendored
@ -41,70 +41,40 @@
|
||||
#include "ngtcp2_macro.h"
|
||||
#include "shared.h"
|
||||
|
||||
static int crypto_initialized;
|
||||
#if defined(OPENSSL_NO_CHACHA) || defined(OPENSSL_NO_POLY1305)
|
||||
# define NGTCP2_NO_CHACHA_POLY1305
|
||||
#endif /* defined(OPENSSL_NO_CHACHA) || \
|
||||
defined(OPENSSL_NO_POLY1305) */
|
||||
|
||||
static EVP_CIPHER *crypto_aes_128_gcm;
|
||||
static EVP_CIPHER *crypto_aes_256_gcm;
|
||||
static EVP_CIPHER *crypto_chacha20_poly1305;
|
||||
static EVP_CIPHER *crypto_aes_128_ccm;
|
||||
static EVP_CIPHER *crypto_aes_128_ctr;
|
||||
static EVP_CIPHER *crypto_aes_256_ctr;
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
static EVP_CIPHER *crypto_chacha20_poly1305;
|
||||
static EVP_CIPHER *crypto_chacha20;
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
static EVP_MD *crypto_sha256;
|
||||
static EVP_MD *crypto_sha384;
|
||||
static EVP_KDF *crypto_hkdf;
|
||||
|
||||
int ngtcp2_crypto_ossl_init(void) {
|
||||
/* We do not care whether the pre-fetch succeeds or not. If it
|
||||
fails, it returns NULL, which is still the default value, and our
|
||||
code should still work with it. */
|
||||
crypto_aes_128_gcm = EVP_CIPHER_fetch(NULL, "AES-128-GCM", NULL);
|
||||
if (crypto_aes_128_gcm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_aes_256_gcm = EVP_CIPHER_fetch(NULL, "AES-256-GCM", NULL);
|
||||
if (crypto_aes_256_gcm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL);
|
||||
if (crypto_chacha20_poly1305 == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_aes_128_ccm = EVP_CIPHER_fetch(NULL, "AES-128-CCM", NULL);
|
||||
if (crypto_aes_128_ccm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL);
|
||||
if (crypto_aes_128_ctr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL);
|
||||
if (crypto_aes_256_ctr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL);
|
||||
crypto_chacha20 = EVP_CIPHER_fetch(NULL, "ChaCha20", NULL);
|
||||
if (crypto_chacha20 == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
crypto_sha256 = EVP_MD_fetch(NULL, "sha256", NULL);
|
||||
if (crypto_sha256 == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_sha384 = EVP_MD_fetch(NULL, "sha384", NULL);
|
||||
if (crypto_sha384 == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_hkdf = EVP_KDF_fetch(NULL, "hkdf", NULL);
|
||||
if (crypto_hkdf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -125,6 +95,7 @@ static const EVP_CIPHER *crypto_aead_aes_256_gcm(void) {
|
||||
return EVP_aes_256_gcm();
|
||||
}
|
||||
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
static const EVP_CIPHER *crypto_aead_chacha20_poly1305(void) {
|
||||
if (crypto_chacha20_poly1305) {
|
||||
return crypto_chacha20_poly1305;
|
||||
@ -132,6 +103,7 @@ static const EVP_CIPHER *crypto_aead_chacha20_poly1305(void) {
|
||||
|
||||
return EVP_chacha20_poly1305();
|
||||
}
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
|
||||
static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) {
|
||||
if (crypto_aes_128_ccm) {
|
||||
@ -157,6 +129,7 @@ static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) {
|
||||
return EVP_aes_256_ctr();
|
||||
}
|
||||
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
static const EVP_CIPHER *crypto_cipher_chacha20(void) {
|
||||
if (crypto_chacha20) {
|
||||
return crypto_chacha20;
|
||||
@ -164,6 +137,7 @@ static const EVP_CIPHER *crypto_cipher_chacha20(void) {
|
||||
|
||||
return EVP_chacha20();
|
||||
}
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
|
||||
static const EVP_MD *crypto_md_sha256(void) {
|
||||
if (crypto_sha256) {
|
||||
@ -189,13 +163,21 @@ static EVP_KDF *crypto_kdf_hkdf(void) {
|
||||
return EVP_KDF_fetch(NULL, "hkdf", NULL);
|
||||
}
|
||||
|
||||
static void crypto_kdf_hkdf_free(EVP_KDF *kdf) {
|
||||
if (kdf && crypto_hkdf != kdf) {
|
||||
EVP_KDF_free(kdf);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) {
|
||||
switch (EVP_CIPHER_nid(aead)) {
|
||||
case NID_aes_128_gcm:
|
||||
case NID_aes_256_gcm:
|
||||
return EVP_GCM_TLS_TAG_LEN;
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
case NID_chacha20_poly1305:
|
||||
return EVP_CHACHAPOLY_TLS_TAG_LEN;
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
case NID_aes_128_ccm:
|
||||
return EVP_CCM_TLS_TAG_LEN;
|
||||
default:
|
||||
@ -239,8 +221,10 @@ static const EVP_CIPHER *crypto_cipher_id_get_aead(uint32_t cipher_id) {
|
||||
return crypto_aead_aes_128_gcm();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return crypto_aead_aes_256_gcm();
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return crypto_aead_chacha20_poly1305();
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return crypto_aead_aes_128_ccm();
|
||||
default:
|
||||
@ -253,8 +237,10 @@ static uint64_t crypto_cipher_id_get_aead_max_encryption(uint32_t cipher_id) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM;
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305;
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_CCM;
|
||||
default:
|
||||
@ -268,8 +254,10 @@ crypto_cipher_id_get_aead_max_decryption_failure(uint32_t cipher_id) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM;
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305;
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM;
|
||||
default:
|
||||
@ -284,8 +272,10 @@ static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) {
|
||||
return crypto_cipher_aes_128_ctr();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return crypto_cipher_aes_256_ctr();
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return crypto_cipher_chacha20();
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -294,7 +284,9 @@ static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) {
|
||||
static const EVP_MD *crypto_cipher_id_get_md(uint32_t cipher_id) {
|
||||
switch (cipher_id) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return crypto_md_sha256();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
@ -308,7 +300,9 @@ static int supported_cipher_id(uint32_t cipher_id) {
|
||||
switch (cipher_id) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
#ifndef NGTCP2_NO_CHACHA_POLY1305
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
#endif /* !defined(NGTCP2_NO_CHACHA_POLY1305) */
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return 1;
|
||||
default:
|
||||
@ -697,9 +691,7 @@ int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md,
|
||||
};
|
||||
int rv = 0;
|
||||
|
||||
if (!crypto_initialized) {
|
||||
EVP_KDF_free(kdf);
|
||||
}
|
||||
crypto_kdf_hkdf_free(kdf);
|
||||
|
||||
if (EVP_KDF_derive(kctx, dest, (size_t)EVP_MD_size(prf), params) <= 0) {
|
||||
rv = -1;
|
||||
@ -730,9 +722,7 @@ int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen,
|
||||
};
|
||||
int rv = 0;
|
||||
|
||||
if (!crypto_initialized) {
|
||||
EVP_KDF_free(kdf);
|
||||
}
|
||||
crypto_kdf_hkdf_free(kdf);
|
||||
|
||||
if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) {
|
||||
rv = -1;
|
||||
@ -763,9 +753,7 @@ int ngtcp2_crypto_hkdf(uint8_t *dest, size_t destlen,
|
||||
};
|
||||
int rv = 0;
|
||||
|
||||
if (!crypto_initialized) {
|
||||
EVP_KDF_free(kdf);
|
||||
}
|
||||
crypto_kdf_hkdf_free(kdf);
|
||||
|
||||
if (EVP_KDF_derive(kctx, dest, destlen, params) <= 0) {
|
||||
rv = -1;
|
||||
|
||||
110
deps/ngtcp2/ngtcp2/crypto/shared.c
vendored
110
deps/ngtcp2/ngtcp2/crypto/shared.c
vendored
@ -461,7 +461,9 @@ int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key,
|
||||
|
||||
if (ngtcp2_conn_is_server(conn) &&
|
||||
crypto_set_local_transport_params(conn, tls) != 0) {
|
||||
goto fail;
|
||||
/* Just return -1 because aead_ctx and hp_ctx are now owned by
|
||||
conn. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1305,13 +1307,22 @@ static size_t crypto_generate_regular_token_aad(uint8_t *dest,
|
||||
return addrlen;
|
||||
}
|
||||
|
||||
/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN is the maximum length of
|
||||
opaque data embedded in a regular token. */
|
||||
#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN 256
|
||||
|
||||
/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN is the maximum length
|
||||
of plaintext included in a regular token. */
|
||||
#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN \
|
||||
(sizeof(ngtcp2_tstamp) + NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN)
|
||||
|
||||
static const uint8_t regular_token_info_prefix[] = "regular_token";
|
||||
|
||||
ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
||||
static ngtcp2_ssize crypto_generate_regular_token(
|
||||
uint8_t *token, const uint8_t *secret, size_t secretlen,
|
||||
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
||||
ngtcp2_tstamp ts) {
|
||||
uint8_t plaintext[sizeof(ngtcp2_tstamp)];
|
||||
const void *data, size_t datalen, ngtcp2_tstamp ts) {
|
||||
uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
|
||||
uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
|
||||
uint8_t key[16];
|
||||
uint8_t iv[12];
|
||||
@ -1328,9 +1339,18 @@ ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
||||
int rv;
|
||||
(void)remote_addrlen;
|
||||
|
||||
if (datalen > NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(p, &ts_be, sizeof(ts_be));
|
||||
p += sizeof(ts_be);
|
||||
|
||||
if (datalen) {
|
||||
memcpy(p, data, datalen);
|
||||
p += datalen;
|
||||
}
|
||||
|
||||
plaintextlen = (size_t)(p - plaintext);
|
||||
|
||||
if (ngtcp2_crypto_random(rand_data, sizeof(rand_data)) != 0) {
|
||||
@ -1378,13 +1398,11 @@ ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
||||
return p - token;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
||||
const uint8_t *secret, size_t secretlen,
|
||||
const ngtcp2_sockaddr *remote_addr,
|
||||
ngtcp2_socklen remote_addrlen,
|
||||
ngtcp2_duration timeout,
|
||||
ngtcp2_tstamp ts) {
|
||||
uint8_t plaintext[sizeof(ngtcp2_tstamp)];
|
||||
static ngtcp2_ssize crypto_verify_regular_token(
|
||||
void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
|
||||
const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
||||
ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
|
||||
uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
|
||||
uint8_t key[16];
|
||||
uint8_t iv[12];
|
||||
size_t keylen;
|
||||
@ -1397,13 +1415,14 @@ int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
||||
const uint8_t *rand_data;
|
||||
const uint8_t *ciphertext;
|
||||
size_t ciphertextlen;
|
||||
size_t datalen;
|
||||
int rv;
|
||||
ngtcp2_tstamp gen_ts;
|
||||
(void)remote_addrlen;
|
||||
|
||||
if (tokenlen != NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
|
||||
if (tokenlen < NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
|
||||
token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR) {
|
||||
return -1;
|
||||
return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
|
||||
}
|
||||
|
||||
rand_data = token + tokenlen - NGTCP2_CRYPTO_TOKEN_RAND_DATALEN;
|
||||
@ -1413,6 +1432,10 @@ int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
||||
ngtcp2_crypto_aead_aes_128_gcm(&aead);
|
||||
ngtcp2_crypto_md_sha256(&md);
|
||||
|
||||
if (ciphertextlen > sizeof(plaintext) + aead.max_overhead) {
|
||||
return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
|
||||
}
|
||||
|
||||
keylen = ngtcp2_crypto_aead_keylen(&aead);
|
||||
ivlen = ngtcp2_crypto_aead_noncelen(&aead);
|
||||
|
||||
@ -1423,13 +1446,13 @@ int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
||||
rand_data, NGTCP2_CRYPTO_TOKEN_RAND_DATALEN,
|
||||
regular_token_info_prefix,
|
||||
sizeof(regular_token_info_prefix) - 1) != 0) {
|
||||
return -1;
|
||||
return NGTCP2_CRYPTO_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
aadlen = crypto_generate_regular_token_aad(aad, remote_addr);
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, &aead, key, ivlen) != 0) {
|
||||
return -1;
|
||||
return NGTCP2_CRYPTO_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
rv = ngtcp2_crypto_decrypt(plaintext, &aead, &aead_ctx, ciphertext,
|
||||
@ -1438,19 +1461,74 @@ int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
||||
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
|
||||
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
|
||||
}
|
||||
|
||||
memcpy(&gen_ts, plaintext, sizeof(gen_ts));
|
||||
|
||||
gen_ts = ngtcp2_ntohl64(gen_ts);
|
||||
if (gen_ts + timeout <= ts) {
|
||||
return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
|
||||
}
|
||||
|
||||
if (max_datalen == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
datalen = ciphertextlen - aead.max_overhead - sizeof(gen_ts);
|
||||
if (datalen > max_datalen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(data, plaintext + sizeof(gen_ts), datalen);
|
||||
|
||||
return (ngtcp2_ssize)datalen;
|
||||
}
|
||||
|
||||
ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
|
||||
uint8_t *token, const uint8_t *secret, size_t secretlen,
|
||||
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
||||
ngtcp2_tstamp ts) {
|
||||
return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
|
||||
remote_addrlen, NULL, 0, ts);
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
|
||||
const uint8_t *secret, size_t secretlen,
|
||||
const ngtcp2_sockaddr *remote_addr,
|
||||
ngtcp2_socklen remote_addrlen,
|
||||
ngtcp2_duration timeout,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_ssize datalen =
|
||||
crypto_verify_regular_token(NULL, 0, token, tokenlen, secret, secretlen,
|
||||
remote_addr, remote_addrlen, timeout, ts);
|
||||
|
||||
if (datalen < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(0 == datalen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
|
||||
uint8_t *token, const uint8_t *secret, size_t secretlen,
|
||||
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
|
||||
const void *data, size_t datalen, ngtcp2_tstamp ts) {
|
||||
return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
|
||||
remote_addrlen, data, datalen, ts);
|
||||
}
|
||||
|
||||
ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
|
||||
void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
|
||||
const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
|
||||
ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
|
||||
return crypto_verify_regular_token(data, max_datalen, token, tokenlen, secret,
|
||||
secretlen, remote_addr, remote_addrlen,
|
||||
timeout, ts);
|
||||
}
|
||||
|
||||
ngtcp2_ssize ngtcp2_crypto_write_connection_close(
|
||||
uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid, uint64_t error_code, const uint8_t *reason,
|
||||
|
||||
352
deps/ngtcp2/ngtcp2/examples/client.cc
vendored
352
deps/ngtcp2/ngtcp2/examples/client.cc
vendored
@ -62,10 +62,10 @@ namespace {
|
||||
constexpr size_t max_preferred_versionslen = 4;
|
||||
} // namespace
|
||||
|
||||
Config config{};
|
||||
Config config;
|
||||
|
||||
Stream::Stream(const Request &req, int64_t stream_id)
|
||||
: req(req), stream_id(stream_id), fd(-1) {}
|
||||
: req{req}, stream_id{stream_id} {}
|
||||
|
||||
Stream::~Stream() {
|
||||
if (fd != -1) {
|
||||
@ -175,26 +175,16 @@ void siginthandler(struct ev_loop *loop, ev_signal *w, int revents) {
|
||||
|
||||
Client::Client(struct ev_loop *loop, uint32_t client_chosen_version,
|
||||
uint32_t original_version)
|
||||
: remote_addr_{},
|
||||
loop_(loop),
|
||||
httpconn_(nullptr),
|
||||
addr_(nullptr),
|
||||
port_(nullptr),
|
||||
nstreams_done_(0),
|
||||
nstreams_closed_(0),
|
||||
nkey_update_(0),
|
||||
client_chosen_version_(client_chosen_version),
|
||||
original_version_(original_version),
|
||||
early_data_(false),
|
||||
handshake_confirmed_(false),
|
||||
: loop_{loop},
|
||||
client_chosen_version_{client_chosen_version},
|
||||
original_version_{original_version},
|
||||
no_gso_{
|
||||
#ifdef UDP_SEGMENT
|
||||
false
|
||||
config.no_gso
|
||||
#else // !defined(UDP_SEGMENT)
|
||||
true
|
||||
#endif // !defined(UDP_SEGMENT)
|
||||
},
|
||||
tx_{} {
|
||||
} {
|
||||
ev_io_init(&wev_, writecb, 0, EV_WRITE);
|
||||
wev_.data = this;
|
||||
ev_timer_init(&timer_, timeoutcb, 0., 0.);
|
||||
@ -563,8 +553,7 @@ int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
|
||||
} // namespace
|
||||
|
||||
void Client::set_remote_addr(const ngtcp2_addr &remote_addr) {
|
||||
memcpy(&remote_addr_.su, remote_addr.addr, remote_addr.addrlen);
|
||||
remote_addr_.len = remote_addr.addrlen;
|
||||
remote_addr_.set(remote_addr.addr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -587,8 +576,10 @@ int select_preferred_address(ngtcp2_conn *conn, ngtcp2_path *dest,
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
ngtcp2_addr_copy_byte(&dest->local, &(*ep)->addr.su.sa, (*ep)->addr.len);
|
||||
ngtcp2_addr_copy_byte(&dest->remote, &remote_addr.su.sa, remote_addr.len);
|
||||
ngtcp2_addr_copy_byte(&dest->local, (*ep)->addr.as_sockaddr(),
|
||||
(*ep)->addr.size());
|
||||
ngtcp2_addr_copy_byte(&dest->remote, remote_addr.as_sockaddr(),
|
||||
remote_addr.size());
|
||||
dest->user_data = *ep;
|
||||
|
||||
return 0;
|
||||
@ -821,16 +812,8 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr,
|
||||
params.grease_quic_bit = 1;
|
||||
|
||||
auto path = ngtcp2_path{
|
||||
.local =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&ep.addr.su.sa),
|
||||
.addrlen = ep.addr.len,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&remote_addr.su.sa),
|
||||
.addrlen = remote_addr.len,
|
||||
},
|
||||
.local = as_ngtcp2_addr(ep.addr),
|
||||
.remote = as_ngtcp2_addr(remote_addr),
|
||||
.user_data = &ep,
|
||||
};
|
||||
auto rv =
|
||||
@ -877,16 +860,11 @@ int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data) {
|
||||
auto path = ngtcp2_path{
|
||||
.local =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&ep.addr.su.sa),
|
||||
.addrlen = ep.addr.len,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
},
|
||||
.local = as_ngtcp2_addr(ep.addr),
|
||||
.remote{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
},
|
||||
.user_data = const_cast<Endpoint *>(&ep),
|
||||
};
|
||||
if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(),
|
||||
@ -916,7 +894,7 @@ int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen,
|
||||
|
||||
int Client::on_read(const Endpoint &ep) {
|
||||
std::array<uint8_t, 64_k> buf;
|
||||
sockaddr_union su;
|
||||
sockaddr_storage ss;
|
||||
size_t pktcnt = 0;
|
||||
ngtcp2_pkt_info pi;
|
||||
|
||||
@ -928,14 +906,21 @@ int Client::on_read(const Endpoint &ep) {
|
||||
uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(int))];
|
||||
|
||||
msghdr msg{
|
||||
.msg_name = &su,
|
||||
.msg_name = &ss,
|
||||
.msg_iov = &msg_iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = msg_ctrl,
|
||||
};
|
||||
|
||||
for (;;) {
|
||||
msg.msg_namelen = sizeof(su);
|
||||
auto start = util::timestamp();
|
||||
|
||||
for (; pktcnt < MAX_RECV_PKTS;) {
|
||||
if (util::recv_pkt_time_threshold_exceeded(
|
||||
config.cc_algo == NGTCP2_CC_ALGO_BBR, start, pktcnt)) {
|
||||
break;
|
||||
}
|
||||
|
||||
msg.msg_namelen = sizeof(ss);
|
||||
msg.msg_controllen = sizeof(msg_ctrl);
|
||||
|
||||
auto nread = recvmsg(ep.fd, &msg, 0);
|
||||
@ -954,7 +939,7 @@ int Client::on_read(const Endpoint &ep) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pi.ecn = msghdr_get_ecn(&msg, su.storage.ss_family);
|
||||
pi.ecn = msghdr_get_ecn(&msg, ss.ss_family);
|
||||
auto gso_size = msghdr_get_udp_gro(&msg);
|
||||
if (gso_size == 0) {
|
||||
gso_size = static_cast<size_t>(nread);
|
||||
@ -968,9 +953,10 @@ int Client::on_read(const Endpoint &ep) {
|
||||
++pktcnt;
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Received packet: local="
|
||||
<< util::straddr(&ep.addr.su.sa, ep.addr.len)
|
||||
<< " remote=" << util::straddr(&su.sa, msg.msg_namelen)
|
||||
std::cerr << "Received packet: local=" << util::straddr(ep.addr)
|
||||
<< " remote="
|
||||
<< util::straddr(reinterpret_cast<const sockaddr *>(&ss),
|
||||
msg.msg_namelen)
|
||||
<< " ecn=0x" << std::hex << static_cast<uint32_t>(pi.ecn)
|
||||
<< std::dec << " " << datalen << " bytes" << std::endl;
|
||||
}
|
||||
@ -984,8 +970,8 @@ int Client::on_read(const Endpoint &ep) {
|
||||
if (!config.quiet) {
|
||||
std::cerr << "** Simulated incoming packet loss **" << std::endl;
|
||||
}
|
||||
} else if (feed_data(ep, &su.sa, msg.msg_namelen, &pi,
|
||||
{data.data(), datalen}) != 0) {
|
||||
} else if (feed_data(ep, reinterpret_cast<const sockaddr *>(&ss),
|
||||
msg.msg_namelen, &pi, {data.data(), datalen}) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -995,10 +981,6 @@ int Client::on_read(const Endpoint &ep) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pktcnt >= 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_exit()) {
|
||||
@ -1157,18 +1139,21 @@ int Client::write_streams() {
|
||||
ngtcp2_pkt_info pi;
|
||||
size_t gso_size;
|
||||
auto ts = util::timestamp();
|
||||
auto txbuf = std::span{tx_.data};
|
||||
auto txbuf = std::span{txbuf_};
|
||||
auto buflen = util::clamp_buffer_size(conn_, txbuf.size(), config.gso_burst);
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
auto nwrite =
|
||||
ngtcp2_conn_write_aggregate_pkt(conn_, &ps.path, &pi, txbuf.data(),
|
||||
txbuf.size(), &gso_size, ::write_pkt, ts);
|
||||
auto nwrite = ngtcp2_conn_write_aggregate_pkt2(
|
||||
conn_, &ps.path, &pi, txbuf.data(), buflen, &gso_size, ::write_pkt,
|
||||
config.gso_burst, ts);
|
||||
if (nwrite < 0) {
|
||||
disconnect();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_conn_update_pkt_tx_time(conn_, ts);
|
||||
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -1223,8 +1208,7 @@ void Client::update_timer() {
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
namespace {
|
||||
int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
int family) {
|
||||
int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) {
|
||||
addrinfo hints{
|
||||
.ai_flags = AI_PASSIVE,
|
||||
.ai_family = family,
|
||||
@ -1234,15 +1218,16 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
char *node;
|
||||
std::array<char, NI_MAXHOST> nodebuf;
|
||||
|
||||
if (iau) {
|
||||
if (inet_ntop(family, iau, nodebuf.data(), nodebuf.size()) == nullptr) {
|
||||
if (in_addr_empty(ia)) {
|
||||
node = nullptr;
|
||||
} else {
|
||||
if (inet_ntop(family, in_addr_get_ptr(ia), nodebuf.data(),
|
||||
nodebuf.size()) == nullptr) {
|
||||
std::cerr << "inet_ntop: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
node = nodebuf.data();
|
||||
} else {
|
||||
node = nullptr;
|
||||
}
|
||||
|
||||
if (auto rv = getaddrinfo(node, "0", &hints, &res); rv != 0) {
|
||||
@ -1250,7 +1235,7 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto res_d = defer(freeaddrinfo, res);
|
||||
auto res_d = defer([res] { freeaddrinfo(res); });
|
||||
|
||||
for (rp = res; rp; rp = rp->ai_next) {
|
||||
if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
|
||||
@ -1263,13 +1248,14 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
return -1;
|
||||
}
|
||||
|
||||
socklen_t len = sizeof(local_addr.su.storage);
|
||||
if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
|
||||
sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
if (getsockname(fd, reinterpret_cast<sockaddr *>(&ss), &len) == -1) {
|
||||
std::cerr << "getsockname: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
local_addr.len = len;
|
||||
local_addr.ifindex = 0;
|
||||
|
||||
local_addr.set(reinterpret_cast<const sockaddr *>(&ss));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1279,18 +1265,19 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
#ifndef HAVE_LINUX_RTNETLINK_H
|
||||
namespace {
|
||||
int connect_sock(Address &local_addr, int fd, const Address &remote_addr) {
|
||||
if (connect(fd, &remote_addr.su.sa, remote_addr.len) != 0) {
|
||||
if (connect(fd, remote_addr.as_sockaddr(), remote_addr.size()) != 0) {
|
||||
std::cerr << "connect: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
socklen_t len = sizeof(local_addr.su.storage);
|
||||
if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
|
||||
sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
if (getsockname(fd, reinterpret_cast<sockaddr *>(&ss), &len) == -1) {
|
||||
std::cerr << "getsockname: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
local_addr.len = len;
|
||||
local_addr.ifindex = 0;
|
||||
|
||||
local_addr.set(reinterpret_cast<const sockaddr *>(&ss));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1326,7 +1313,7 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto res_d = defer(freeaddrinfo, res);
|
||||
auto res_d = defer([res] { freeaddrinfo(res); });
|
||||
|
||||
int fd = -1;
|
||||
|
||||
@ -1344,9 +1331,7 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
remote_addr.len = rp->ai_addrlen;
|
||||
memcpy(&remote_addr.su, rp->ai_addr, rp->ai_addrlen);
|
||||
remote_addr.ifindex = 0;
|
||||
remote_addr.set(rp->ai_addr);
|
||||
|
||||
return fd;
|
||||
}
|
||||
@ -1354,9 +1339,9 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) {
|
||||
|
||||
std::optional<Endpoint *> Client::endpoint_for(const Address &remote_addr) {
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
in_addr_union iau;
|
||||
InAddr ia;
|
||||
|
||||
if (get_local_addr(iau, remote_addr) != 0) {
|
||||
if (get_local_addr(ia, remote_addr) != 0) {
|
||||
std::cerr << "Could not get local address for a selected preferred address"
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
@ -1364,12 +1349,14 @@ std::optional<Endpoint *> Client::endpoint_for(const Address &remote_addr) {
|
||||
|
||||
auto current_path = ngtcp2_conn_get_path(conn_);
|
||||
auto current_ep = static_cast<Endpoint *>(current_path->user_data);
|
||||
if (addreq(¤t_ep->addr.su.sa, iau)) {
|
||||
if (addreq(current_ep->addr, ia)) {
|
||||
return current_ep;
|
||||
}
|
||||
#endif // defined(HAVE_LINUX_RTNETLINK_H)
|
||||
|
||||
auto fd = udp_sock(remote_addr.su.sa.sa_family);
|
||||
auto family = remote_addr.family();
|
||||
|
||||
auto fd = udp_sock(family);
|
||||
if (fd == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1377,7 +1364,7 @@ std::optional<Endpoint *> Client::endpoint_for(const Address &remote_addr) {
|
||||
Address local_addr;
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
if (bind_addr(local_addr, fd, &iau, remote_addr.su.sa.sa_family) != 0) {
|
||||
if (bind_addr(local_addr, fd, ia, family) != 0) {
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
@ -1412,21 +1399,23 @@ int Client::change_local_addr() {
|
||||
std::cerr << "Changing local address" << std::endl;
|
||||
}
|
||||
|
||||
auto nfd = udp_sock(remote_addr_.su.sa.sa_family);
|
||||
auto family = remote_addr_.family();
|
||||
|
||||
auto nfd = udp_sock(family);
|
||||
if (nfd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
in_addr_union iau;
|
||||
InAddr ia;
|
||||
|
||||
if (get_local_addr(iau, remote_addr_) != 0) {
|
||||
if (get_local_addr(ia, remote_addr_) != 0) {
|
||||
std::cerr << "Could not get local address" << std::endl;
|
||||
close(nfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind_addr(local_addr, nfd, &iau, remote_addr_.su.sa.sa_family) != 0) {
|
||||
if (bind_addr(local_addr, nfd, ia, family) != 0) {
|
||||
close(nfd);
|
||||
return -1;
|
||||
}
|
||||
@ -1438,8 +1427,8 @@ int Client::change_local_addr() {
|
||||
#endif // !defined(HAVE_LINUX_RTNETLINK_H)
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Local address is now "
|
||||
<< util::straddr(&local_addr.su.sa, local_addr.len) << std::endl;
|
||||
std::cerr << "Local address is now " << util::straddr(local_addr)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
endpoints_.emplace_back();
|
||||
@ -1450,8 +1439,7 @@ int Client::change_local_addr() {
|
||||
ev_io_init(&ep.rev, readcb, nfd, EV_READ);
|
||||
ep.rev.data = &ep;
|
||||
|
||||
ngtcp2_addr addr;
|
||||
ngtcp2_addr_init(&addr, &local_addr.su.sa, local_addr.len);
|
||||
auto addr = as_ngtcp2_addr(local_addr);
|
||||
|
||||
if (config.nat_rebinding) {
|
||||
ngtcp2_conn_set_local_addr(conn_, &addr);
|
||||
@ -1459,11 +1447,7 @@ int Client::change_local_addr() {
|
||||
} else {
|
||||
auto path = ngtcp2_path{
|
||||
.local = addr,
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&remote_addr_.su.sa),
|
||||
.addrlen = remote_addr_.len,
|
||||
},
|
||||
.remote = as_ngtcp2_addr(remote_addr_),
|
||||
.user_data = &ep,
|
||||
};
|
||||
if (auto rv = ngtcp2_conn_initiate_immediate_migration(conn_, &path,
|
||||
@ -1672,8 +1656,7 @@ Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr,
|
||||
assert(static_cast<size_t>(nwrite) == data.size());
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Sent packet: local="
|
||||
<< util::straddr(&ep.addr.su.sa, ep.addr.len) << " remote="
|
||||
std::cerr << "Sent packet: local=" << util::straddr(ep.addr) << " remote="
|
||||
<< util::straddr(remote_addr.addr, remote_addr.addrlen)
|
||||
<< " ecn=0x" << std::hex << ecn << std::dec << " " << nwrite
|
||||
<< " bytes" << std::endl;
|
||||
@ -1691,11 +1674,10 @@ void Client::on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
|
||||
auto &p = tx_.blocked;
|
||||
|
||||
memcpy(&p.remote_addr.su, path.remote.addr, path.remote.addrlen);
|
||||
p.remote_addr.set(path.remote.addr);
|
||||
|
||||
auto &ep = *static_cast<Endpoint *>(path.user_data);
|
||||
|
||||
p.remote_addr.len = path.remote.addrlen;
|
||||
p.endpoint = &ep;
|
||||
p.ecn = ecn;
|
||||
p.data = data;
|
||||
@ -1723,13 +1705,8 @@ int Client::send_blocked_packet() {
|
||||
|
||||
auto &p = tx_.blocked;
|
||||
|
||||
ngtcp2_addr remote_addr{
|
||||
.addr = &p.remote_addr.su.sa,
|
||||
.addrlen = p.remote_addr.len,
|
||||
};
|
||||
|
||||
auto [rest, rv] =
|
||||
send_packet(*p.endpoint, remote_addr, p.ecn, p.data, p.gso_size);
|
||||
auto [rest, rv] = send_packet(*p.endpoint, as_ngtcp2_addr(p.remote_addr),
|
||||
p.ecn, p.data, p.gso_size);
|
||||
if (rv != 0) {
|
||||
assert(NETWORK_ERR_SEND_BLOCKED == rv);
|
||||
|
||||
@ -1785,6 +1762,7 @@ int Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) {
|
||||
auto rv = nghttp3_conn_close_stream(httpconn_, stream_id, app_error_code);
|
||||
switch (rv) {
|
||||
case 0:
|
||||
http_stream_close(stream_id, app_error_code);
|
||||
break;
|
||||
case NGHTTP3_ERR_STREAM_NOT_FOUND:
|
||||
// We have to handle the case when stream opened but no data is
|
||||
@ -1924,11 +1902,11 @@ int Client::submit_http_request(const Stream *stream) {
|
||||
|
||||
int Client::recv_stream_data(uint32_t flags, int64_t stream_id,
|
||||
std::span<const uint8_t> data) {
|
||||
auto nconsumed =
|
||||
nghttp3_conn_read_stream(httpconn_, stream_id, data.data(), data.size(),
|
||||
flags & NGTCP2_STREAM_DATA_FLAG_FIN);
|
||||
auto nconsumed = nghttp3_conn_read_stream2(
|
||||
httpconn_, stream_id, data.data(), data.size(),
|
||||
flags & NGTCP2_STREAM_DATA_FLAG_FIN, ngtcp2_conn_get_timestamp(conn_));
|
||||
if (nconsumed < 0) {
|
||||
std::cerr << "nghttp3_conn_read_stream: "
|
||||
std::cerr << "nghttp3_conn_read_stream2: "
|
||||
<< nghttp3_strerror(static_cast<int>(nconsumed)) << std::endl;
|
||||
ngtcp2_ccerr_set_application_error(
|
||||
&last_error_,
|
||||
@ -1964,15 +1942,13 @@ int Client::select_preferred_address(Address &selected_addr,
|
||||
if (!paddr->ipv4_present) {
|
||||
return -1;
|
||||
}
|
||||
selected_addr.su.in = paddr->ipv4;
|
||||
selected_addr.len = sizeof(paddr->ipv4);
|
||||
selected_addr.skaddr.emplace<sockaddr_in>(paddr->ipv4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!paddr->ipv6_present) {
|
||||
return -1;
|
||||
}
|
||||
selected_addr.su.in6 = paddr->ipv6;
|
||||
selected_addr.len = sizeof(paddr->ipv6);
|
||||
selected_addr.skaddr.emplace<sockaddr_in6>(paddr->ipv6);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@ -1980,8 +1956,8 @@ int Client::select_preferred_address(Address &selected_addr,
|
||||
|
||||
if (!config.quiet) {
|
||||
char host[NI_MAXHOST], service[NI_MAXSERV];
|
||||
if (auto rv = getnameinfo(&selected_addr.su.sa, selected_addr.len, host,
|
||||
sizeof(host), service, sizeof(service),
|
||||
if (auto rv = getnameinfo(selected_addr.as_sockaddr(), selected_addr.size(),
|
||||
host, sizeof(host), service, sizeof(service),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
rv != 0) {
|
||||
std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
|
||||
@ -2149,41 +2125,31 @@ int Client::reset_stream(int64_t stream_id, uint64_t app_error_code) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
int http_stream_close(nghttp3_conn *conn, int64_t stream_id,
|
||||
uint64_t app_error_code, void *conn_user_data,
|
||||
void *stream_user_data) {
|
||||
auto c = static_cast<Client *>(conn_user_data);
|
||||
if (c->http_stream_close(stream_id, app_error_code) != 0) {
|
||||
return NGHTTP3_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int Client::http_stream_close(int64_t stream_id, uint64_t app_error_code) {
|
||||
if (ngtcp2_is_bidi_stream(stream_id)) {
|
||||
assert(ngtcp2_conn_is_local_stream(conn_, stream_id));
|
||||
|
||||
++nstreams_closed_;
|
||||
} else {
|
||||
assert(!ngtcp2_conn_is_local_stream(conn_, stream_id));
|
||||
ngtcp2_conn_extend_max_streams_uni(conn_, 1);
|
||||
void Client::http_stream_close(int64_t stream_id, uint64_t app_error_code) {
|
||||
if (!ngtcp2_is_bidi_stream(stream_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto it = streams_.find(stream_id); it != std::ranges::end(streams_)) {
|
||||
if (!config.quiet) {
|
||||
std::cerr << "HTTP stream " << stream_id << " closed with error code "
|
||||
<< app_error_code << std::endl;
|
||||
}
|
||||
streams_.erase(it);
|
||||
assert(ngtcp2_conn_is_local_stream(conn_, stream_id));
|
||||
|
||||
++nstreams_closed_;
|
||||
|
||||
auto it = streams_.find(stream_id);
|
||||
if (it == std::ranges::end(streams_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!config.quiet) {
|
||||
std::cerr << "HTTP stream " << stream_id << " closed with error code "
|
||||
<< app_error_code << std::endl;
|
||||
}
|
||||
|
||||
streams_.erase(it);
|
||||
}
|
||||
|
||||
namespace {
|
||||
int http_recv_settings(nghttp3_conn *conn, const nghttp3_settings *settings,
|
||||
int http_recv_settings(nghttp3_conn *conn,
|
||||
const nghttp3_proto_settings *settings,
|
||||
void *conn_user_data) {
|
||||
if (!config.quiet) {
|
||||
debug::print_http_settings(settings);
|
||||
@ -2226,7 +2192,6 @@ int Client::setup_httpconn() {
|
||||
}
|
||||
|
||||
nghttp3_callbacks callbacks{
|
||||
.stream_close = ::http_stream_close,
|
||||
.recv_data = ::http_recv_data,
|
||||
.deferred_consume = ::http_deferred_consume,
|
||||
.begin_headers = ::http_begin_headers,
|
||||
@ -2237,10 +2202,10 @@ int Client::setup_httpconn() {
|
||||
.end_trailers = ::http_end_trailers,
|
||||
.stop_sending = ::http_stop_sending,
|
||||
.reset_stream = ::http_reset_stream,
|
||||
.recv_settings = ::http_recv_settings,
|
||||
.recv_origin = ::http_recv_origin,
|
||||
.end_origin = ::http_end_origin,
|
||||
.rand = rand_bytes,
|
||||
.recv_settings2 = ::http_recv_settings,
|
||||
};
|
||||
nghttp3_settings settings;
|
||||
nghttp3_settings_default(&settings);
|
||||
@ -2329,15 +2294,15 @@ int run(Client &c, const char *addr, const char *port,
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
in_addr_union iau;
|
||||
InAddr ia;
|
||||
|
||||
if (get_local_addr(iau, remote_addr) != 0) {
|
||||
if (get_local_addr(ia, remote_addr) != 0) {
|
||||
std::cerr << "Could not get local address" << std::endl;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind_addr(local_addr, fd, &iau, remote_addr.su.sa.sa_family) != 0) {
|
||||
if (bind_addr(local_addr, fd, ia, remote_addr.family()) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
@ -2436,35 +2401,11 @@ void print_usage() {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void config_set_default(Config &config) {
|
||||
config = Config{
|
||||
.tx_loss_prob = 0.,
|
||||
.rx_loss_prob = 0.,
|
||||
.fd = -1,
|
||||
.ciphers = util::crypto_default_ciphers(),
|
||||
.groups = util::crypto_default_groups(),
|
||||
.version = NGTCP2_PROTO_VER_V1,
|
||||
.timeout = 30 * NGTCP2_SECONDS,
|
||||
.http_method = "GET"sv,
|
||||
.max_data = 24_m,
|
||||
.max_stream_data_bidi_local = 16_m,
|
||||
.max_stream_data_uni = 16_m,
|
||||
.max_streams_uni = 100,
|
||||
.cc_algo = NGTCP2_CC_ALGO_CUBIC,
|
||||
.initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT,
|
||||
.handshake_timeout = UINT64_MAX,
|
||||
.ack_thresh = 2,
|
||||
.initial_pkt_num = UINT32_MAX,
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_help() {
|
||||
print_usage();
|
||||
|
||||
config_set_default(config);
|
||||
Config config;
|
||||
|
||||
std::cout << R"(
|
||||
<HOST> Remote server host (DNS name or IP address). In case of
|
||||
@ -2677,6 +2618,15 @@ Options:
|
||||
the handshake fails with ech_required alert, ECH retry
|
||||
configs, if provided by server, will be written to
|
||||
<PATH>.
|
||||
--no-gso Disables GSO.
|
||||
--show-stat Print the connection statistics when the connection is
|
||||
closed.
|
||||
--gso-burst=<N>
|
||||
The maximum number of packets to aggregate for GSO. If
|
||||
GSO is disabled, this is the maximum number of packets
|
||||
to send per an event loop in a single connection. It
|
||||
defaults to 0, which means it is not limited by the
|
||||
configuration.
|
||||
-h, --help Display this help and exit.
|
||||
|
||||
---
|
||||
@ -2697,7 +2647,6 @@ Options:
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
config_set_default(config);
|
||||
char *data_path = nullptr;
|
||||
const char *private_key_file = nullptr;
|
||||
const char *cert_file = nullptr;
|
||||
@ -2762,6 +2711,9 @@ int main(int argc, char **argv) {
|
||||
{"initial-pkt-num", required_argument, &flag, 42},
|
||||
{"pmtud-probes", required_argument, &flag, 43},
|
||||
{"ech-config-list-file", required_argument, &flag, 44},
|
||||
{"no-gso", no_argument, &flag, 45},
|
||||
{"show-stat", no_argument, &flag, 46},
|
||||
{"gso-burst", required_argument, &flag, 47},
|
||||
{},
|
||||
};
|
||||
|
||||
@ -3092,9 +3044,9 @@ int main(int argc, char **argv) {
|
||||
if (auto n = util::parse_uint_iec(optarg); !n) {
|
||||
std::cerr << "max-udp-payload-size: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n > 64_k) {
|
||||
std::cerr << "max-udp-payload-size: must not exceed 65536"
|
||||
<< std::endl;
|
||||
} else if (*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) {
|
||||
std::cerr << "max-udp-payload-size: must not exceed "
|
||||
<< NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n == 0) {
|
||||
std::cerr << "max-udp-payload-size: must not be 0" << std::endl;
|
||||
@ -3212,10 +3164,12 @@ int main(int argc, char **argv) {
|
||||
if (auto n = util::parse_uint_iec(s); !n) {
|
||||
std::cerr << "pmtud-probes: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n <= 1200 || *n >= 64_k) {
|
||||
std::cerr
|
||||
<< "pmtud-probes: must be in range [1201, 65535], inclusive."
|
||||
<< std::endl;
|
||||
} else if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE ||
|
||||
*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) {
|
||||
std::cerr << "pmtud-probes: must be in range ["
|
||||
<< NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1 << ", "
|
||||
<< NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE << "], inclusive."
|
||||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
config.pmtud_probes.push_back(static_cast<uint16_t>(*n));
|
||||
@ -3227,11 +3181,37 @@ int main(int argc, char **argv) {
|
||||
// --ech-config-list-file
|
||||
config.ech_config_list_file = optarg;
|
||||
break;
|
||||
case 45:
|
||||
// --no-gso
|
||||
config.no_gso = true;
|
||||
break;
|
||||
case 46:
|
||||
// --show-stat
|
||||
config.show_stat = true;
|
||||
break;
|
||||
case 47: {
|
||||
// --gso-burst
|
||||
auto n = util::parse_uint(optarg);
|
||||
if (!n) {
|
||||
std::cerr << "gso-burst: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (*n > 64) {
|
||||
std::cerr << "gso-burst: must be in range [0, 64], inclusive."
|
||||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
config.gso_burst = static_cast<size_t>(*n);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind < 2) {
|
||||
@ -3327,7 +3307,7 @@ int main(int argc, char **argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto ev_loop_d = defer(ev_loop_destroy, EV_DEFAULT);
|
||||
auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); });
|
||||
|
||||
auto keylog_filename = getenv("SSLKEYLOGFILE");
|
||||
if (keylog_filename) {
|
||||
|
||||
28
deps/ngtcp2/ngtcp2/examples/client.h
vendored
28
deps/ngtcp2/ngtcp2/examples/client.h
vendored
@ -59,7 +59,7 @@ struct Stream {
|
||||
|
||||
Request req;
|
||||
int64_t stream_id;
|
||||
int fd;
|
||||
int fd{-1};
|
||||
};
|
||||
|
||||
class Client;
|
||||
@ -67,8 +67,8 @@ class Client;
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Client *client;
|
||||
int fd;
|
||||
Client *client{};
|
||||
int fd{};
|
||||
};
|
||||
|
||||
class Client : public ClientBase {
|
||||
@ -133,7 +133,7 @@ public:
|
||||
int extend_max_stream_data(int64_t stream_id, uint64_t max_data);
|
||||
int stop_sending(int64_t stream_id, uint64_t app_error_code);
|
||||
int reset_stream(int64_t stream_id, uint64_t app_error_code);
|
||||
int http_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
void http_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
|
||||
void on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
std::span<const uint8_t> data, size_t gso_size);
|
||||
@ -161,24 +161,24 @@ private:
|
||||
struct ev_loop *loop_;
|
||||
std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_;
|
||||
std::vector<uint32_t> offered_versions_;
|
||||
nghttp3_conn *httpconn_;
|
||||
nghttp3_conn *httpconn_{};
|
||||
// addr_ is the server host address.
|
||||
const char *addr_;
|
||||
const char *addr_{};
|
||||
// port_ is the server port.
|
||||
const char *port_;
|
||||
const char *port_{};
|
||||
// nstreams_done_ is the number of streams opened.
|
||||
size_t nstreams_done_;
|
||||
size_t nstreams_done_{};
|
||||
// nstreams_closed_ is the number of streams get closed.
|
||||
size_t nstreams_closed_;
|
||||
size_t nstreams_closed_{};
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
size_t nkey_update_{};
|
||||
uint32_t client_chosen_version_;
|
||||
uint32_t original_version_;
|
||||
// early_data_ is true if client attempts to do 0RTT data transfer.
|
||||
bool early_data_;
|
||||
bool early_data_{};
|
||||
// handshake_confirmed_ gets true after handshake has been
|
||||
// confirmed.
|
||||
bool handshake_confirmed_;
|
||||
bool handshake_confirmed_{};
|
||||
bool no_gso_;
|
||||
|
||||
struct {
|
||||
@ -191,8 +191,8 @@ private:
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::array<uint8_t, 64_k> data;
|
||||
} tx_;
|
||||
} tx_{};
|
||||
std::array<uint8_t, 64_k> txbuf_;
|
||||
};
|
||||
|
||||
#endif // !defined(CLIENT_H)
|
||||
|
||||
10
deps/ngtcp2/ngtcp2/examples/client_base.cc
vendored
10
deps/ngtcp2/ngtcp2/examples/client_base.cc
vendored
@ -43,16 +43,16 @@ static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
||||
return c->conn();
|
||||
}
|
||||
|
||||
ClientBase::ClientBase()
|
||||
: conn_ref_{get_conn, this},
|
||||
qlog_(nullptr),
|
||||
conn_(nullptr),
|
||||
ticket_received_(false) {
|
||||
ClientBase::ClientBase() : conn_ref_{get_conn, this} {
|
||||
ngtcp2_ccerr_default(&last_error_);
|
||||
}
|
||||
|
||||
ClientBase::~ClientBase() {
|
||||
if (conn_) {
|
||||
if (config.show_stat) {
|
||||
debug::print_conn_info(conn_);
|
||||
}
|
||||
|
||||
ngtcp2_conn_del(conn_);
|
||||
}
|
||||
|
||||
|
||||
105
deps/ngtcp2/ngtcp2/examples/client_base.h
vendored
105
deps/ngtcp2/ngtcp2/examples/client_base.h
vendored
@ -40,6 +40,7 @@
|
||||
#include "tls_client_session.h"
|
||||
#include "network.h"
|
||||
#include "shared.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
@ -50,55 +51,55 @@ struct Request {
|
||||
};
|
||||
|
||||
struct Config {
|
||||
ngtcp2_cid dcid;
|
||||
ngtcp2_cid scid;
|
||||
bool scid_present;
|
||||
ngtcp2_cid dcid{};
|
||||
ngtcp2_cid scid{};
|
||||
bool scid_present{};
|
||||
// tx_loss_prob is probability of losing outgoing packet.
|
||||
double tx_loss_prob;
|
||||
double tx_loss_prob{};
|
||||
// rx_loss_prob is probability of losing incoming packet.
|
||||
double rx_loss_prob;
|
||||
double rx_loss_prob{};
|
||||
// fd is a file descriptor to read input for streams.
|
||||
int fd;
|
||||
int fd{-1};
|
||||
// ciphers is the list of enabled ciphers.
|
||||
const char *ciphers;
|
||||
const char *ciphers{util::crypto_default_ciphers()};
|
||||
// groups is the list of supported groups.
|
||||
const char *groups;
|
||||
const char *groups{util::crypto_default_groups()};
|
||||
// nstreams is the number of streams to open.
|
||||
size_t nstreams;
|
||||
size_t nstreams{};
|
||||
// data is the pointer to memory region which maps file denoted by
|
||||
// fd.
|
||||
uint8_t *data;
|
||||
uint8_t *data{};
|
||||
// datalen is the length of file denoted by fd.
|
||||
size_t datalen;
|
||||
size_t datalen{};
|
||||
// version is a QUIC version to use.
|
||||
uint32_t version;
|
||||
uint32_t version{NGTCP2_PROTO_VER_V1};
|
||||
// quiet suppresses the output normally shown except for the error
|
||||
// messages.
|
||||
bool quiet;
|
||||
bool quiet{};
|
||||
// timeout is an idle timeout for QUIC connection.
|
||||
ngtcp2_duration timeout;
|
||||
ngtcp2_duration timeout{30 * NGTCP2_SECONDS};
|
||||
// session_file is a path to a file to write, and read TLS session.
|
||||
const char *session_file;
|
||||
const char *session_file{};
|
||||
// tp_file is a path to a file to write, and read QUIC transport
|
||||
// parameters.
|
||||
const char *tp_file;
|
||||
const char *tp_file{};
|
||||
// show_secret is true if transport secrets should be printed out.
|
||||
bool show_secret;
|
||||
bool show_secret{};
|
||||
// change_local_addr is the duration after which client changes
|
||||
// local address.
|
||||
ngtcp2_duration change_local_addr;
|
||||
ngtcp2_duration change_local_addr{};
|
||||
// key_update is the duration after which client initiates key
|
||||
// update.
|
||||
ngtcp2_duration key_update;
|
||||
ngtcp2_duration key_update{};
|
||||
// delay_stream is the duration after which client sends the first
|
||||
// 1-RTT stream.
|
||||
ngtcp2_duration delay_stream;
|
||||
ngtcp2_duration delay_stream{};
|
||||
// nat_rebinding is true if simulated NAT rebinding is enabled.
|
||||
bool nat_rebinding;
|
||||
bool nat_rebinding{};
|
||||
// no_preferred_addr is true if client do not follow preferred
|
||||
// address offered by server.
|
||||
bool no_preferred_addr;
|
||||
std::string_view http_method;
|
||||
bool no_preferred_addr{};
|
||||
std::string_view http_method{"GET"sv};
|
||||
// download is a path to a directory where a downloaded file is
|
||||
// saved. If it is empty, no file is saved.
|
||||
std::string_view download;
|
||||
@ -106,55 +107,55 @@ struct Config {
|
||||
std::vector<Request> requests;
|
||||
// no_quic_dump is true if hexdump of QUIC STREAM and CRYPTO data
|
||||
// should be disabled.
|
||||
bool no_quic_dump;
|
||||
bool no_quic_dump{};
|
||||
// no_http_dump is true if hexdump of HTTP response body should be
|
||||
// disabled.
|
||||
bool no_http_dump;
|
||||
bool no_http_dump{};
|
||||
// qlog_file is the path to write qlog.
|
||||
std::string_view qlog_file;
|
||||
// qlog_dir is the path to directory where qlog is stored. qlog_dir
|
||||
// and qlog_file are mutually exclusive.
|
||||
std::string_view qlog_dir;
|
||||
// max_data is the initial connection-level flow control window.
|
||||
uint64_t max_data;
|
||||
uint64_t max_data{24_m};
|
||||
// max_stream_data_bidi_local is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the local endpoint
|
||||
// initiates.
|
||||
uint64_t max_stream_data_bidi_local;
|
||||
uint64_t max_stream_data_bidi_local{16_m};
|
||||
// max_stream_data_bidi_remote is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the remote
|
||||
// endpoint initiates.
|
||||
uint64_t max_stream_data_bidi_remote;
|
||||
uint64_t max_stream_data_bidi_remote{};
|
||||
// max_stream_data_uni is the initial stream-level flow control
|
||||
// window for a unidirectional stream.
|
||||
uint64_t max_stream_data_uni;
|
||||
uint64_t max_stream_data_uni{16_m};
|
||||
// max_streams_bidi is the number of the concurrent bidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_bidi;
|
||||
uint64_t max_streams_bidi{};
|
||||
// max_streams_uni is the number of the concurrent unidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_uni;
|
||||
uint64_t max_streams_uni{100};
|
||||
// max_window is the maximum connection-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_window;
|
||||
uint64_t max_window{};
|
||||
// max_stream_window is the maximum stream-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_stream_window;
|
||||
uint64_t max_stream_window{};
|
||||
// exit_on_first_stream_close is the flag that if it is true, client
|
||||
// exits when a first HTTP stream gets closed. It is not
|
||||
// necessarily the same time when the underlying QUIC stream closes
|
||||
// due to the QPACK synchronization.
|
||||
bool exit_on_first_stream_close;
|
||||
bool exit_on_first_stream_close{};
|
||||
// exit_on_all_streams_close is the flag that if it is true, client
|
||||
// exits when all HTTP streams get closed.
|
||||
bool exit_on_all_streams_close;
|
||||
bool exit_on_all_streams_close{};
|
||||
// disable_early_data disables early data.
|
||||
bool disable_early_data;
|
||||
bool disable_early_data{};
|
||||
// static_secret is used to derive keying materials for Stateless
|
||||
// Retry token.
|
||||
std::array<uint8_t, 32> static_secret;
|
||||
// cc_algo is the congestion controller algorithm.
|
||||
ngtcp2_cc_algo cc_algo;
|
||||
ngtcp2_cc_algo cc_algo{NGTCP2_CC_ALGO_CUBIC};
|
||||
// token_file is a path to file to read or write token from
|
||||
// NEW_TOKEN frame.
|
||||
std::string_view token_file;
|
||||
@ -162,13 +163,13 @@ struct Config {
|
||||
// remote host.
|
||||
std::string_view sni;
|
||||
// initial_rtt is an initial RTT.
|
||||
ngtcp2_duration initial_rtt;
|
||||
ngtcp2_duration initial_rtt{NGTCP2_DEFAULT_INITIAL_RTT};
|
||||
// max_udp_payload_size is the maximum UDP payload size that client
|
||||
// transmits.
|
||||
size_t max_udp_payload_size;
|
||||
size_t max_udp_payload_size{};
|
||||
// handshake_timeout is the period of time before giving up QUIC
|
||||
// connection establishment.
|
||||
ngtcp2_duration handshake_timeout;
|
||||
ngtcp2_duration handshake_timeout{UINT64_MAX};
|
||||
// preferred_versions includes QUIC versions in the order of
|
||||
// preference. Client uses this field to select a version from the
|
||||
// version set offered in Version Negotiation packet.
|
||||
@ -178,24 +179,32 @@ struct Config {
|
||||
// transport_parameter.
|
||||
std::vector<uint32_t> available_versions;
|
||||
// no_pmtud disables Path MTU Discovery.
|
||||
bool no_pmtud;
|
||||
bool no_pmtud{};
|
||||
// ack_thresh is the minimum number of the received ACK eliciting
|
||||
// packets that triggers immediate acknowledgement.
|
||||
size_t ack_thresh;
|
||||
size_t ack_thresh{2};
|
||||
// wait_for_ticket, if true, waits for a ticket to be received
|
||||
// before exiting on exit_on_first_stream_close or
|
||||
// exit_on_all_streams_close.
|
||||
bool wait_for_ticket;
|
||||
bool wait_for_ticket{};
|
||||
// initial_pkt_num is the initial packet number for each packet
|
||||
// number space. If it is set to UINT32_MAX, it is chosen randomly.
|
||||
uint32_t initial_pkt_num;
|
||||
uint32_t initial_pkt_num{UINT32_MAX};
|
||||
// pmtud_probes is the array of UDP datagram payload size to probes.
|
||||
std::vector<uint16_t> pmtud_probes;
|
||||
// ech_config_list contains ECHConfigList.
|
||||
std::vector<uint8_t> ech_config_list;
|
||||
// ech_config_list_file is a path to a file to read and write
|
||||
// ECHConfigList.
|
||||
const char *ech_config_list_file;
|
||||
const char *ech_config_list_file{};
|
||||
// no_gso disables GSO.
|
||||
bool no_gso{};
|
||||
// show_stat, if true, displays the connection statistics when the
|
||||
// connection is closed.
|
||||
bool show_stat{};
|
||||
// gso_burst is the number of packets to aggregate in GSO. 0 means
|
||||
// it is not limited by the configuration.
|
||||
size_t gso_burst{};
|
||||
};
|
||||
|
||||
class ClientBase {
|
||||
@ -218,10 +227,10 @@ public:
|
||||
protected:
|
||||
ngtcp2_crypto_conn_ref conn_ref_;
|
||||
TLSClientSession tls_session_;
|
||||
FILE *qlog_;
|
||||
ngtcp2_conn *conn_;
|
||||
FILE *qlog_{};
|
||||
ngtcp2_conn *conn_{};
|
||||
ngtcp2_ccerr last_error_;
|
||||
bool ticket_received_;
|
||||
bool ticket_received_{};
|
||||
};
|
||||
|
||||
void qlog_write_cb(void *user_data, uint32_t flags, const void *data,
|
||||
|
||||
25
deps/ngtcp2/ngtcp2/examples/debug.cc
vendored
25
deps/ngtcp2/ngtcp2/examples/debug.cc
vendored
@ -283,7 +283,7 @@ void print_http_response_headers(int64_t stream_id, const nghttp3_nv *nva,
|
||||
}
|
||||
}
|
||||
|
||||
void print_http_settings(const nghttp3_settings *settings) {
|
||||
void print_http_settings(const nghttp3_proto_settings *settings) {
|
||||
fprintf(outfile,
|
||||
"http: remote settings\n"
|
||||
"http: SETTINGS_MAX_FIELD_SECTION_SIZE=%" PRIu64 "\n"
|
||||
@ -317,6 +317,29 @@ std::string_view secret_title(ngtcp2_encryption_level level) {
|
||||
}
|
||||
}
|
||||
|
||||
void print_conn_info(ngtcp2_conn *conn) {
|
||||
ngtcp2_conn_info cinfo;
|
||||
|
||||
ngtcp2_conn_get_conn_info(conn, &cinfo);
|
||||
|
||||
std::cout << "# Connection Statistics (see ngtcp2_conn_info for details)\n"
|
||||
"min_rtt="
|
||||
<< util::format_durationf(cinfo.min_rtt) << '\n'
|
||||
<< "smoothed_rtt=" << util::format_durationf(cinfo.smoothed_rtt)
|
||||
<< '\n'
|
||||
<< "rttvar=" << util::format_durationf(cinfo.rttvar) << '\n'
|
||||
<< "cwnd=" << cinfo.cwnd << '\n'
|
||||
<< "ssthresh=" << cinfo.ssthresh << '\n'
|
||||
<< "pkt_sent=" << cinfo.pkt_sent << '\n'
|
||||
<< "bytes_sent=" << cinfo.bytes_sent << '\n'
|
||||
<< "pkt_recv=" << cinfo.pkt_recv << '\n'
|
||||
<< "bytes_recv=" << cinfo.bytes_recv << '\n'
|
||||
<< "pkt_lost=" << cinfo.pkt_lost << '\n'
|
||||
<< "bytes_lost=" << cinfo.bytes_lost << '\n'
|
||||
<< "ping_recv=" << cinfo.ping_recv << '\n'
|
||||
<< "pkt_discarded=" << cinfo.pkt_discarded << std::endl;
|
||||
}
|
||||
|
||||
} // namespace debug
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
4
deps/ngtcp2/ngtcp2/examples/debug.h
vendored
4
deps/ngtcp2/ngtcp2/examples/debug.h
vendored
@ -116,7 +116,7 @@ void print_http_request_headers(int64_t stream_id, const nghttp3_nv *nva,
|
||||
void print_http_response_headers(int64_t stream_id, const nghttp3_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
void print_http_settings(const nghttp3_settings *settings);
|
||||
void print_http_settings(const nghttp3_proto_settings *settings);
|
||||
|
||||
void print_http_origin(const uint8_t *origin, size_t originlen);
|
||||
|
||||
@ -124,6 +124,8 @@ void print_http_end_origin();
|
||||
|
||||
std::string_view secret_title(ngtcp2_encryption_level level);
|
||||
|
||||
void print_conn_info(ngtcp2_conn *conn);
|
||||
|
||||
} // namespace debug
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
6
deps/ngtcp2/ngtcp2/examples/examplestest.cc
vendored
6
deps/ngtcp2/ngtcp2/examples/examplestest.cc
vendored
@ -32,11 +32,17 @@
|
||||
// include test cases' include files here
|
||||
#include "util_test.h"
|
||||
#include "siphash_test.h"
|
||||
#ifdef WITH_EXAMPLE_WOLFSSL
|
||||
# include "sim_test.h"
|
||||
#endif // defined(WITH_EXAMPLE_WOLFSSL)
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const MunitSuite suites[] = {
|
||||
ngtcp2::util_suite,
|
||||
ngtcp2::siphash_suite,
|
||||
#ifdef WITH_EXAMPLE_WOLFSSL
|
||||
ngtcp2::sim_suite,
|
||||
#endif // defined(WITH_EXAMPLE_WOLFSSL)
|
||||
{},
|
||||
};
|
||||
const MunitSuite suite = {
|
||||
|
||||
293
deps/ngtcp2/ngtcp2/examples/h09client.cc
vendored
293
deps/ngtcp2/ngtcp2/examples/h09client.cc
vendored
@ -62,10 +62,10 @@ namespace {
|
||||
constexpr size_t max_preferred_versionslen = 4;
|
||||
} // namespace
|
||||
|
||||
Config config{};
|
||||
Config config;
|
||||
|
||||
Stream::Stream(const Request &req, int64_t stream_id)
|
||||
: req(req), stream_id(stream_id), fd(-1) {
|
||||
: req{req}, stream_id{stream_id} {
|
||||
nghttp3_buf_init(&reqbuf);
|
||||
}
|
||||
|
||||
@ -177,25 +177,16 @@ void siginthandler(struct ev_loop *loop, ev_signal *w, int revents) {
|
||||
|
||||
Client::Client(struct ev_loop *loop, uint32_t client_chosen_version,
|
||||
uint32_t original_version)
|
||||
: remote_addr_{},
|
||||
loop_(loop),
|
||||
addr_(nullptr),
|
||||
port_(nullptr),
|
||||
nstreams_done_(0),
|
||||
nstreams_closed_(0),
|
||||
nkey_update_(0),
|
||||
client_chosen_version_(client_chosen_version),
|
||||
original_version_(original_version),
|
||||
early_data_(false),
|
||||
handshake_confirmed_(false),
|
||||
: loop_{loop},
|
||||
client_chosen_version_{client_chosen_version},
|
||||
original_version_{original_version},
|
||||
no_gso_{
|
||||
#ifdef UDP_SEGMENT
|
||||
false
|
||||
config.no_gso
|
||||
#else // !defined(UDP_SEGMENT)
|
||||
true
|
||||
#endif // !defined(UDP_SEGMENT)
|
||||
},
|
||||
tx_{} {
|
||||
} {
|
||||
ev_io_init(&wev_, writecb, 0, EV_WRITE);
|
||||
wev_.data = this;
|
||||
ev_timer_init(&timer_, timeoutcb, 0., 0.);
|
||||
@ -515,8 +506,7 @@ int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
|
||||
} // namespace
|
||||
|
||||
void Client::set_remote_addr(const ngtcp2_addr &remote_addr) {
|
||||
memcpy(&remote_addr_.su, remote_addr.addr, remote_addr.addrlen);
|
||||
remote_addr_.len = remote_addr.addrlen;
|
||||
remote_addr_.set(remote_addr.addr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -539,8 +529,10 @@ int select_preferred_address(ngtcp2_conn *conn, ngtcp2_path *dest,
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
ngtcp2_addr_copy_byte(&dest->local, &(*ep)->addr.su.sa, (*ep)->addr.len);
|
||||
ngtcp2_addr_copy_byte(&dest->remote, &remote_addr.su.sa, remote_addr.len);
|
||||
ngtcp2_addr_copy_byte(&dest->local, (*ep)->addr.as_sockaddr(),
|
||||
(*ep)->addr.size());
|
||||
ngtcp2_addr_copy_byte(&dest->remote, remote_addr.as_sockaddr(),
|
||||
remote_addr.size());
|
||||
dest->user_data = *ep;
|
||||
|
||||
return 0;
|
||||
@ -750,16 +742,8 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr,
|
||||
params.grease_quic_bit = 1;
|
||||
|
||||
auto path = ngtcp2_path{
|
||||
.local =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&ep.addr.su.sa),
|
||||
.addrlen = ep.addr.len,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&remote_addr.su.sa),
|
||||
.addrlen = remote_addr.len,
|
||||
},
|
||||
.local = as_ngtcp2_addr(ep.addr),
|
||||
.remote = as_ngtcp2_addr(remote_addr),
|
||||
.user_data = &ep,
|
||||
};
|
||||
auto rv =
|
||||
@ -806,16 +790,11 @@ int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data) {
|
||||
auto path = ngtcp2_path{
|
||||
.local =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&ep.addr.su.sa),
|
||||
.addrlen = ep.addr.len,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
},
|
||||
.local = as_ngtcp2_addr(ep.addr),
|
||||
.remote{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
},
|
||||
.user_data = const_cast<Endpoint *>(&ep),
|
||||
};
|
||||
if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(),
|
||||
@ -845,7 +824,7 @@ int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen,
|
||||
|
||||
int Client::on_read(const Endpoint &ep) {
|
||||
std::array<uint8_t, 64_k> buf;
|
||||
sockaddr_union su;
|
||||
sockaddr_storage ss;
|
||||
size_t pktcnt = 0;
|
||||
ngtcp2_pkt_info pi;
|
||||
|
||||
@ -857,14 +836,21 @@ int Client::on_read(const Endpoint &ep) {
|
||||
uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(int))];
|
||||
|
||||
msghdr msg{
|
||||
.msg_name = &su,
|
||||
.msg_name = &ss,
|
||||
.msg_iov = &msg_iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = msg_ctrl,
|
||||
};
|
||||
|
||||
for (;;) {
|
||||
msg.msg_namelen = sizeof(su);
|
||||
auto start = util::timestamp();
|
||||
|
||||
for (; pktcnt < MAX_RECV_PKTS;) {
|
||||
if (util::recv_pkt_time_threshold_exceeded(
|
||||
config.cc_algo == NGTCP2_CC_ALGO_BBR, start, pktcnt)) {
|
||||
break;
|
||||
}
|
||||
|
||||
msg.msg_namelen = sizeof(ss);
|
||||
msg.msg_controllen = sizeof(msg_ctrl);
|
||||
|
||||
auto nread = recvmsg(ep.fd, &msg, 0);
|
||||
@ -883,7 +869,7 @@ int Client::on_read(const Endpoint &ep) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pi.ecn = msghdr_get_ecn(&msg, su.storage.ss_family);
|
||||
pi.ecn = msghdr_get_ecn(&msg, ss.ss_family);
|
||||
auto gso_size = msghdr_get_udp_gro(&msg);
|
||||
if (gso_size == 0) {
|
||||
gso_size = static_cast<size_t>(nread);
|
||||
@ -897,9 +883,10 @@ int Client::on_read(const Endpoint &ep) {
|
||||
++pktcnt;
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Received packet: local="
|
||||
<< util::straddr(&ep.addr.su.sa, ep.addr.len)
|
||||
<< " remote=" << util::straddr(&su.sa, msg.msg_namelen)
|
||||
std::cerr << "Received packet: local=" << util::straddr(ep.addr)
|
||||
<< " remote="
|
||||
<< util::straddr(reinterpret_cast<const sockaddr *>(&ss),
|
||||
msg.msg_namelen)
|
||||
<< " ecn=0x" << std::hex << static_cast<uint32_t>(pi.ecn)
|
||||
<< std::dec << " " << datalen << " bytes" << std::endl;
|
||||
}
|
||||
@ -913,8 +900,8 @@ int Client::on_read(const Endpoint &ep) {
|
||||
if (!config.quiet) {
|
||||
std::cerr << "** Simulated incoming packet loss **" << std::endl;
|
||||
}
|
||||
} else if (feed_data(ep, &su.sa, msg.msg_namelen, &pi,
|
||||
{data.data(), datalen}) != 0) {
|
||||
} else if (feed_data(ep, reinterpret_cast<const sockaddr *>(&ss),
|
||||
msg.msg_namelen, &pi, {data.data(), datalen}) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -924,10 +911,6 @@ int Client::on_read(const Endpoint &ep) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pktcnt >= 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_exit()) {
|
||||
@ -1057,18 +1040,21 @@ int Client::write_streams() {
|
||||
ngtcp2_pkt_info pi;
|
||||
size_t gso_size;
|
||||
auto ts = util::timestamp();
|
||||
auto txbuf = std::span{tx_.data};
|
||||
auto txbuf = std::span{txbuf_};
|
||||
auto buflen = util::clamp_buffer_size(conn_, txbuf.size(), config.gso_burst);
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
auto nwrite =
|
||||
ngtcp2_conn_write_aggregate_pkt(conn_, &ps.path, &pi, txbuf.data(),
|
||||
txbuf.size(), &gso_size, ::write_pkt, ts);
|
||||
auto nwrite = ngtcp2_conn_write_aggregate_pkt2(
|
||||
conn_, &ps.path, &pi, txbuf.data(), buflen, &gso_size, ::write_pkt,
|
||||
config.gso_burst, ts);
|
||||
if (nwrite < 0) {
|
||||
disconnect();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_conn_update_pkt_tx_time(conn_, ts);
|
||||
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -1123,8 +1109,7 @@ void Client::update_timer() {
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
namespace {
|
||||
int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
int family) {
|
||||
int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) {
|
||||
addrinfo hints{
|
||||
.ai_flags = AI_PASSIVE,
|
||||
.ai_family = family,
|
||||
@ -1134,15 +1119,16 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
char *node;
|
||||
std::array<char, NI_MAXHOST> nodebuf;
|
||||
|
||||
if (iau) {
|
||||
if (inet_ntop(family, iau, nodebuf.data(), nodebuf.size()) == nullptr) {
|
||||
if (in_addr_empty(ia)) {
|
||||
node = nullptr;
|
||||
} else {
|
||||
if (inet_ntop(family, in_addr_get_ptr(ia), nodebuf.data(),
|
||||
nodebuf.size()) == nullptr) {
|
||||
std::cerr << "inet_ntop: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
node = nodebuf.data();
|
||||
} else {
|
||||
node = nullptr;
|
||||
}
|
||||
|
||||
if (auto rv = getaddrinfo(node, "0", &hints, &res); rv != 0) {
|
||||
@ -1150,7 +1136,7 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto res_d = defer(freeaddrinfo, res);
|
||||
auto res_d = defer([res] { freeaddrinfo(res); });
|
||||
|
||||
for (rp = res; rp; rp = rp->ai_next) {
|
||||
if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
|
||||
@ -1163,13 +1149,14 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
return -1;
|
||||
}
|
||||
|
||||
socklen_t len = sizeof(local_addr.su.storage);
|
||||
if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
|
||||
sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
if (getsockname(fd, reinterpret_cast<sockaddr *>(&ss), &len) == -1) {
|
||||
std::cerr << "getsockname: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
local_addr.len = len;
|
||||
local_addr.ifindex = 0;
|
||||
|
||||
local_addr.set(reinterpret_cast<const sockaddr *>(&ss));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1179,18 +1166,19 @@ int bind_addr(Address &local_addr, int fd, const in_addr_union *iau,
|
||||
#ifndef HAVE_LINUX_RTNETLINK_H
|
||||
namespace {
|
||||
int connect_sock(Address &local_addr, int fd, const Address &remote_addr) {
|
||||
if (connect(fd, &remote_addr.su.sa, remote_addr.len) != 0) {
|
||||
if (connect(fd, remote_addr.as_sockaddr(), remote_addr.size()) != 0) {
|
||||
std::cerr << "connect: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
socklen_t len = sizeof(local_addr.su.storage);
|
||||
if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
|
||||
sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
if (getsockname(fd, reinterpret_cast<sockaddr *>(&ss), &len) == -1) {
|
||||
std::cerr << "getsockname: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
local_addr.len = len;
|
||||
local_addr.ifindex = 0;
|
||||
|
||||
local_addr.set(reinterpret_cast<const sockaddr *>(&ss));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1226,7 +1214,7 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto res_d = defer(freeaddrinfo, res);
|
||||
auto res_d = defer([res] { freeaddrinfo(res); });
|
||||
|
||||
int fd = -1;
|
||||
|
||||
@ -1244,9 +1232,7 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
remote_addr.len = rp->ai_addrlen;
|
||||
memcpy(&remote_addr.su, rp->ai_addr, rp->ai_addrlen);
|
||||
remote_addr.ifindex = 0;
|
||||
remote_addr.set(rp->ai_addr);
|
||||
|
||||
return fd;
|
||||
}
|
||||
@ -1254,9 +1240,9 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) {
|
||||
|
||||
std::optional<Endpoint *> Client::endpoint_for(const Address &remote_addr) {
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
in_addr_union iau;
|
||||
InAddr ia;
|
||||
|
||||
if (get_local_addr(iau, remote_addr) != 0) {
|
||||
if (get_local_addr(ia, remote_addr) != 0) {
|
||||
std::cerr << "Could not get local address for a selected preferred address"
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
@ -1264,12 +1250,14 @@ std::optional<Endpoint *> Client::endpoint_for(const Address &remote_addr) {
|
||||
|
||||
auto current_path = ngtcp2_conn_get_path(conn_);
|
||||
auto current_ep = static_cast<Endpoint *>(current_path->user_data);
|
||||
if (addreq(¤t_ep->addr.su.sa, iau)) {
|
||||
if (addreq(current_ep->addr, ia)) {
|
||||
return current_ep;
|
||||
}
|
||||
#endif // defined(HAVE_LINUX_RTNETLINK_H)
|
||||
|
||||
auto fd = udp_sock(remote_addr.su.sa.sa_family);
|
||||
auto family = remote_addr.family();
|
||||
|
||||
auto fd = udp_sock(family);
|
||||
if (fd == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1277,7 +1265,7 @@ std::optional<Endpoint *> Client::endpoint_for(const Address &remote_addr) {
|
||||
Address local_addr;
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
if (bind_addr(local_addr, fd, &iau, remote_addr.su.sa.sa_family) != 0) {
|
||||
if (bind_addr(local_addr, fd, ia, family) != 0) {
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
@ -1312,21 +1300,23 @@ int Client::change_local_addr() {
|
||||
std::cerr << "Changing local address" << std::endl;
|
||||
}
|
||||
|
||||
auto nfd = udp_sock(remote_addr_.su.sa.sa_family);
|
||||
auto family = remote_addr_.family();
|
||||
|
||||
auto nfd = udp_sock(family);
|
||||
if (nfd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
in_addr_union iau;
|
||||
InAddr ia;
|
||||
|
||||
if (get_local_addr(iau, remote_addr_) != 0) {
|
||||
if (get_local_addr(ia, remote_addr_) != 0) {
|
||||
std::cerr << "Could not get local address" << std::endl;
|
||||
close(nfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind_addr(local_addr, nfd, &iau, remote_addr_.su.sa.sa_family) != 0) {
|
||||
if (bind_addr(local_addr, nfd, ia, family) != 0) {
|
||||
close(nfd);
|
||||
return -1;
|
||||
}
|
||||
@ -1338,8 +1328,8 @@ int Client::change_local_addr() {
|
||||
#endif // !defined(HAVE_LINUX_RTNETLINK_H)
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Local address is now "
|
||||
<< util::straddr(&local_addr.su.sa, local_addr.len) << std::endl;
|
||||
std::cerr << "Local address is now " << util::straddr(local_addr)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
endpoints_.emplace_back();
|
||||
@ -1350,8 +1340,7 @@ int Client::change_local_addr() {
|
||||
ev_io_init(&ep.rev, readcb, nfd, EV_READ);
|
||||
ep.rev.data = &ep;
|
||||
|
||||
ngtcp2_addr addr;
|
||||
ngtcp2_addr_init(&addr, &local_addr.su.sa, local_addr.len);
|
||||
auto addr = as_ngtcp2_addr(local_addr);
|
||||
|
||||
if (config.nat_rebinding) {
|
||||
ngtcp2_conn_set_local_addr(conn_, &addr);
|
||||
@ -1359,11 +1348,7 @@ int Client::change_local_addr() {
|
||||
} else {
|
||||
auto path = ngtcp2_path{
|
||||
.local = addr,
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&remote_addr_.su.sa),
|
||||
.addrlen = remote_addr_.len,
|
||||
},
|
||||
.remote = as_ngtcp2_addr(remote_addr_),
|
||||
.user_data = &ep,
|
||||
};
|
||||
if (auto rv = ngtcp2_conn_initiate_immediate_migration(conn_, &path,
|
||||
@ -1572,8 +1557,7 @@ Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr,
|
||||
assert(static_cast<size_t>(nwrite) == data.size());
|
||||
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Sent packet: local="
|
||||
<< util::straddr(&ep.addr.su.sa, ep.addr.len) << " remote="
|
||||
std::cerr << "Sent packet: local=" << util::straddr(ep.addr) << " remote="
|
||||
<< util::straddr(remote_addr.addr, remote_addr.addrlen)
|
||||
<< " ecn=0x" << std::hex << ecn << std::dec << " " << nwrite
|
||||
<< " bytes" << std::endl;
|
||||
@ -1591,11 +1575,10 @@ void Client::on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
|
||||
auto &p = tx_.blocked;
|
||||
|
||||
memcpy(&p.remote_addr.su, path.remote.addr, path.remote.addrlen);
|
||||
p.remote_addr.set(path.remote.addr);
|
||||
|
||||
auto &ep = *static_cast<Endpoint *>(path.user_data);
|
||||
|
||||
p.remote_addr.len = path.remote.addrlen;
|
||||
p.endpoint = &ep;
|
||||
p.ecn = ecn;
|
||||
p.data = data;
|
||||
@ -1623,13 +1606,8 @@ int Client::send_blocked_packet() {
|
||||
|
||||
auto &p = tx_.blocked;
|
||||
|
||||
ngtcp2_addr remote_addr{
|
||||
.addr = &p.remote_addr.su.sa,
|
||||
.addrlen = p.remote_addr.len,
|
||||
};
|
||||
|
||||
auto [rest, rv] =
|
||||
send_packet(*p.endpoint, remote_addr, p.ecn, p.data, p.gso_size);
|
||||
auto [rest, rv] = send_packet(*p.endpoint, as_ngtcp2_addr(p.remote_addr),
|
||||
p.ecn, p.data, p.gso_size);
|
||||
if (rv != 0) {
|
||||
assert(NETWORK_ERR_SEND_BLOCKED == rv);
|
||||
|
||||
@ -1801,15 +1779,13 @@ int Client::select_preferred_address(Address &selected_addr,
|
||||
if (!paddr->ipv4_present) {
|
||||
return -1;
|
||||
}
|
||||
selected_addr.su.in = paddr->ipv4;
|
||||
selected_addr.len = sizeof(paddr->ipv4);
|
||||
selected_addr.skaddr.emplace<sockaddr_in>(paddr->ipv4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!paddr->ipv6_present) {
|
||||
return -1;
|
||||
}
|
||||
selected_addr.su.in6 = paddr->ipv6;
|
||||
selected_addr.len = sizeof(paddr->ipv6);
|
||||
selected_addr.skaddr.emplace<sockaddr_in6>(paddr->ipv6);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@ -1817,8 +1793,8 @@ int Client::select_preferred_address(Address &selected_addr,
|
||||
|
||||
if (!config.quiet) {
|
||||
char host[NI_MAXHOST], service[NI_MAXSERV];
|
||||
if (auto rv = getnameinfo(&selected_addr.su.sa, selected_addr.len, host,
|
||||
sizeof(host), service, sizeof(service),
|
||||
if (auto rv = getnameinfo(selected_addr.as_sockaddr(), selected_addr.size(),
|
||||
host, sizeof(host), service, sizeof(service),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
rv != 0) {
|
||||
std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
|
||||
@ -1847,15 +1823,15 @@ int run(Client &c, const char *addr, const char *port,
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
in_addr_union iau;
|
||||
InAddr ia;
|
||||
|
||||
if (get_local_addr(iau, remote_addr) != 0) {
|
||||
if (get_local_addr(ia, remote_addr) != 0) {
|
||||
std::cerr << "Could not get local address" << std::endl;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind_addr(local_addr, fd, &iau, remote_addr.su.sa.sa_family) != 0) {
|
||||
if (bind_addr(local_addr, fd, ia, remote_addr.family()) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
@ -1949,35 +1925,11 @@ void print_usage() {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void config_set_default(Config &config) {
|
||||
config = Config{
|
||||
.tx_loss_prob = 0.,
|
||||
.rx_loss_prob = 0.,
|
||||
.fd = -1,
|
||||
.ciphers = util::crypto_default_ciphers(),
|
||||
.groups = util::crypto_default_groups(),
|
||||
.version = NGTCP2_PROTO_VER_V1,
|
||||
.timeout = 30 * NGTCP2_SECONDS,
|
||||
.http_method = "GET"sv,
|
||||
.max_data = 24_m,
|
||||
.max_stream_data_bidi_local = 16_m,
|
||||
.max_stream_data_uni = 16_m,
|
||||
.max_streams_uni = 100,
|
||||
.cc_algo = NGTCP2_CC_ALGO_CUBIC,
|
||||
.initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT,
|
||||
.handshake_timeout = UINT64_MAX,
|
||||
.ack_thresh = 2,
|
||||
.initial_pkt_num = UINT32_MAX,
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_help() {
|
||||
print_usage();
|
||||
|
||||
config_set_default(config);
|
||||
Config config;
|
||||
|
||||
std::cout << R"(
|
||||
<HOST> Remote server host (DNS name or IP address). In case of
|
||||
@ -2186,6 +2138,15 @@ Options:
|
||||
the handshake fails with ech_required alert, ECH retry
|
||||
configs, if provided by server, will be written to
|
||||
<PATH>.
|
||||
--no-gso Disables GSO.
|
||||
--show-stat Print the connection statistics when the connection is
|
||||
closed.
|
||||
--gso-burst=<N>
|
||||
The maximum number of packets to aggregate for GSO. If
|
||||
GSO is disabled, this is the maximum number of packets
|
||||
to send per an event loop in a single connection. It
|
||||
defaults to 0, which means it is not limited by the
|
||||
configuration.
|
||||
-h, --help Display this help and exit.
|
||||
|
||||
---
|
||||
@ -2206,7 +2167,6 @@ Options:
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
config_set_default(config);
|
||||
char *data_path = nullptr;
|
||||
const char *private_key_file = nullptr;
|
||||
const char *cert_file = nullptr;
|
||||
@ -2270,6 +2230,9 @@ int main(int argc, char **argv) {
|
||||
{"initial-pkt-num", required_argument, &flag, 42},
|
||||
{"pmtud-probes", required_argument, &flag, 43},
|
||||
{"ech-config-list-file", required_argument, &flag, 44},
|
||||
{"no-gso", no_argument, &flag, 45},
|
||||
{"show-stat", no_argument, &flag, 46},
|
||||
{"gso-burst", required_argument, &flag, 47},
|
||||
{},
|
||||
};
|
||||
|
||||
@ -2580,9 +2543,9 @@ int main(int argc, char **argv) {
|
||||
if (auto n = util::parse_uint_iec(optarg); !n) {
|
||||
std::cerr << "max-udp-payload-size: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n > 64_k) {
|
||||
std::cerr << "max-udp-payload-size: must not exceed 65536"
|
||||
<< std::endl;
|
||||
} else if (*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) {
|
||||
std::cerr << "max-udp-payload-size: must not exceed "
|
||||
<< NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n == 0) {
|
||||
std::cerr << "max-udp-payload-size: must not be 0" << std::endl;
|
||||
@ -2700,10 +2663,12 @@ int main(int argc, char **argv) {
|
||||
if (auto n = util::parse_uint_iec(s); !n) {
|
||||
std::cerr << "pmtud-probes: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n <= 1200 || *n >= 64_k) {
|
||||
std::cerr
|
||||
<< "pmtud-probes: must be in range [1201, 65535], inclusive."
|
||||
<< std::endl;
|
||||
} else if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE ||
|
||||
*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) {
|
||||
std::cerr << "pmtud-probes: must be in range ["
|
||||
<< NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1 << ", "
|
||||
<< NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE << "], inclusive."
|
||||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
config.pmtud_probes.push_back(static_cast<uint16_t>(*n));
|
||||
@ -2715,11 +2680,37 @@ int main(int argc, char **argv) {
|
||||
// --ech-config-list-file
|
||||
config.ech_config_list_file = optarg;
|
||||
break;
|
||||
case 45:
|
||||
// --no-gso
|
||||
config.no_gso = true;
|
||||
break;
|
||||
case 46:
|
||||
// --show-stat
|
||||
config.show_stat = true;
|
||||
break;
|
||||
case 47: {
|
||||
// --gso-burst
|
||||
auto n = util::parse_uint(optarg);
|
||||
if (!n) {
|
||||
std::cerr << "gso-burst: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (*n > 64) {
|
||||
std::cerr << "gso-burst: must be in range [0, 64], inclusive."
|
||||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
config.gso_burst = static_cast<size_t>(*n);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind < 2) {
|
||||
@ -2815,7 +2806,7 @@ int main(int argc, char **argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto ev_loop_d = defer(ev_loop_destroy, EV_DEFAULT);
|
||||
auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); });
|
||||
|
||||
auto keylog_filename = getenv("SSLKEYLOGFILE");
|
||||
if (keylog_filename) {
|
||||
|
||||
24
deps/ngtcp2/ngtcp2/examples/h09client.h
vendored
24
deps/ngtcp2/ngtcp2/examples/h09client.h
vendored
@ -61,7 +61,7 @@ struct Stream {
|
||||
|
||||
Request req;
|
||||
int64_t stream_id;
|
||||
int fd;
|
||||
int fd{-1};
|
||||
std::string rawreqbuf;
|
||||
nghttp3_buf reqbuf;
|
||||
};
|
||||
@ -77,8 +77,8 @@ class Client;
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Client *client;
|
||||
int fd;
|
||||
Client *client{};
|
||||
int fd{};
|
||||
};
|
||||
|
||||
class Client : public ClientBase {
|
||||
@ -167,22 +167,22 @@ private:
|
||||
std::set<Stream *, StreamIDLess> sendq_;
|
||||
std::vector<uint32_t> offered_versions_;
|
||||
// addr_ is the server host address.
|
||||
const char *addr_;
|
||||
const char *addr_{};
|
||||
// port_ is the server port.
|
||||
const char *port_;
|
||||
const char *port_{};
|
||||
// nstreams_done_ is the number of streams opened.
|
||||
size_t nstreams_done_;
|
||||
size_t nstreams_done_{};
|
||||
// nstreams_closed_ is the number of streams get closed.
|
||||
size_t nstreams_closed_;
|
||||
size_t nstreams_closed_{};
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
size_t nkey_update_{};
|
||||
uint32_t client_chosen_version_;
|
||||
uint32_t original_version_;
|
||||
// early_data_ is true if client attempts to do 0RTT data transfer.
|
||||
bool early_data_;
|
||||
bool early_data_{};
|
||||
// handshake_confirmed_ gets true after handshake has been
|
||||
// confirmed.
|
||||
bool handshake_confirmed_;
|
||||
bool handshake_confirmed_{};
|
||||
bool no_gso_;
|
||||
|
||||
struct {
|
||||
@ -195,8 +195,8 @@ private:
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::array<uint8_t, 64_k> data;
|
||||
} tx_;
|
||||
} tx_{};
|
||||
std::array<uint8_t, 64_k> txbuf_;
|
||||
};
|
||||
|
||||
#endif // !defined(H09CLIENT_H)
|
||||
|
||||
474
deps/ngtcp2/ngtcp2/examples/h09server.cc
vendored
474
deps/ngtcp2/ngtcp2/examples/h09server.cc
vendored
@ -66,22 +66,14 @@ namespace {
|
||||
constexpr size_t max_preferred_versionslen = 4;
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
constexpr size_t NGTCP2_STATELESS_RESET_BURST = 100;
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
constexpr size_t NGTCP2_TX_BUFLEN = 64_k;
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
auto randgen = util::make_mt19937();
|
||||
} // namespace
|
||||
|
||||
Config config{};
|
||||
Config config;
|
||||
|
||||
Stream::Stream(int64_t stream_id, Handler *handler)
|
||||
: stream_id(stream_id), handler(handler), eos(false) {
|
||||
: stream_id{stream_id}, handler{handler} {
|
||||
nghttp3_buf_init(&respbuf);
|
||||
htp.data = this;
|
||||
http_parser_init(&htp, HTTP_REQUEST);
|
||||
@ -156,10 +148,10 @@ enum FileEntryFlag {
|
||||
};
|
||||
|
||||
struct FileEntry {
|
||||
uint64_t len;
|
||||
void *map;
|
||||
int fd;
|
||||
uint8_t flags;
|
||||
uint64_t len{};
|
||||
void *map{};
|
||||
int fd{};
|
||||
uint8_t flags{};
|
||||
};
|
||||
|
||||
namespace {
|
||||
@ -183,7 +175,7 @@ std::pair<FileEntry, int> Stream::open_file(const std::string &path) {
|
||||
return {{}, -1};
|
||||
}
|
||||
|
||||
FileEntry fe{};
|
||||
FileEntry fe;
|
||||
if (st.st_mode & S_IFDIR) {
|
||||
fe.flags |= FILE_ENTRY_TYPE_DIR;
|
||||
fe.fd = -1;
|
||||
@ -319,10 +311,7 @@ void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = h->on_write();
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
h->signal_write();
|
||||
|
||||
return;
|
||||
|
||||
@ -339,23 +328,14 @@ fail:
|
||||
} // namespace
|
||||
|
||||
Handler::Handler(struct ev_loop *loop, Server *server)
|
||||
: loop_(loop),
|
||||
server_(server),
|
||||
qlog_(nullptr),
|
||||
scid_{},
|
||||
nkey_update_(0),
|
||||
: loop_{loop},
|
||||
server_{server},
|
||||
no_gso_{
|
||||
#ifdef UDP_SEGMENT
|
||||
false
|
||||
config.no_gso
|
||||
#else // !defined(UDP_SEGMENT)
|
||||
true
|
||||
#endif // !defined(UDP_SEGMENT)
|
||||
},
|
||||
close_wait_{
|
||||
.next_pkts_recv = 1,
|
||||
},
|
||||
tx_{
|
||||
.data = std::unique_ptr<uint8_t[]>(new uint8_t[NGTCP2_TX_BUFLEN]),
|
||||
} {
|
||||
ev_io_init(&wev_, writecb, 0, EV_WRITE);
|
||||
wev_.data = this;
|
||||
@ -416,19 +396,17 @@ int Handler::handshake_completed() {
|
||||
token.data(), config.static_secret.data(), config.static_secret.size(),
|
||||
path->remote.addr, path->remote.addrlen, t);
|
||||
if (tokenlen < 0) {
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unable to generate token" << std::endl;
|
||||
}
|
||||
std::cerr << "Unable to generate token" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(),
|
||||
as_unsigned(tokenlen));
|
||||
rv != 0) {
|
||||
if (!config.quiet) {
|
||||
std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv)
|
||||
<< std::endl;
|
||||
}
|
||||
std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv)
|
||||
<< std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -515,9 +493,9 @@ void Handler::on_stream_open(int64_t stream_id) {
|
||||
if (!ngtcp2_is_bidi_stream(stream_id)) {
|
||||
return;
|
||||
}
|
||||
auto it = streams_.find(stream_id);
|
||||
(void)it;
|
||||
assert(it == std::ranges::end(streams_));
|
||||
|
||||
assert(!streams_.contains(stream_id));
|
||||
|
||||
streams_.emplace(stream_id, std::make_unique<Stream>(stream_id, this));
|
||||
}
|
||||
|
||||
@ -610,9 +588,7 @@ int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
|
||||
token.data(), config.static_secret.data(), config.static_secret.size(),
|
||||
path->remote.addr, path->remote.addrlen, t);
|
||||
if (tokenlen < 0) {
|
||||
if (!config.quiet) {
|
||||
std::cerr << "Unable to generate token" << std::endl;
|
||||
}
|
||||
std::cerr << "Unable to generate token" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -620,10 +596,8 @@ int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
|
||||
if (auto rv =
|
||||
ngtcp2_conn_submit_new_token(conn, token.data(), as_unsigned(tokenlen));
|
||||
rv != 0) {
|
||||
if (!config.quiet) {
|
||||
std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv)
|
||||
<< std::endl;
|
||||
}
|
||||
std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv)
|
||||
<< std::endl;
|
||||
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
@ -670,7 +644,7 @@ void Handler::write_qlog(const void *data, size_t datalen) {
|
||||
}
|
||||
|
||||
int Handler::init(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_cid *dcid,
|
||||
const Address &remote_addr, const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid, const ngtcp2_cid *ocid,
|
||||
std::span<const uint8_t> token, ngtcp2_token_type token_type,
|
||||
uint32_t version, TLSServerContext &tls_ctx) {
|
||||
@ -789,16 +763,19 @@ int Handler::init(const Endpoint &ep, const Address &local_addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.preferred_ipv4_addr.len || config.preferred_ipv6_addr.len) {
|
||||
if (!config.preferred_ipv4_addr.empty() ||
|
||||
!config.preferred_ipv6_addr.empty()) {
|
||||
params.preferred_addr_present = 1;
|
||||
|
||||
if (config.preferred_ipv4_addr.len) {
|
||||
params.preferred_addr.ipv4 = config.preferred_ipv4_addr.su.in;
|
||||
if (!config.preferred_ipv4_addr.empty()) {
|
||||
params.preferred_addr.ipv4 =
|
||||
std::get<sockaddr_in>(config.preferred_ipv4_addr.skaddr);
|
||||
params.preferred_addr.ipv4_present = 1;
|
||||
}
|
||||
|
||||
if (config.preferred_ipv6_addr.len) {
|
||||
params.preferred_addr.ipv6 = config.preferred_ipv6_addr.su.in6;
|
||||
if (!config.preferred_ipv6_addr.empty()) {
|
||||
params.preferred_addr.ipv6 =
|
||||
std::get<sockaddr_in6>(config.preferred_ipv6_addr.skaddr);
|
||||
params.preferred_addr.ipv6_present = 1;
|
||||
}
|
||||
|
||||
@ -820,16 +797,8 @@ int Handler::init(const Endpoint &ep, const Address &local_addr,
|
||||
}
|
||||
|
||||
auto path = ngtcp2_path{
|
||||
.local =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&local_addr.su.sa),
|
||||
.addrlen = local_addr.len,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
},
|
||||
.local = as_ngtcp2_addr(local_addr),
|
||||
.remote = as_ngtcp2_addr(remote_addr),
|
||||
.user_data = const_cast<Endpoint *>(&ep),
|
||||
};
|
||||
if (auto rv =
|
||||
@ -854,20 +823,11 @@ int Handler::init(const Endpoint &ep, const Address &local_addr,
|
||||
}
|
||||
|
||||
int Handler::feed_data(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data) {
|
||||
auto path = ngtcp2_path{
|
||||
.local =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&local_addr.su.sa),
|
||||
.addrlen = local_addr.len,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
},
|
||||
.local = as_ngtcp2_addr(local_addr),
|
||||
.remote = as_ngtcp2_addr(remote_addr),
|
||||
.user_data = const_cast<Endpoint *>(&ep),
|
||||
};
|
||||
|
||||
@ -901,9 +861,9 @@ int Handler::feed_data(const Endpoint &ep, const Address &local_addr,
|
||||
}
|
||||
|
||||
int Handler::on_read(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi, std::span<const uint8_t> data) {
|
||||
if (auto rv = feed_data(ep, local_addr, sa, salen, pi, data); rv != 0) {
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data) {
|
||||
if (auto rv = feed_data(ep, local_addr, remote_addr, pi, data); rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1030,17 +990,20 @@ int Handler::write_streams() {
|
||||
ngtcp2_pkt_info pi;
|
||||
size_t gso_size;
|
||||
auto ts = util::timestamp();
|
||||
auto txbuf = std::span{tx_.data.get(), NGTCP2_TX_BUFLEN};
|
||||
auto txbuf = std::span{txbuf_};
|
||||
auto buflen = util::clamp_buffer_size(conn_, txbuf.size(), config.gso_burst);
|
||||
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
auto nwrite =
|
||||
ngtcp2_conn_write_aggregate_pkt(conn_, &ps.path, &pi, txbuf.data(),
|
||||
txbuf.size(), &gso_size, ::write_pkt, ts);
|
||||
auto nwrite = ngtcp2_conn_write_aggregate_pkt2(
|
||||
conn_, &ps.path, &pi, txbuf.data(), buflen, &gso_size, ::write_pkt,
|
||||
config.gso_burst, ts);
|
||||
if (nwrite < 0) {
|
||||
return handle_error();
|
||||
}
|
||||
|
||||
ngtcp2_conn_update_pkt_tx_time(conn_, ts);
|
||||
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -1078,11 +1041,9 @@ void Handler::on_send_blocked(const ngtcp2_path &path, unsigned int ecn,
|
||||
|
||||
auto &p = tx_.blocked;
|
||||
|
||||
memcpy(&p.local_addr.su, path.local.addr, path.local.addrlen);
|
||||
memcpy(&p.remote_addr.su, path.remote.addr, path.remote.addrlen);
|
||||
p.local_addr.set(path.local.addr);
|
||||
p.remote_addr.set(path.remote.addr);
|
||||
|
||||
p.local_addr.len = path.local.addrlen;
|
||||
p.remote_addr.len = path.remote.addrlen;
|
||||
p.endpoint = static_cast<Endpoint *>(path.user_data);
|
||||
p.ecn = ecn;
|
||||
p.data = data;
|
||||
@ -1108,17 +1069,9 @@ int Handler::send_blocked_packet() {
|
||||
|
||||
auto &p = tx_.blocked;
|
||||
|
||||
ngtcp2_addr local_addr{
|
||||
.addr = &p.local_addr.su.sa,
|
||||
.addrlen = p.local_addr.len,
|
||||
};
|
||||
ngtcp2_addr remote_addr{
|
||||
.addr = &p.remote_addr.su.sa,
|
||||
.addrlen = p.remote_addr.len,
|
||||
};
|
||||
|
||||
auto [rest, rv] = server_->send_packet(
|
||||
*p.endpoint, no_gso_, local_addr, remote_addr, p.ecn, p.data, p.gso_size);
|
||||
*p.endpoint, no_gso_, as_ngtcp2_addr(p.local_addr),
|
||||
as_ngtcp2_addr(p.remote_addr), p.ecn, p.data, p.gso_size);
|
||||
if (rv != 0) {
|
||||
assert(NETWORK_ERR_SEND_BLOCKED == rv);
|
||||
|
||||
@ -1230,7 +1183,7 @@ int Handler::send_conn_close() {
|
||||
}
|
||||
|
||||
int Handler::send_conn_close(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const Address &remote_addr,
|
||||
const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data) {
|
||||
assert(conn_closebuf_ && conn_closebuf_->size());
|
||||
@ -1244,21 +1197,8 @@ int Handler::send_conn_close(const Endpoint &ep, const Address &local_addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto path = ngtcp2_path{
|
||||
.local =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(&local_addr.su.sa),
|
||||
.addrlen = local_addr.len,
|
||||
},
|
||||
.remote =
|
||||
{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
},
|
||||
.user_data = const_cast<Endpoint *>(&ep),
|
||||
};
|
||||
|
||||
auto rv = server_->send_packet(ep, path.local, path.remote,
|
||||
auto rv = server_->send_packet(ep, as_ngtcp2_addr(local_addr),
|
||||
as_ngtcp2_addr(remote_addr),
|
||||
/* ecn = */ 0, conn_closebuf_->data());
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
@ -1444,9 +1384,7 @@ void siginthandler(struct ev_loop *loop, ev_signal *watcher, int revents) {
|
||||
} // namespace
|
||||
|
||||
Server::Server(struct ev_loop *loop, TLSServerContext &tls_ctx)
|
||||
: loop_(loop),
|
||||
tls_ctx_(tls_ctx),
|
||||
stateless_reset_bucket_(NGTCP2_STATELESS_RESET_BURST) {
|
||||
: loop_{loop}, tls_ctx_{tls_ctx} {
|
||||
ev_signal_init(&sigintev_, siginthandler, SIGINT);
|
||||
|
||||
ev_timer_init(
|
||||
@ -1513,7 +1451,7 @@ int create_sock(Address &local_addr, const char *addr, const char *port,
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto res_d = defer(freeaddrinfo, res);
|
||||
auto res_d = defer([res] { freeaddrinfo(res); });
|
||||
|
||||
int fd = -1;
|
||||
|
||||
@ -1565,14 +1503,15 @@ int create_sock(Address &local_addr, const char *addr, const char *port,
|
||||
return -1;
|
||||
}
|
||||
|
||||
socklen_t len = sizeof(local_addr.su.storage);
|
||||
if (getsockname(fd, &local_addr.su.sa, &len) == -1) {
|
||||
sockaddr_storage ss;
|
||||
socklen_t len = sizeof(ss);
|
||||
if (getsockname(fd, reinterpret_cast<sockaddr *>(&ss), &len) == -1) {
|
||||
std::cerr << "getsockname: " << strerror(errno) << std::endl;
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
local_addr.len = len;
|
||||
local_addr.ifindex = 0;
|
||||
|
||||
local_addr.set(reinterpret_cast<const sockaddr *>(&ss));
|
||||
|
||||
return fd;
|
||||
}
|
||||
@ -1593,6 +1532,7 @@ int add_endpoint(std::vector<Endpoint> &endpoints, const char *addr,
|
||||
ep.addr = dest;
|
||||
ep.fd = fd;
|
||||
ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
|
||||
ev_set_priority(&ep.rev, EV_MAXPRI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1600,14 +1540,16 @@ int add_endpoint(std::vector<Endpoint> &endpoints, const char *addr,
|
||||
|
||||
namespace {
|
||||
int add_endpoint(std::vector<Endpoint> &endpoints, const Address &addr) {
|
||||
auto fd = util::create_nonblock_socket(addr.su.sa.sa_family, SOCK_DGRAM, 0);
|
||||
auto family = addr.family();
|
||||
|
||||
auto fd = util::create_nonblock_socket(family, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
std::cerr << "socket: " << strerror(errno) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int val = 1;
|
||||
if (addr.su.sa.sa_family == AF_INET6) {
|
||||
if (family == AF_INET6) {
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
|
||||
static_cast<socklen_t>(sizeof(val))) == -1) {
|
||||
std::cerr << "setsockopt: " << strerror(errno) << std::endl;
|
||||
@ -1634,12 +1576,12 @@ int add_endpoint(std::vector<Endpoint> &endpoints, const Address &addr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd_set_recv_ecn(fd, addr.su.sa.sa_family);
|
||||
fd_set_ip_mtu_discover(fd, addr.su.sa.sa_family);
|
||||
fd_set_ip_dontfrag(fd, addr.su.sa.sa_family);
|
||||
fd_set_recv_ecn(fd, family);
|
||||
fd_set_ip_mtu_discover(fd, family);
|
||||
fd_set_ip_dontfrag(fd, family);
|
||||
fd_set_udp_gro(fd);
|
||||
|
||||
if (bind(fd, &addr.su.sa, addr.len) == -1) {
|
||||
if (bind(fd, addr.as_sockaddr(), addr.size()) == -1) {
|
||||
std::cerr << "bind: " << strerror(errno) << std::endl;
|
||||
close(fd);
|
||||
return -1;
|
||||
@ -1650,6 +1592,7 @@ int add_endpoint(std::vector<Endpoint> &endpoints, const Address &addr) {
|
||||
ep.addr = addr;
|
||||
ep.fd = fd;
|
||||
ev_io_init(&ep.rev, sreadcb, 0, EV_READ);
|
||||
ev_set_priority(&ep.rev, EV_MAXPRI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1671,11 +1614,11 @@ int Server::init(const char *addr, const char *port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.preferred_ipv4_addr.len &&
|
||||
if (!config.preferred_ipv4_addr.empty() &&
|
||||
add_endpoint(endpoints_, config.preferred_ipv4_addr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (config.preferred_ipv6_addr.len &&
|
||||
if (!config.preferred_ipv6_addr.empty() &&
|
||||
add_endpoint(endpoints_, config.preferred_ipv6_addr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1695,7 +1638,7 @@ int Server::init(const char *addr, const char *port) {
|
||||
}
|
||||
|
||||
int Server::on_read(const Endpoint &ep) {
|
||||
sockaddr_union su;
|
||||
sockaddr_storage ss;
|
||||
std::array<uint8_t, 64_k> buf;
|
||||
size_t pktcnt = 0;
|
||||
ngtcp2_pkt_info pi;
|
||||
@ -1709,14 +1652,21 @@ int Server::on_read(const Endpoint &ep) {
|
||||
CMSG_SPACE(sizeof(int))];
|
||||
|
||||
msghdr msg{
|
||||
.msg_name = &su,
|
||||
.msg_name = &ss,
|
||||
.msg_iov = &msg_iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = msg_ctrl,
|
||||
};
|
||||
|
||||
for (; pktcnt < 10;) {
|
||||
msg.msg_namelen = sizeof(su);
|
||||
auto start = util::timestamp();
|
||||
|
||||
for (; pktcnt < MAX_RECV_PKTS;) {
|
||||
if (util::recv_pkt_time_threshold_exceeded(
|
||||
config.cc_algo == NGTCP2_CC_ALGO_BBR, start, pktcnt)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg.msg_namelen = sizeof(ss);
|
||||
msg.msg_controllen = sizeof(msg_ctrl);
|
||||
|
||||
auto nread = recvmsg(ep.fd, &msg, 0);
|
||||
@ -1734,14 +1684,17 @@ int Server::on_read(const Endpoint &ep) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (util::prohibited_port(util::port(&su))) {
|
||||
Address remote_addr;
|
||||
remote_addr.set(reinterpret_cast<const sockaddr *>(&ss));
|
||||
|
||||
if (util::prohibited_port(remote_addr.port())) {
|
||||
++pktcnt;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
pi.ecn = msghdr_get_ecn(&msg, su.storage.ss_family);
|
||||
auto local_addr = msghdr_get_local_addr(&msg, su.storage.ss_family);
|
||||
pi.ecn = msghdr_get_ecn(&msg, ss.ss_family);
|
||||
auto local_addr = msghdr_get_local_addr(&msg, ss.ss_family);
|
||||
if (!local_addr) {
|
||||
++pktcnt;
|
||||
std::cerr << "Unable to obtain local address" << std::endl;
|
||||
@ -1753,7 +1706,7 @@ int Server::on_read(const Endpoint &ep) {
|
||||
gso_size = static_cast<size_t>(nread);
|
||||
}
|
||||
|
||||
set_port(*local_addr, ep.addr);
|
||||
local_addr->port(ep.addr.port());
|
||||
|
||||
auto data = std::span{buf.data(), static_cast<size_t>(nread)};
|
||||
|
||||
@ -1764,10 +1717,8 @@ int Server::on_read(const Endpoint &ep) {
|
||||
|
||||
if (!config.quiet) {
|
||||
std::array<char, IF_NAMESIZE> ifname;
|
||||
std::cerr << "Received packet: local="
|
||||
<< util::straddr(&local_addr->su.sa, local_addr->len)
|
||||
<< " remote=" << util::straddr(&su.sa, msg.msg_namelen)
|
||||
<< " if="
|
||||
std::cerr << "Received packet: local=" << util::straddr(*local_addr)
|
||||
<< " remote=" << util::straddr(remote_addr) << " if="
|
||||
<< if_indextoname(local_addr->ifindex, ifname.data())
|
||||
<< " ecn=0x" << std::hex << static_cast<uint32_t>(pi.ecn)
|
||||
<< std::dec << " " << datalen << " bytes" << std::endl;
|
||||
@ -1783,8 +1734,7 @@ int Server::on_read(const Endpoint &ep) {
|
||||
std::cerr << "** Simulated incoming packet loss **" << std::endl;
|
||||
}
|
||||
} else {
|
||||
read_pkt(ep, *local_addr, &su.sa, msg.msg_namelen, &pi,
|
||||
{data.data(), datalen});
|
||||
read_pkt(ep, *local_addr, remote_addr, &pi, {data.data(), datalen});
|
||||
}
|
||||
|
||||
data = data.subspan(datalen);
|
||||
@ -1795,8 +1745,7 @@ int Server::on_read(const Endpoint &ep) {
|
||||
}
|
||||
|
||||
void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data) {
|
||||
ngtcp2_version_cid vc;
|
||||
|
||||
@ -1807,7 +1756,8 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
break;
|
||||
case NGTCP2_ERR_VERSION_NEGOTIATION:
|
||||
send_version_negotiation(vc.version, {vc.scid, vc.scidlen},
|
||||
{vc.dcid, vc.dcidlen}, ep, local_addr, sa, salen);
|
||||
{vc.dcid, vc.dcidlen}, ep, local_addr,
|
||||
remote_addr);
|
||||
return;
|
||||
default:
|
||||
std::cerr << "Could not decode version and CID from QUIC packet header: "
|
||||
@ -1829,7 +1779,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
|
||||
if (!(data[0] & 0x80) && data.size() >= NGTCP2_SV_SCIDLEN + 21) {
|
||||
send_stateless_reset(data.size(), {vc.dcid, vc.dcidlen}, ep, local_addr,
|
||||
sa, salen);
|
||||
remote_addr);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1844,25 +1794,25 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
if (config.validate_addr || hd.tokenlen) {
|
||||
std::cerr << "Perform stateless address validation" << std::endl;
|
||||
if (hd.tokenlen == 0) {
|
||||
send_retry(&hd, ep, local_addr, sa, salen, data.size() * 3);
|
||||
send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hd.token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 &&
|
||||
hd.dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN) {
|
||||
send_stateless_connection_close(&hd, ep, local_addr, sa, salen);
|
||||
send_stateless_connection_close(&hd, ep, local_addr, remote_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (hd.token[0]) {
|
||||
case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2:
|
||||
switch (verify_retry_token(&ocid, &hd, sa, salen)) {
|
||||
switch (verify_retry_token(&ocid, &hd, remote_addr)) {
|
||||
case 0:
|
||||
pocid = &ocid;
|
||||
token_type = NGTCP2_TOKEN_TYPE_RETRY;
|
||||
break;
|
||||
case -1:
|
||||
send_stateless_connection_close(&hd, ep, local_addr, sa, salen);
|
||||
send_stateless_connection_close(&hd, ep, local_addr, remote_addr);
|
||||
return;
|
||||
case 1:
|
||||
hd.token = nullptr;
|
||||
@ -1872,9 +1822,9 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
|
||||
break;
|
||||
case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR:
|
||||
if (verify_token(&hd, sa, salen) != 0) {
|
||||
if (verify_token(&hd, remote_addr) != 0) {
|
||||
if (config.validate_addr) {
|
||||
send_retry(&hd, ep, local_addr, sa, salen, data.size() * 3);
|
||||
send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1889,7 +1839,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
std::cerr << "Ignore unrecognized token" << std::endl;
|
||||
}
|
||||
if (config.validate_addr) {
|
||||
send_retry(&hd, ep, local_addr, sa, salen, data.size() * 3);
|
||||
send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1900,17 +1850,17 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
}
|
||||
|
||||
auto h = std::make_unique<Handler>(loop_, this);
|
||||
if (h->init(ep, local_addr, sa, salen, &hd.scid, &hd.dcid, pocid,
|
||||
if (h->init(ep, local_addr, remote_addr, &hd.scid, &hd.dcid, pocid,
|
||||
{hd.token, hd.tokenlen}, token_type, hd.version,
|
||||
tls_ctx_) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (h->on_read(ep, local_addr, sa, salen, pi, data)) {
|
||||
switch (h->on_read(ep, local_addr, remote_addr, pi, data)) {
|
||||
case 0:
|
||||
break;
|
||||
case NETWORK_ERR_RETRY:
|
||||
send_retry(&hd, ep, local_addr, sa, salen, data.size() * 3);
|
||||
send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
@ -1941,7 +1891,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
auto h = (*handler_it).second;
|
||||
auto conn = h->conn();
|
||||
if (ngtcp2_conn_in_closing_period(conn)) {
|
||||
if (h->send_conn_close(ep, local_addr, sa, salen, pi, data) != 0) {
|
||||
if (h->send_conn_close(ep, local_addr, remote_addr, pi, data) != 0) {
|
||||
remove(h);
|
||||
}
|
||||
return;
|
||||
@ -1950,7 +1900,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto rv = h->on_read(ep, local_addr, sa, salen, pi, data); rv != 0) {
|
||||
if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); rv != 0) {
|
||||
if (rv != NETWORK_ERR_CLOSE_WAIT) {
|
||||
remove(h);
|
||||
}
|
||||
@ -1961,11 +1911,10 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
}
|
||||
|
||||
namespace {
|
||||
uint32_t generate_reserved_version(const sockaddr *sa, socklen_t salen,
|
||||
uint32_t version) {
|
||||
uint32_t generate_reserved_version(const Address &addr, uint32_t version) {
|
||||
uint32_t h = 0x811C9DC5u;
|
||||
const uint8_t *p = (const uint8_t *)sa;
|
||||
const uint8_t *ep = p + salen;
|
||||
const uint8_t *p = reinterpret_cast<const uint8_t *>(addr.as_sockaddr());
|
||||
const uint8_t *ep = p + addr.size();
|
||||
for (; p != ep; ++p) {
|
||||
h ^= *p;
|
||||
h *= 0x01000193u;
|
||||
@ -1988,13 +1937,13 @@ int Server::send_version_negotiation(uint32_t version,
|
||||
std::span<const uint8_t> scid,
|
||||
const Endpoint &ep,
|
||||
const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen) {
|
||||
const Address &remote_addr) {
|
||||
Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
|
||||
std::array<uint32_t, 1 + max_preferred_versionslen> sv;
|
||||
|
||||
auto p = std::ranges::begin(sv);
|
||||
|
||||
*p++ = generate_reserved_version(sa, salen, version);
|
||||
*p++ = generate_reserved_version(remote_addr, version);
|
||||
|
||||
if (config.preferred_versions.empty()) {
|
||||
*p++ = NGTCP2_PROTO_VER_V1;
|
||||
@ -2016,17 +1965,8 @@ int Server::send_version_negotiation(uint32_t version,
|
||||
|
||||
buf.push(as_unsigned(nwrite));
|
||||
|
||||
ngtcp2_addr laddr{
|
||||
.addr = const_cast<sockaddr *>(&local_addr.su.sa),
|
||||
.addrlen = local_addr.len,
|
||||
};
|
||||
ngtcp2_addr raddr{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
};
|
||||
|
||||
if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.data()) !=
|
||||
NETWORK_ERR_OK) {
|
||||
if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr),
|
||||
/* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2034,13 +1974,14 @@ int Server::send_version_negotiation(uint32_t version,
|
||||
}
|
||||
|
||||
int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, size_t max_pktlen) {
|
||||
const Address &local_addr, const Address &remote_addr,
|
||||
size_t max_pktlen) {
|
||||
std::array<char, NI_MAXHOST> host;
|
||||
std::array<char, NI_MAXSERV> port;
|
||||
|
||||
if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
|
||||
port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
if (auto rv = getnameinfo(remote_addr.as_sockaddr(), remote_addr.size(),
|
||||
host.data(), host.size(), port.data(), port.size(),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
rv != 0) {
|
||||
std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
|
||||
return -1;
|
||||
@ -2064,7 +2005,8 @@ int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
|
||||
auto tokenlen = ngtcp2_crypto_generate_retry_token2(
|
||||
token.data(), config.static_secret.data(), config.static_secret.size(),
|
||||
chd->version, sa, salen, &scid, &chd->dcid, t);
|
||||
chd->version, remote_addr.as_sockaddr(), remote_addr.size(), &scid,
|
||||
&chd->dcid, t);
|
||||
if (tokenlen < 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -2087,17 +2029,8 @@ int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
|
||||
buf.push(as_unsigned(nwrite));
|
||||
|
||||
ngtcp2_addr laddr{
|
||||
.addr = const_cast<sockaddr *>(&local_addr.su.sa),
|
||||
.addrlen = local_addr.len,
|
||||
};
|
||||
ngtcp2_addr raddr{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
};
|
||||
|
||||
if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.data()) !=
|
||||
NETWORK_ERR_OK) {
|
||||
if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr),
|
||||
/* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2107,8 +2040,7 @@ int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
|
||||
const Endpoint &ep,
|
||||
const Address &local_addr,
|
||||
const sockaddr *sa,
|
||||
socklen_t salen) {
|
||||
const Address &remote_addr) {
|
||||
Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE};
|
||||
|
||||
auto nwrite = ngtcp2_crypto_write_connection_close(
|
||||
@ -2121,17 +2053,8 @@ int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
|
||||
|
||||
buf.push(as_unsigned(nwrite));
|
||||
|
||||
ngtcp2_addr laddr{
|
||||
.addr = const_cast<sockaddr *>(&local_addr.su.sa),
|
||||
.addrlen = local_addr.len,
|
||||
};
|
||||
ngtcp2_addr raddr{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
};
|
||||
|
||||
if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.data()) !=
|
||||
NETWORK_ERR_OK) {
|
||||
if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr),
|
||||
/* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2140,7 +2063,7 @@ int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
|
||||
|
||||
int Server::send_stateless_reset(size_t pktlen, std::span<const uint8_t> dcid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen) {
|
||||
const Address &remote_addr) {
|
||||
if (stateless_reset_bucket_ == 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -2196,17 +2119,8 @@ int Server::send_stateless_reset(size_t pktlen, std::span<const uint8_t> dcid,
|
||||
|
||||
buf.push(as_unsigned(nwrite));
|
||||
|
||||
ngtcp2_addr laddr{
|
||||
.addr = const_cast<sockaddr *>(&local_addr.su.sa),
|
||||
.addrlen = local_addr.len,
|
||||
};
|
||||
ngtcp2_addr raddr{
|
||||
.addr = const_cast<sockaddr *>(sa),
|
||||
.addrlen = salen,
|
||||
};
|
||||
|
||||
if (send_packet(ep, laddr, raddr, /* ecn = */ 0, buf.data()) !=
|
||||
NETWORK_ERR_OK) {
|
||||
if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr),
|
||||
/* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2214,14 +2128,15 @@ int Server::send_stateless_reset(size_t pktlen, std::span<const uint8_t> dcid,
|
||||
}
|
||||
|
||||
int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
|
||||
const sockaddr *sa, socklen_t salen) {
|
||||
const Address &remote_addr) {
|
||||
int rv;
|
||||
|
||||
if (!config.quiet) {
|
||||
std::array<char, NI_MAXHOST> host;
|
||||
std::array<char, NI_MAXSERV> port;
|
||||
|
||||
if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
|
||||
if (auto rv = getnameinfo(remote_addr.as_sockaddr(), remote_addr.size(),
|
||||
host.data(), host.size(), port.data(),
|
||||
port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
rv != 0) {
|
||||
std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
|
||||
@ -2237,8 +2152,8 @@ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
|
||||
|
||||
rv = ngtcp2_crypto_verify_retry_token2(
|
||||
ocid, hd->token, hd->tokenlen, config.static_secret.data(),
|
||||
config.static_secret.size(), hd->version, sa, salen, &hd->dcid,
|
||||
10 * NGTCP2_SECONDS, t);
|
||||
config.static_secret.size(), hd->version, remote_addr.as_sockaddr(),
|
||||
remote_addr.size(), &hd->dcid, 10 * NGTCP2_SECONDS, t);
|
||||
switch (rv) {
|
||||
case 0:
|
||||
break;
|
||||
@ -2260,13 +2175,13 @@ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Server::verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
|
||||
socklen_t salen) {
|
||||
int Server::verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr) {
|
||||
std::array<char, NI_MAXHOST> host;
|
||||
std::array<char, NI_MAXSERV> port;
|
||||
|
||||
if (auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(),
|
||||
port.size(), NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
if (auto rv = getnameinfo(remote_addr.as_sockaddr(), remote_addr.size(),
|
||||
host.data(), host.size(), port.data(), port.size(),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
rv != 0) {
|
||||
std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl;
|
||||
return -1;
|
||||
@ -2280,10 +2195,10 @@ int Server::verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
|
||||
|
||||
auto t = util::system_clock_now();
|
||||
|
||||
if (ngtcp2_crypto_verify_regular_token(hd->token, hd->tokenlen,
|
||||
config.static_secret.data(),
|
||||
config.static_secret.size(), sa, salen,
|
||||
3600 * NGTCP2_SECONDS, t) != 0) {
|
||||
if (ngtcp2_crypto_verify_regular_token(
|
||||
hd->token, hd->tokenlen, config.static_secret.data(),
|
||||
config.static_secret.size(), remote_addr.as_sockaddr(),
|
||||
remote_addr.size(), 3600 * NGTCP2_SECONDS, t) != 0) {
|
||||
std::cerr << "Could not verify token" << std::endl;
|
||||
|
||||
return -1;
|
||||
@ -2559,8 +2474,7 @@ int parse_host_port(Address &dest, int af, const std::string_view &host_port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dest.len = res->ai_addrlen;
|
||||
memcpy(&dest.su, res->ai_addr, res->ai_addrlen);
|
||||
dest.set(res->ai_addr);
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
@ -2581,43 +2495,11 @@ void print_usage() {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void config_set_default(Config &config) {
|
||||
auto path = realpath(".", nullptr);
|
||||
assert(path);
|
||||
auto htdocs = std::string(path);
|
||||
free(path);
|
||||
|
||||
config = Config{
|
||||
.tx_loss_prob = 0.,
|
||||
.rx_loss_prob = 0.,
|
||||
.ciphers = util::crypto_default_ciphers(),
|
||||
.groups = util::crypto_default_groups(),
|
||||
.htdocs = std::move(htdocs),
|
||||
.mime_types_file = "/etc/mime.types"sv,
|
||||
.timeout = 30 * NGTCP2_SECONDS,
|
||||
.max_data = 1_m,
|
||||
.max_stream_data_bidi_remote = 256_k,
|
||||
.max_stream_data_uni = 256_k,
|
||||
.max_streams_bidi = 100,
|
||||
.max_streams_uni = 3,
|
||||
.max_window = 6_m,
|
||||
.max_stream_window = 6_m,
|
||||
.max_dyn_length = 20_m,
|
||||
.cc_algo = NGTCP2_CC_ALGO_CUBIC,
|
||||
.initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT,
|
||||
.handshake_timeout = UINT64_MAX,
|
||||
.ack_thresh = 2,
|
||||
.initial_pkt_num = UINT32_MAX,
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_help() {
|
||||
print_usage();
|
||||
|
||||
config_set_default(config);
|
||||
Config config;
|
||||
|
||||
std::cout << R"(
|
||||
<ADDR> Address to listen to. '*' binds to any address.
|
||||
@ -2776,12 +2658,21 @@ Options:
|
||||
Specify UDP datagram payload sizes to probe in Path MTU
|
||||
Discovery. <SIZE> must be strictly larger than 1200.
|
||||
--ech-config-file=<PATH>
|
||||
Read private key and ECHConfig from |PATH|. The file
|
||||
denoted by |PATH| must contain private key and ECHConfig
|
||||
Read private key and ECHConfig from <PATH>. The file
|
||||
denoted by <PATH> must contain private key and ECHConfig
|
||||
as described in
|
||||
https://datatracker.ietf.org/doc/html/draft-farrell-tls-pemesni.
|
||||
ECH configuration is only applied if an underlying TLS
|
||||
stack supports it.
|
||||
--no-gso Disables GSO.
|
||||
--show-stat Print the connection statistics when the connection is
|
||||
closed.
|
||||
--gso-burst=<N>
|
||||
The maximum number of packets to aggregate for GSO. If
|
||||
GSO is disabled, this is the maximum number of packets
|
||||
to send per an event loop in a single connection. It
|
||||
defaults to 0, which means it is not limited by the
|
||||
configuration.
|
||||
-h, --help Display this help and exit.
|
||||
|
||||
---
|
||||
@ -2804,8 +2695,6 @@ Options:
|
||||
std::ofstream keylog_file;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
config_set_default(config);
|
||||
|
||||
if (argc) {
|
||||
prog = basename(argv[0]);
|
||||
}
|
||||
@ -2854,6 +2743,9 @@ int main(int argc, char **argv) {
|
||||
{"initial-pkt-num", required_argument, &flag, 31},
|
||||
{"pmtud-probes", required_argument, &flag, 32},
|
||||
{"ech-config-file", required_argument, &flag, 33},
|
||||
{"no-gso", no_argument, &flag, 35},
|
||||
{"show-stat", no_argument, &flag, 36},
|
||||
{"gso-burst", required_argument, &flag, 37},
|
||||
{},
|
||||
};
|
||||
|
||||
@ -3060,9 +2952,9 @@ int main(int argc, char **argv) {
|
||||
if (auto n = util::parse_uint_iec(optarg); !n) {
|
||||
std::cerr << "max-udp-payload-size: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n > 64_k) {
|
||||
std::cerr << "max-udp-payload-size: must not exceed 65536"
|
||||
<< std::endl;
|
||||
} else if (*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) {
|
||||
std::cerr << "max-udp-payload-size: must not exceed "
|
||||
<< NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
config.max_udp_payload_size = *n;
|
||||
@ -3192,10 +3084,12 @@ int main(int argc, char **argv) {
|
||||
if (auto n = util::parse_uint_iec(s); !n) {
|
||||
std::cerr << "pmtud-probes: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (*n <= 1200 || *n >= 64_k) {
|
||||
std::cerr
|
||||
<< "pmtud-probes: must be in range [1201, 65535], inclusive."
|
||||
<< std::endl;
|
||||
} else if (*n <= NGTCP2_MAX_UDP_PAYLOAD_SIZE ||
|
||||
*n > NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE) {
|
||||
std::cerr << "pmtud-probes: must be in range ["
|
||||
<< NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1 << ", "
|
||||
<< NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE << "], inclusive."
|
||||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
config.pmtud_probes.push_back(static_cast<uint16_t>(*n));
|
||||
@ -3207,11 +3101,37 @@ int main(int argc, char **argv) {
|
||||
// --ech-config-file
|
||||
ech_config_file = optarg;
|
||||
break;
|
||||
case 35:
|
||||
// --no-gso
|
||||
config.no_gso = true;
|
||||
break;
|
||||
case 36:
|
||||
// --show-stat
|
||||
config.show_stat = true;
|
||||
break;
|
||||
case 37: {
|
||||
// --gso-burst
|
||||
auto n = util::parse_uint(optarg);
|
||||
if (!n) {
|
||||
std::cerr << "gso-burst: invalid argument" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (*n > 64) {
|
||||
std::cerr << "gso-burst: must be in range [0, 64], inclusive."
|
||||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
config.gso_burst = static_cast<size_t>(*n);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind < 4) {
|
||||
@ -3265,7 +3185,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
std::cerr << "Using document root " << config.htdocs << std::endl;
|
||||
|
||||
auto ev_loop_d = defer(ev_loop_destroy, EV_DEFAULT);
|
||||
auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); });
|
||||
|
||||
auto keylog_filename = getenv("SSLKEYLOGFILE");
|
||||
if (keylog_filename) {
|
||||
|
||||
65
deps/ngtcp2/ngtcp2/examples/h09server.h
vendored
65
deps/ngtcp2/ngtcp2/examples/h09server.h
vendored
@ -52,14 +52,6 @@
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct HTTPHeader {
|
||||
HTTPHeader(const std::string_view &name, const std::string_view &value)
|
||||
: name(name), value(value) {}
|
||||
|
||||
std::string_view name;
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
class Handler;
|
||||
struct FileEntry;
|
||||
|
||||
@ -79,7 +71,7 @@ struct Stream {
|
||||
nghttp3_buf respbuf;
|
||||
http_parser htp;
|
||||
// eos gets true when one HTTP request message is seen.
|
||||
bool eos;
|
||||
bool eos{};
|
||||
};
|
||||
|
||||
struct StreamIDLess {
|
||||
@ -94,8 +86,8 @@ class Server;
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Server *server;
|
||||
int fd;
|
||||
Server *server{};
|
||||
int fd{};
|
||||
};
|
||||
|
||||
class Handler : public HandlerBase {
|
||||
@ -103,19 +95,19 @@ public:
|
||||
Handler(struct ev_loop *loop, Server *server);
|
||||
~Handler();
|
||||
|
||||
int init(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
|
||||
const ngtcp2_cid *ocid, std::span<const uint8_t> token,
|
||||
ngtcp2_token_type token_type, uint32_t version,
|
||||
TLSServerContext &tls_ctx);
|
||||
int init(const Endpoint &ep, const Address &local_addr,
|
||||
const Address &remote_addr, const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid, const ngtcp2_cid *ocid,
|
||||
std::span<const uint8_t> token, ngtcp2_token_type token_type,
|
||||
uint32_t version, TLSServerContext &tls_ctx);
|
||||
|
||||
int on_read(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
int on_read(const Endpoint &ep, const Address &local_addr,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int on_write();
|
||||
int write_streams();
|
||||
int feed_data(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
void update_timer();
|
||||
int handle_expiry();
|
||||
@ -135,8 +127,8 @@ public:
|
||||
int handle_error();
|
||||
int send_conn_close();
|
||||
int send_conn_close(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi, std::span<const uint8_t> data);
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
|
||||
int update_key(uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
@ -166,8 +158,8 @@ private:
|
||||
Server *server_;
|
||||
ev_io wev_;
|
||||
ev_timer timer_;
|
||||
FILE *qlog_;
|
||||
ngtcp2_cid scid_;
|
||||
FILE *qlog_{};
|
||||
ngtcp2_cid scid_{};
|
||||
std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_;
|
||||
std::set<Stream *, StreamIDLess> sendq_;
|
||||
// conn_closebuf_ contains a packet which contains CONNECTION_CLOSE.
|
||||
@ -175,14 +167,14 @@ private:
|
||||
// packet in draining period.
|
||||
std::unique_ptr<Buffer> conn_closebuf_;
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
size_t nkey_update_{};
|
||||
bool no_gso_;
|
||||
struct {
|
||||
size_t bytes_recv;
|
||||
size_t bytes_sent;
|
||||
size_t num_pkts_recv;
|
||||
size_t next_pkts_recv;
|
||||
} close_wait_;
|
||||
size_t next_pkts_recv = 1;
|
||||
} close_wait_{};
|
||||
|
||||
struct {
|
||||
bool send_blocked;
|
||||
@ -195,8 +187,8 @@ private:
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::unique_ptr<uint8_t[]> data;
|
||||
} tx_;
|
||||
} tx_{};
|
||||
std::array<uint8_t, 64_k> txbuf_;
|
||||
};
|
||||
|
||||
class Server {
|
||||
@ -210,26 +202,25 @@ public:
|
||||
|
||||
int on_read(const Endpoint &ep);
|
||||
void read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int send_version_negotiation(uint32_t version, std::span<const uint8_t> dcid,
|
||||
std::span<const uint8_t> scid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
const Address &local_addr, const sockaddr *sa, socklen_t salen,
|
||||
const Address &local_addr, const Address &remote_addr,
|
||||
size_t max_pktlen);
|
||||
int send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
|
||||
const Endpoint &ep,
|
||||
const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int send_stateless_reset(size_t pktlen, std::span<const uint8_t> dcid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
|
||||
socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr);
|
||||
int send_packet(const Endpoint &ep, const ngtcp2_addr &local_addr,
|
||||
const ngtcp2_addr &remote_addr, unsigned int ecn,
|
||||
std::span<const uint8_t> data);
|
||||
@ -251,7 +242,7 @@ private:
|
||||
TLSServerContext &tls_ctx_;
|
||||
ev_signal sigintev_;
|
||||
ev_timer stateless_reset_regen_timer_;
|
||||
size_t stateless_reset_bucket_;
|
||||
size_t stateless_reset_bucket_{NGTCP2_STATELESS_RESET_BURST};
|
||||
};
|
||||
|
||||
#endif // !defined(H09SERVER_H)
|
||||
|
||||
40
deps/ngtcp2/ngtcp2/examples/network.h
vendored
40
deps/ngtcp2/ngtcp2/examples/network.h
vendored
@ -43,6 +43,7 @@
|
||||
#endif // defined(HAVE_ARPA_INET_H)
|
||||
|
||||
#include <array>
|
||||
#include <variant>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
@ -50,29 +51,40 @@ namespace ngtcp2 {
|
||||
|
||||
enum network_error {
|
||||
NETWORK_ERR_OK = 0,
|
||||
NETWORK_ERR_FATAL = -10,
|
||||
NETWORK_ERR_SEND_BLOCKED = -11,
|
||||
NETWORK_ERR_CLOSE_WAIT = -12,
|
||||
NETWORK_ERR_RETRY = -13,
|
||||
NETWORK_ERR_DROP_CONN = -14,
|
||||
};
|
||||
|
||||
union in_addr_union {
|
||||
in_addr in;
|
||||
in6_addr in6;
|
||||
};
|
||||
using InAddr = std::variant<std::monostate, in_addr, in6_addr>;
|
||||
|
||||
union sockaddr_union {
|
||||
sockaddr_storage storage;
|
||||
sockaddr sa;
|
||||
sockaddr_in6 in6;
|
||||
sockaddr_in in;
|
||||
};
|
||||
using Sockaddr = std::variant<std::monostate, sockaddr_in, sockaddr_in6>;
|
||||
|
||||
struct Address {
|
||||
socklen_t len;
|
||||
union sockaddr_union su;
|
||||
uint32_t ifindex;
|
||||
// as_sockaddr returns the pointer to the stored address casted to
|
||||
// const sockaddr *.
|
||||
[[nodiscard]] const sockaddr *as_sockaddr() const;
|
||||
[[nodiscard]] sockaddr *as_sockaddr();
|
||||
// family returns the address family.
|
||||
[[nodiscard]] int family() const;
|
||||
// port returns the port.
|
||||
[[nodiscard]] uint16_t port() const;
|
||||
// port sets |port| to this address.
|
||||
void port(uint16_t port);
|
||||
// set stores |sa| to this address. The address family is
|
||||
// determined by |sa|->sa_family, and |sa| must point to the memory
|
||||
// that contains valid object which is either sockaddr_in or
|
||||
// sockaddr_in6.
|
||||
void set(const sockaddr *sa);
|
||||
// size returns the size of the stored address.
|
||||
[[nodiscard]] socklen_t size() const;
|
||||
// empty returns true if this address does not contain any
|
||||
// meaningful address.
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
Sockaddr skaddr;
|
||||
uint32_t ifindex{};
|
||||
};
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
537
deps/ngtcp2/ngtcp2/examples/server.cc
vendored
537
deps/ngtcp2/ngtcp2/examples/server.cc
vendored
File diff suppressed because it is too large
Load Diff
75
deps/ngtcp2/ngtcp2/examples/server.h
vendored
75
deps/ngtcp2/ngtcp2/examples/server.h
vendored
@ -51,14 +51,6 @@
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
struct HTTPHeader {
|
||||
HTTPHeader(const std::string_view &name, const std::string_view &value)
|
||||
: name(name), value(value) {}
|
||||
|
||||
std::string_view name;
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
class Handler;
|
||||
struct FileEntry;
|
||||
|
||||
@ -83,15 +75,15 @@ struct Stream {
|
||||
std::string authority;
|
||||
std::string status_resp_body;
|
||||
// data is a pointer to the memory which maps file denoted by fd.
|
||||
uint8_t *data;
|
||||
uint8_t *data{};
|
||||
// datalen is the length of mapped file by data.
|
||||
uint64_t datalen;
|
||||
uint64_t datalen{};
|
||||
// dynresp is true if dynamic data response is enabled.
|
||||
bool dynresp;
|
||||
bool dynresp{};
|
||||
// dyndataleft is the number of dynamic data left to send.
|
||||
uint64_t dyndataleft;
|
||||
uint64_t dyndataleft{};
|
||||
// dynbuflen is the number of bytes in-flight.
|
||||
uint64_t dynbuflen;
|
||||
uint64_t dynbuflen{};
|
||||
};
|
||||
|
||||
class Server;
|
||||
@ -100,8 +92,8 @@ class Server;
|
||||
struct Endpoint {
|
||||
Address addr;
|
||||
ev_io rev;
|
||||
Server *server;
|
||||
int fd;
|
||||
Server *server{};
|
||||
int fd{};
|
||||
};
|
||||
|
||||
class Handler : public HandlerBase {
|
||||
@ -109,19 +101,19 @@ public:
|
||||
Handler(struct ev_loop *loop, Server *server);
|
||||
~Handler();
|
||||
|
||||
int init(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
|
||||
const ngtcp2_cid *ocid, std::span<const uint8_t> token,
|
||||
ngtcp2_token_type token_type, uint32_t version,
|
||||
TLSServerContext &tls_ctx);
|
||||
int init(const Endpoint &ep, const Address &local_addr,
|
||||
const Address &remote_addr, const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid, const ngtcp2_cid *ocid,
|
||||
std::span<const uint8_t> token, ngtcp2_token_type token_type,
|
||||
uint32_t version, TLSServerContext &tls_ctx);
|
||||
|
||||
int on_read(const Endpoint &ep, const Address &local_addr, const sockaddr *sa,
|
||||
socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
int on_read(const Endpoint &ep, const Address &local_addr,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int on_write();
|
||||
int write_streams();
|
||||
int feed_data(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
void update_timer();
|
||||
int handle_expiry();
|
||||
@ -140,8 +132,8 @@ public:
|
||||
int handle_error();
|
||||
int send_conn_close();
|
||||
int send_conn_close(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen,
|
||||
const ngtcp2_pkt_info *pi, std::span<const uint8_t> data);
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
|
||||
int update_key(uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
@ -185,23 +177,23 @@ private:
|
||||
Server *server_;
|
||||
ev_io wev_;
|
||||
ev_timer timer_;
|
||||
FILE *qlog_;
|
||||
ngtcp2_cid scid_;
|
||||
nghttp3_conn *httpconn_;
|
||||
FILE *qlog_{};
|
||||
ngtcp2_cid scid_{};
|
||||
nghttp3_conn *httpconn_{};
|
||||
std::unordered_map<int64_t, std::unique_ptr<Stream>> streams_;
|
||||
// conn_closebuf_ contains a packet which contains CONNECTION_CLOSE.
|
||||
// This packet is repeatedly sent as a response to the incoming
|
||||
// packet in draining period.
|
||||
std::unique_ptr<Buffer> conn_closebuf_;
|
||||
// nkey_update_ is the number of key update occurred.
|
||||
size_t nkey_update_;
|
||||
size_t nkey_update_{};
|
||||
bool no_gso_;
|
||||
struct {
|
||||
size_t bytes_recv;
|
||||
size_t bytes_sent;
|
||||
size_t num_pkts_recv;
|
||||
size_t next_pkts_recv;
|
||||
} close_wait_;
|
||||
size_t next_pkts_recv = 1;
|
||||
} close_wait_{};
|
||||
|
||||
struct {
|
||||
bool send_blocked;
|
||||
@ -214,8 +206,8 @@ private:
|
||||
std::span<const uint8_t> data;
|
||||
size_t gso_size;
|
||||
} blocked;
|
||||
std::unique_ptr<uint8_t[]> data;
|
||||
} tx_;
|
||||
} tx_{};
|
||||
std::array<uint8_t, 64_k> txbuf_;
|
||||
};
|
||||
|
||||
class Server {
|
||||
@ -229,26 +221,25 @@ public:
|
||||
|
||||
int on_read(const Endpoint &ep);
|
||||
void read_pkt(const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen, const ngtcp2_pkt_info *pi,
|
||||
const Address &remote_addr, const ngtcp2_pkt_info *pi,
|
||||
std::span<const uint8_t> data);
|
||||
int send_version_negotiation(uint32_t version, std::span<const uint8_t> dcid,
|
||||
std::span<const uint8_t> scid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep,
|
||||
const Address &local_addr, const sockaddr *sa, socklen_t salen,
|
||||
const Address &local_addr, const Address &remote_addr,
|
||||
size_t max_pktlen);
|
||||
int send_stateless_connection_close(const ngtcp2_pkt_hd *chd,
|
||||
const Endpoint &ep,
|
||||
const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int send_stateless_reset(size_t pktlen, std::span<const uint8_t> dcid,
|
||||
const Endpoint &ep, const Address &local_addr,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd,
|
||||
const sockaddr *sa, socklen_t salen);
|
||||
int verify_token(const ngtcp2_pkt_hd *hd, const sockaddr *sa,
|
||||
socklen_t salen);
|
||||
const Address &remote_addr);
|
||||
int verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr);
|
||||
int send_packet(const Endpoint &ep, const ngtcp2_addr &local_addr,
|
||||
const ngtcp2_addr &remote_addr, unsigned int ecn,
|
||||
std::span<const uint8_t> data);
|
||||
@ -270,7 +261,7 @@ private:
|
||||
TLSServerContext &tls_ctx_;
|
||||
ev_signal sigintev_;
|
||||
ev_timer stateless_reset_regen_timer_;
|
||||
size_t stateless_reset_bucket_;
|
||||
size_t stateless_reset_bucket_{NGTCP2_STATELESS_RESET_BURST};
|
||||
};
|
||||
|
||||
#endif // !defined(SERVER_H)
|
||||
|
||||
10
deps/ngtcp2/ngtcp2/examples/server_base.cc
vendored
10
deps/ngtcp2/ngtcp2/examples/server_base.cc
vendored
@ -35,20 +35,24 @@ using namespace ngtcp2;
|
||||
extern Config config;
|
||||
|
||||
Buffer::Buffer(const uint8_t *data, size_t datalen)
|
||||
: buf{data, data + datalen}, begin(buf.data()), tail(begin + datalen) {}
|
||||
Buffer::Buffer(size_t datalen) : buf(datalen), begin(buf.data()), tail(begin) {}
|
||||
: buf{data, data + datalen}, begin{buf.data()}, tail{begin + datalen} {}
|
||||
Buffer::Buffer(size_t datalen) : buf(datalen), begin{buf.data()}, tail{begin} {}
|
||||
|
||||
static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
||||
auto h = static_cast<HandlerBase *>(conn_ref->user_data);
|
||||
return h->conn();
|
||||
}
|
||||
|
||||
HandlerBase::HandlerBase() : conn_ref_{get_conn, this}, conn_(nullptr) {
|
||||
HandlerBase::HandlerBase() : conn_ref_{get_conn, this} {
|
||||
ngtcp2_ccerr_default(&last_error_);
|
||||
}
|
||||
|
||||
HandlerBase::~HandlerBase() {
|
||||
if (conn_) {
|
||||
if (config.show_stat) {
|
||||
debug::print_conn_info(conn_);
|
||||
}
|
||||
|
||||
ngtcp2_conn_del(conn_);
|
||||
}
|
||||
}
|
||||
|
||||
86
deps/ngtcp2/ngtcp2/examples/server_base.h
vendored
86
deps/ngtcp2/ngtcp2/examples/server_base.h
vendored
@ -51,93 +51,93 @@ struct Config {
|
||||
Address preferred_ipv4_addr;
|
||||
Address preferred_ipv6_addr;
|
||||
// tx_loss_prob is probability of losing outgoing packet.
|
||||
double tx_loss_prob;
|
||||
double tx_loss_prob{};
|
||||
// rx_loss_prob is probability of losing incoming packet.
|
||||
double rx_loss_prob;
|
||||
double rx_loss_prob{};
|
||||
// ciphers is the list of enabled ciphers.
|
||||
const char *ciphers;
|
||||
const char *ciphers{util::crypto_default_ciphers()};
|
||||
// groups is the list of supported groups.
|
||||
const char *groups;
|
||||
const char *groups{util::crypto_default_groups()};
|
||||
// htdocs is a root directory to serve documents.
|
||||
std::string htdocs;
|
||||
std::string htdocs{util::realpath(".")};
|
||||
// mime_types_file is a path to "MIME media types and the
|
||||
// extensions" file. Ubuntu mime-support package includes it in
|
||||
// /etc/mime/types.
|
||||
std::string_view mime_types_file;
|
||||
std::string_view mime_types_file{"/etc/mime.types"sv};
|
||||
// mime_types maps file extension to MIME media type.
|
||||
std::unordered_map<std::string, std::string> mime_types;
|
||||
// port is the port number which server listens on for incoming
|
||||
// connections.
|
||||
uint16_t port;
|
||||
uint16_t port{};
|
||||
// quiet suppresses the output normally shown except for the error
|
||||
// messages.
|
||||
bool quiet;
|
||||
bool quiet{};
|
||||
// timeout is an idle timeout for QUIC connection.
|
||||
ngtcp2_duration timeout;
|
||||
ngtcp2_duration timeout{30 * NGTCP2_SECONDS};
|
||||
// show_secret is true if transport secrets should be printed out.
|
||||
bool show_secret;
|
||||
bool show_secret{};
|
||||
// validate_addr is true if server requires address validation.
|
||||
bool validate_addr;
|
||||
bool validate_addr{};
|
||||
// early_response is true if server starts sending response when it
|
||||
// receives HTTP header fields without waiting for request body. If
|
||||
// HTTP response data is written before receiving request body,
|
||||
// STOP_SENDING is sent.
|
||||
bool early_response;
|
||||
bool early_response{};
|
||||
// verify_client is true if server verifies client with X.509
|
||||
// certificate based authentication.
|
||||
bool verify_client;
|
||||
bool verify_client{};
|
||||
// qlog_dir is the path to directory where qlog is stored.
|
||||
std::string_view qlog_dir;
|
||||
// no_quic_dump is true if hexdump of QUIC STREAM and CRYPTO data
|
||||
// should be disabled.
|
||||
bool no_quic_dump;
|
||||
bool no_quic_dump{};
|
||||
// no_http_dump is true if hexdump of HTTP response body should be
|
||||
// disabled.
|
||||
bool no_http_dump;
|
||||
bool no_http_dump{};
|
||||
// max_data is the initial connection-level flow control window.
|
||||
uint64_t max_data;
|
||||
uint64_t max_data{1_m};
|
||||
// max_stream_data_bidi_local is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the local endpoint
|
||||
// initiates.
|
||||
uint64_t max_stream_data_bidi_local;
|
||||
uint64_t max_stream_data_bidi_local{};
|
||||
// max_stream_data_bidi_remote is the initial stream-level flow
|
||||
// control window for a bidirectional stream that the remote
|
||||
// endpoint initiates.
|
||||
uint64_t max_stream_data_bidi_remote;
|
||||
uint64_t max_stream_data_bidi_remote{256_k};
|
||||
// max_stream_data_uni is the initial stream-level flow control
|
||||
// window for a unidirectional stream.
|
||||
uint64_t max_stream_data_uni;
|
||||
uint64_t max_stream_data_uni{256_k};
|
||||
// max_streams_bidi is the number of the concurrent bidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_bidi;
|
||||
uint64_t max_streams_bidi{100};
|
||||
// max_streams_uni is the number of the concurrent unidirectional
|
||||
// streams.
|
||||
uint64_t max_streams_uni;
|
||||
uint64_t max_streams_uni{3};
|
||||
// max_window is the maximum connection-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_window;
|
||||
uint64_t max_window{6_m};
|
||||
// max_stream_window is the maximum stream-level flow control window
|
||||
// size if auto-tuning is enabled.
|
||||
uint64_t max_stream_window;
|
||||
uint64_t max_stream_window{6_m};
|
||||
// max_dyn_length is the maximum length of dynamically generated
|
||||
// response.
|
||||
uint64_t max_dyn_length;
|
||||
uint64_t max_dyn_length{20_m};
|
||||
// static_secret is used to derive keying materials for Retry and
|
||||
// Stateless Retry token.
|
||||
std::array<uint8_t, 32> static_secret;
|
||||
// cc_algo is the congestion controller algorithm.
|
||||
ngtcp2_cc_algo cc_algo;
|
||||
ngtcp2_cc_algo cc_algo{NGTCP2_CC_ALGO_CUBIC};
|
||||
// initial_rtt is an initial RTT.
|
||||
ngtcp2_duration initial_rtt;
|
||||
ngtcp2_duration initial_rtt{NGTCP2_DEFAULT_INITIAL_RTT};
|
||||
// max_udp_payload_size is the maximum UDP payload size that server
|
||||
// transmits.
|
||||
size_t max_udp_payload_size;
|
||||
size_t max_udp_payload_size{};
|
||||
// send_trailers controls whether server sends trailer fields or
|
||||
// not.
|
||||
bool send_trailers;
|
||||
bool send_trailers{};
|
||||
// handshake_timeout is the period of time before giving up QUIC
|
||||
// connection establishment.
|
||||
ngtcp2_duration handshake_timeout;
|
||||
ngtcp2_duration handshake_timeout{UINT64_MAX};
|
||||
// preferred_versions includes QUIC versions in the order of
|
||||
// preference. Server negotiates one of those versions if a client
|
||||
// initially selects a less preferred version.
|
||||
@ -147,21 +147,39 @@ struct Config {
|
||||
// transport_parameter.
|
||||
std::vector<uint32_t> available_versions;
|
||||
// no_pmtud disables Path MTU Discovery.
|
||||
bool no_pmtud;
|
||||
bool no_pmtud{};
|
||||
// ack_thresh is the minimum number of the received ACK eliciting
|
||||
// packets that triggers immediate acknowledgement.
|
||||
size_t ack_thresh;
|
||||
size_t ack_thresh{2};
|
||||
// initial_pkt_num is the initial packet number for each packet
|
||||
// number space. If it is set to UINT32_MAX, it is chosen randomly.
|
||||
uint32_t initial_pkt_num;
|
||||
uint32_t initial_pkt_num{UINT32_MAX};
|
||||
// pmtud_probes is the array of UDP datagram payload size to probes.
|
||||
std::vector<uint16_t> pmtud_probes;
|
||||
// ech_config contains server-side ECH configuration.
|
||||
util::ECHServerConfig ech_config;
|
||||
util::ECHServerConfig ech_config{};
|
||||
// origin_list contains a payload of ORIGIN frame.
|
||||
std::optional<std::vector<uint8_t>> origin_list;
|
||||
// no_gso disables GSO.
|
||||
bool no_gso{};
|
||||
// show_stat, if true, displays the connection statistics when the
|
||||
// connection is closed.
|
||||
bool show_stat{};
|
||||
// gso_burst is the number of packets to aggregate in GSO. 0 means
|
||||
// it is not limited by the configuration.
|
||||
size_t gso_burst{};
|
||||
};
|
||||
|
||||
struct HTTPHeader {
|
||||
HTTPHeader(const std::string_view &name, const std::string_view &value)
|
||||
: name{name}, value{value} {}
|
||||
|
||||
std::string_view name;
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
inline constexpr size_t NGTCP2_STATELESS_RESET_BURST = 100;
|
||||
|
||||
struct Buffer {
|
||||
Buffer(const uint8_t *data, size_t datalen);
|
||||
explicit Buffer(size_t datalen);
|
||||
@ -197,7 +215,7 @@ public:
|
||||
protected:
|
||||
ngtcp2_crypto_conn_ref conn_ref_;
|
||||
TLSServerSession tls_session_;
|
||||
ngtcp2_conn *conn_;
|
||||
ngtcp2_conn *conn_{};
|
||||
ngtcp2_ccerr last_error_;
|
||||
};
|
||||
|
||||
|
||||
280
deps/ngtcp2/ngtcp2/examples/shared.cc
vendored
280
deps/ngtcp2/ngtcp2/examples/shared.cc
vendored
@ -170,10 +170,9 @@ std::optional<Address> msghdr_get_local_addr(msghdr *msg, int family) {
|
||||
in_pktinfo pktinfo;
|
||||
memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo));
|
||||
Address res{
|
||||
.len = sizeof(res.su.in),
|
||||
.ifindex = static_cast<uint32_t>(pktinfo.ipi_ifindex),
|
||||
};
|
||||
auto &sa = res.su.in;
|
||||
auto &sa = res.skaddr.emplace<sockaddr_in>();
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_addr = pktinfo.ipi_addr;
|
||||
return res;
|
||||
@ -186,10 +185,9 @@ std::optional<Address> msghdr_get_local_addr(msghdr *msg, int family) {
|
||||
in6_pktinfo pktinfo;
|
||||
memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo));
|
||||
Address res{
|
||||
.len = sizeof(res.su.in6),
|
||||
.ifindex = static_cast<uint32_t>(pktinfo.ipi6_ifindex),
|
||||
};
|
||||
auto &sa = res.su.in6;
|
||||
auto &sa = res.skaddr.emplace<sockaddr_in6>();
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_addr = pktinfo.ipi6_addr;
|
||||
return res;
|
||||
@ -216,64 +214,52 @@ size_t msghdr_get_udp_gro(msghdr *msg) {
|
||||
return static_cast<size_t>(gso_size);
|
||||
}
|
||||
|
||||
void set_port(Address &dst, const Address &src) {
|
||||
switch (dst.su.storage.ss_family) {
|
||||
case AF_INET:
|
||||
assert(AF_INET == src.su.storage.ss_family);
|
||||
dst.su.in.sin_port = src.su.in.sin_port;
|
||||
return;
|
||||
case AF_INET6:
|
||||
assert(AF_INET6 == src.su.storage.ss_family);
|
||||
dst.su.in6.sin6_port = src.su.in6.sin6_port;
|
||||
return;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_RTNETLINK_H
|
||||
|
||||
struct nlmsg {
|
||||
nlmsghdr hdr;
|
||||
rtmsg msg;
|
||||
rtattr dst;
|
||||
in_addr_union dst_addr;
|
||||
uint8_t dst_addr[sizeof(sockaddr_storage)];
|
||||
};
|
||||
|
||||
namespace {
|
||||
int send_netlink_msg(int fd, const Address &remote_addr, uint32_t seq) {
|
||||
nlmsg nlmsg{
|
||||
.hdr =
|
||||
{
|
||||
.nlmsg_type = RTM_GETROUTE,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
|
||||
.nlmsg_seq = seq,
|
||||
},
|
||||
.msg =
|
||||
{
|
||||
.rtm_family = static_cast<unsigned char>(remote_addr.su.sa.sa_family),
|
||||
.rtm_protocol = RTPROT_KERNEL,
|
||||
},
|
||||
.dst =
|
||||
{
|
||||
.rta_type = RTA_DST,
|
||||
},
|
||||
.hdr{
|
||||
.nlmsg_type = RTM_GETROUTE,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
|
||||
.nlmsg_seq = seq,
|
||||
},
|
||||
.msg{
|
||||
.rtm_family = static_cast<unsigned char>(remote_addr.family()),
|
||||
.rtm_protocol = RTPROT_KERNEL,
|
||||
},
|
||||
.dst{
|
||||
.rta_type = RTA_DST,
|
||||
},
|
||||
};
|
||||
|
||||
switch (remote_addr.su.sa.sa_family) {
|
||||
case AF_INET:
|
||||
nlmsg.dst.rta_len = RTA_LENGTH(sizeof(remote_addr.su.in.sin_addr));
|
||||
memcpy(RTA_DATA(&nlmsg.dst), &remote_addr.su.in.sin_addr,
|
||||
sizeof(remote_addr.su.in.sin_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
nlmsg.dst.rta_len = RTA_LENGTH(sizeof(remote_addr.su.in6.sin6_addr));
|
||||
memcpy(RTA_DATA(&nlmsg.dst), &remote_addr.su.in6.sin6_addr,
|
||||
sizeof(remote_addr.su.in6.sin6_addr));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
std::visit(
|
||||
[&nlmsg](auto &&arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in>) {
|
||||
nlmsg.dst.rta_len = RTA_LENGTH(sizeof(arg.sin_addr));
|
||||
memcpy(RTA_DATA(&nlmsg.dst), &arg.sin_addr, sizeof(arg.sin_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in6>) {
|
||||
nlmsg.dst.rta_len = RTA_LENGTH(sizeof(arg.sin6_addr));
|
||||
memcpy(RTA_DATA(&nlmsg.dst), &arg.sin6_addr, sizeof(arg.sin6_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
abort();
|
||||
},
|
||||
remote_addr.skaddr);
|
||||
|
||||
nlmsg.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(nlmsg.msg) + nlmsg.dst.rta_len);
|
||||
|
||||
@ -309,7 +295,7 @@ int send_netlink_msg(int fd, const Address &remote_addr, uint32_t seq) {
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int recv_netlink_msg(in_addr_union &iau, int fd, uint32_t seq) {
|
||||
int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) {
|
||||
std::array<uint8_t, 8192> buf;
|
||||
iovec iov = {
|
||||
.iov_base = buf.data(),
|
||||
@ -334,8 +320,6 @@ int recv_netlink_msg(in_addr_union &iau, int fd, uint32_t seq) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t in_addrlen = 0;
|
||||
|
||||
for (auto hdr = reinterpret_cast<nlmsghdr *>(buf.data());
|
||||
NLMSG_OK(hdr, nread); hdr = NLMSG_NEXT(hdr, nread)) {
|
||||
if (seq != hdr->nlmsg_seq) {
|
||||
@ -372,28 +356,42 @@ int recv_netlink_msg(in_addr_union &iau, int fd, uint32_t seq) {
|
||||
}
|
||||
|
||||
switch (static_cast<rtmsg *>(NLMSG_DATA(hdr))->rtm_family) {
|
||||
case AF_INET:
|
||||
in_addrlen = sizeof(in_addr);
|
||||
case AF_INET: {
|
||||
constexpr auto in_addrlen = sizeof(in_addr);
|
||||
if (RTA_LENGTH(in_addrlen) != rta->rta_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
in_addr addr;
|
||||
memcpy(&addr, RTA_DATA(rta), in_addrlen);
|
||||
|
||||
ia.emplace<in_addr>(addr);
|
||||
|
||||
break;
|
||||
case AF_INET6:
|
||||
in_addrlen = sizeof(in6_addr);
|
||||
}
|
||||
case AF_INET6: {
|
||||
constexpr auto in_addrlen = sizeof(in6_addr);
|
||||
if (RTA_LENGTH(in_addrlen) != rta->rta_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
in6_addr addr;
|
||||
memcpy(&addr, RTA_DATA(rta), in_addrlen);
|
||||
|
||||
ia.emplace<in6_addr>(addr);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (RTA_LENGTH(in_addrlen) != rta->rta_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&iau, RTA_DATA(rta), in_addrlen);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_addrlen == 0) {
|
||||
if (in_addr_empty(ia)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -459,7 +457,7 @@ int recv_netlink_msg(in_addr_union &iau, int fd, uint32_t seq) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int get_local_addr(in_addr_union &iau, const Address &remote_addr) {
|
||||
int get_local_addr(InAddr &ia, const Address &remote_addr) {
|
||||
sockaddr_nl sa{
|
||||
.nl_family = AF_NETLINK,
|
||||
};
|
||||
@ -471,7 +469,7 @@ int get_local_addr(in_addr_union &iau, const Address &remote_addr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto fd_d = defer(close, fd);
|
||||
auto fd_d = defer([fd] { close(fd); });
|
||||
|
||||
if (bind(fd, reinterpret_cast<sockaddr *>(&sa), sizeof(sa)) == -1) {
|
||||
std::cerr << "bind: Could not bind netlink socket: " << strerror(errno)
|
||||
@ -485,23 +483,163 @@ int get_local_addr(in_addr_union &iau, const Address &remote_addr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return recv_netlink_msg(iau, fd, seq);
|
||||
return recv_netlink_msg(ia, fd, seq);
|
||||
}
|
||||
|
||||
#endif // defined(HAVE_LINUX_NETLINK_H)
|
||||
|
||||
bool addreq(const sockaddr *sa, const in_addr_union &iau) {
|
||||
bool addreq(const Address &addr, const InAddr &ia) {
|
||||
return std::visit(
|
||||
[&ia](auto &&arg) -> bool {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in>) {
|
||||
auto rhs = std::get_if<in_addr>(&ia);
|
||||
|
||||
return rhs && memcmp(&arg.sin_addr, rhs, sizeof(*rhs)) == 0;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in6>) {
|
||||
auto rhs = std::get_if<in6_addr>(&ia);
|
||||
|
||||
return rhs && memcmp(&arg.sin6_addr, rhs, sizeof(*rhs)) == 0;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
abort();
|
||||
},
|
||||
addr.skaddr);
|
||||
}
|
||||
|
||||
const void *in_addr_get_ptr(const InAddr &ia) {
|
||||
return std::visit(
|
||||
[](auto &&arg) {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(arg)>,
|
||||
std::monostate>) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return reinterpret_cast<const void *>(&arg);
|
||||
},
|
||||
ia);
|
||||
}
|
||||
|
||||
bool in_addr_empty(const InAddr &ia) {
|
||||
return std::holds_alternative<std::monostate>(ia);
|
||||
}
|
||||
|
||||
const sockaddr *as_sockaddr(const Sockaddr &skaddr) {
|
||||
return std::visit(
|
||||
[](auto &&arg) {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(arg)>,
|
||||
std::monostate>) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return reinterpret_cast<const sockaddr *>(&arg);
|
||||
},
|
||||
skaddr);
|
||||
}
|
||||
|
||||
sockaddr *as_sockaddr(Sockaddr &skaddr) {
|
||||
return std::visit(
|
||||
[](auto &&arg) {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(arg)>,
|
||||
std::monostate>) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return reinterpret_cast<sockaddr *>(&arg);
|
||||
},
|
||||
skaddr);
|
||||
}
|
||||
|
||||
int sockaddr_family(const Sockaddr &skaddr) {
|
||||
return as_sockaddr(skaddr)->sa_family;
|
||||
}
|
||||
|
||||
uint16_t sockaddr_port(const Sockaddr &skaddr) {
|
||||
return std::visit(
|
||||
[](auto &&arg) -> uint16_t {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in>) {
|
||||
return ntohs(arg.sin_port);
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in6>) {
|
||||
return ntohs(arg.sin6_port);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
abort();
|
||||
},
|
||||
skaddr);
|
||||
}
|
||||
|
||||
void sockaddr_port(Sockaddr &skaddr, uint16_t port) {
|
||||
std::visit(
|
||||
[port](auto &&arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in>) {
|
||||
arg.sin_port = htons(port);
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, sockaddr_in6>) {
|
||||
arg.sin6_port = htons(port);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
abort();
|
||||
},
|
||||
skaddr);
|
||||
}
|
||||
|
||||
void sockaddr_set(Sockaddr &skaddr, const sockaddr *sa) {
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
return memcmp(&reinterpret_cast<const sockaddr_in *>(sa)->sin_addr, &iau.in,
|
||||
sizeof(iau.in)) == 0;
|
||||
skaddr.emplace<sockaddr_in>(*reinterpret_cast<const sockaddr_in *>(sa));
|
||||
return;
|
||||
case AF_INET6:
|
||||
return memcmp(&reinterpret_cast<const sockaddr_in6 *>(sa)->sin6_addr,
|
||||
&iau.in6, sizeof(iau.in6)) == 0;
|
||||
skaddr.emplace<sockaddr_in6>(*reinterpret_cast<const sockaddr_in6 *>(sa));
|
||||
return;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
socklen_t sockaddr_size(const Sockaddr &skaddr) {
|
||||
return std::visit(
|
||||
[](auto &&arg) { return static_cast<socklen_t>(sizeof(arg)); }, skaddr);
|
||||
}
|
||||
|
||||
bool sockaddr_empty(const Sockaddr &skaddr) {
|
||||
return std::holds_alternative<std::monostate>(skaddr);
|
||||
}
|
||||
|
||||
const sockaddr *Address::as_sockaddr() const {
|
||||
return ngtcp2::as_sockaddr(skaddr);
|
||||
}
|
||||
|
||||
sockaddr *Address::as_sockaddr() { return ngtcp2::as_sockaddr(skaddr); }
|
||||
|
||||
int Address::family() const { return sockaddr_family(skaddr); }
|
||||
|
||||
uint16_t Address::port() const { return sockaddr_port(skaddr); }
|
||||
|
||||
void Address::port(uint16_t port) { sockaddr_port(skaddr, port); }
|
||||
|
||||
void Address::set(const sockaddr *sa) { sockaddr_set(skaddr, sa); }
|
||||
|
||||
socklen_t Address::size() const { return sockaddr_size(skaddr); }
|
||||
|
||||
bool Address::empty() const { return sockaddr_empty(skaddr); }
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
75
deps/ngtcp2/ngtcp2/examples/shared.h
vendored
75
deps/ngtcp2/ngtcp2/examples/shared.h
vendored
@ -51,15 +51,17 @@ consteval std::span<const uint8_t> as_uint8_span(const uint8_t (&s)[N]) {
|
||||
return {s, N - 1};
|
||||
}
|
||||
|
||||
constexpr uint8_t RAW_HQ_ALPN[] = "\xahq-interop";
|
||||
constexpr auto HQ_ALPN = as_uint8_span(RAW_HQ_ALPN);
|
||||
constexpr auto HQ_ALPN_V1 = as_uint8_span(RAW_HQ_ALPN);
|
||||
inline constexpr uint8_t RAW_HQ_ALPN[] = "\xahq-interop";
|
||||
inline constexpr auto HQ_ALPN = as_uint8_span(RAW_HQ_ALPN);
|
||||
inline constexpr auto HQ_ALPN_V1 = as_uint8_span(RAW_HQ_ALPN);
|
||||
|
||||
constexpr uint8_t RAW_H3_ALPN[] = "\x2h3";
|
||||
constexpr auto H3_ALPN = as_uint8_span(RAW_H3_ALPN);
|
||||
constexpr auto H3_ALPN_V1 = as_uint8_span(RAW_H3_ALPN);
|
||||
inline constexpr uint8_t RAW_H3_ALPN[] = "\x2h3";
|
||||
inline constexpr auto H3_ALPN = as_uint8_span(RAW_H3_ALPN);
|
||||
inline constexpr auto H3_ALPN_V1 = as_uint8_span(RAW_H3_ALPN);
|
||||
|
||||
constexpr uint32_t TLS_ALERT_ECH_REQUIRED = 121;
|
||||
inline constexpr uint32_t TLS_ALERT_ECH_REQUIRED = 121;
|
||||
|
||||
inline constexpr size_t MAX_RECV_PKTS = 64;
|
||||
|
||||
// msghdr_get_ecn gets ECN bits from |msg|. |family| is the address
|
||||
// family from which packet is received.
|
||||
@ -85,14 +87,61 @@ std::optional<Address> msghdr_get_local_addr(msghdr *msg, int family);
|
||||
// not found, or UDP_GRO is not supported, this function returns 0.
|
||||
size_t msghdr_get_udp_gro(msghdr *msg);
|
||||
|
||||
void set_port(Address &dst, const Address &src);
|
||||
|
||||
// get_local_addr stores preferred local address (interface address)
|
||||
// in |iau| for a given destination address |remote_addr|.
|
||||
int get_local_addr(in_addr_union &iau, const Address &remote_addr);
|
||||
// in |ia| for a given destination address |remote_addr|.
|
||||
int get_local_addr(InAddr &ia, const Address &remote_addr);
|
||||
|
||||
// addreq returns true if |sa| and |iau| contain the same address.
|
||||
bool addreq(const sockaddr *sa, const in_addr_union &iau);
|
||||
// addreq returns true if |addr| and |ia| contain the same address.
|
||||
bool addreq(const Address &addr, const InAddr &ia);
|
||||
|
||||
// in_addr_get_ptr returns the pointer to the stored address in |ia|.
|
||||
// It is undefined if |ia| contains std::monostate.
|
||||
const void *in_addr_get_ptr(const InAddr &ia);
|
||||
|
||||
// in_addr_empty returns true if |ia| if it does not contain any
|
||||
// meaningful address.
|
||||
bool in_addr_empty(const InAddr &ia);
|
||||
|
||||
// as_sockaddr returns the pointer to the stored address casted to
|
||||
// const sockaddr *.
|
||||
[[nodiscard]] const sockaddr *as_sockaddr(const Sockaddr &skaddr);
|
||||
[[nodiscard]] sockaddr *as_sockaddr(Sockaddr &skaddr);
|
||||
|
||||
// sockaddr_family returns the address family.
|
||||
[[nodiscard]] int sockaddr_family(const Sockaddr &skaddr);
|
||||
|
||||
// sockaddr_port returns the port.
|
||||
[[nodiscard]] uint16_t sockaddr_port(const Sockaddr &skaddr);
|
||||
|
||||
// sockaddr_port sets |port| to |skaddr|.
|
||||
void sockaddr_port(Sockaddr &skaddr, uint16_t port);
|
||||
|
||||
// sockaddr_set stores |sa| to |skaddr|. The address family is
|
||||
// determined by |sa|->sa_family, and |sa| must point to the memory
|
||||
// that contains valid object which is either sockaddr_in or
|
||||
// sockaddr_in6.
|
||||
void sockaddr_set(Sockaddr &skaddr, const sockaddr *sa);
|
||||
|
||||
// sockaddr_size returns the size of the stored address.
|
||||
[[nodiscard]] socklen_t sockaddr_size(const Sockaddr &skaddr);
|
||||
|
||||
// sockaddr_empty returns true if |skaddr| does not contain any
|
||||
// meaningful address.
|
||||
[[nodiscard]] bool sockaddr_empty(const Sockaddr &skaddr);
|
||||
|
||||
[[nodiscard]] inline ngtcp2_addr as_ngtcp2_addr(const Address &addr) {
|
||||
return {
|
||||
.addr = const_cast<sockaddr *>(addr.as_sockaddr()),
|
||||
.addrlen = addr.size(),
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline ngtcp2_addr as_ngtcp2_addr(Address &addr) {
|
||||
return {
|
||||
.addr = addr.as_sockaddr(),
|
||||
.addrlen = addr.size(),
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
|
||||
977
deps/ngtcp2/ngtcp2/examples/sim.cc
vendored
Normal file
977
deps/ngtcp2/ngtcp2/examples/sim.cc
vendored
Normal file
@ -0,0 +1,977 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "sim.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
#include <string_view>
|
||||
#include <iostream>
|
||||
|
||||
#include "ngtcp2/ngtcp2_crypto_wolfssl.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "shared.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace {
|
||||
constexpr auto ALPN_LIST = "ngtcp2-sim"sv;
|
||||
constexpr size_t CIDLEN = 10;
|
||||
constexpr uint8_t SERVER_SECRET[] = "server_secret";
|
||||
|
||||
int generate_secure_random(std::span<uint8_t> data) {
|
||||
if (wolfSSL_RAND_bytes(data.data(), static_cast<int>(data.size())) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rand_bytes(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_rand_ctx *rand_ctx) {
|
||||
auto rv = generate_secure_random({dest, destlen});
|
||||
(void)rv;
|
||||
assert(0 == rv);
|
||||
}
|
||||
|
||||
int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token,
|
||||
size_t cidlen, void *user_data) {
|
||||
if (generate_secure_random({cid->data, cidlen}) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
cid->datalen = cidlen;
|
||||
if (ngtcp2_crypto_generate_stateless_reset_token(
|
||||
token, SERVER_SECRET, sizeof(SERVER_SECRET) - 1, cid) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ngtcp2_tstamp to_ngtcp2_tstamp(const Timestamp &ts) {
|
||||
return static_cast<ngtcp2_tstamp>(ts.time_since_epoch().count());
|
||||
}
|
||||
|
||||
Timestamp to_timestamp(ngtcp2_tstamp ts) {
|
||||
return Timestamp{Timestamp::duration{ts}};
|
||||
}
|
||||
|
||||
uint64_t LinkConfig::compute_expected_goodput(Timestamp::duration rtt) const {
|
||||
// Assume 80% usage ratio.
|
||||
uint64_t g = rate * 8 / 10;
|
||||
|
||||
if (loss < 1e-9) {
|
||||
return g;
|
||||
}
|
||||
|
||||
constexpr double margin = 0.95;
|
||||
|
||||
return std::min(g,
|
||||
static_cast<uint64_t>(MAX_UDP_PAYLOAD_SIZE * NGTCP2_SECONDS /
|
||||
static_cast<double>(rtt.count()) /
|
||||
sqrt(loss) * 8 * margin));
|
||||
}
|
||||
|
||||
namespace {
|
||||
int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
|
||||
uint64_t offset, const uint8_t *data, size_t datalen,
|
||||
void *user_data, void *stream_user_data) {
|
||||
ngtcp2_conn_extend_max_stream_offset(conn, stream_id, datalen);
|
||||
ngtcp2_conn_extend_max_offset(conn, datalen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ngtcp2_callbacks default_client_callbacks() {
|
||||
return ngtcp2_callbacks{
|
||||
.client_initial = ngtcp2_crypto_client_initial_cb,
|
||||
.recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb,
|
||||
.encrypt = ngtcp2_crypto_encrypt_cb,
|
||||
.decrypt = ngtcp2_crypto_decrypt_cb,
|
||||
.hp_mask = ngtcp2_crypto_hp_mask_cb,
|
||||
.recv_stream_data = recv_stream_data,
|
||||
.recv_retry = ngtcp2_crypto_recv_retry_cb,
|
||||
.rand = rand_bytes,
|
||||
.get_new_connection_id = get_new_connection_id,
|
||||
.update_key = ngtcp2_crypto_update_key_cb,
|
||||
.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb,
|
||||
.delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
|
||||
.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb,
|
||||
.version_negotiation = ngtcp2_crypto_version_negotiation_cb,
|
||||
};
|
||||
}
|
||||
|
||||
ngtcp2_callbacks default_server_callbacks() {
|
||||
return ngtcp2_callbacks{
|
||||
.recv_client_initial = ngtcp2_crypto_recv_client_initial_cb,
|
||||
.recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb,
|
||||
.encrypt = ngtcp2_crypto_encrypt_cb,
|
||||
.decrypt = ngtcp2_crypto_decrypt_cb,
|
||||
.hp_mask = ngtcp2_crypto_hp_mask_cb,
|
||||
.recv_stream_data = recv_stream_data,
|
||||
.rand = rand_bytes,
|
||||
.get_new_connection_id = get_new_connection_id,
|
||||
.update_key = ngtcp2_crypto_update_key_cb,
|
||||
.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb,
|
||||
.delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
|
||||
.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb,
|
||||
.version_negotiation = ngtcp2_crypto_version_negotiation_cb,
|
||||
};
|
||||
}
|
||||
|
||||
ngtcp2_settings default_client_settings() {
|
||||
ngtcp2_settings settings;
|
||||
ngtcp2_settings_default(&settings);
|
||||
|
||||
settings.log_printf = debug::log_printf;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
ngtcp2_settings default_server_settings() {
|
||||
ngtcp2_settings settings;
|
||||
ngtcp2_settings_default(&settings);
|
||||
|
||||
settings.log_printf = debug::log_printf;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
ngtcp2_transport_params default_client_transport_params() {
|
||||
ngtcp2_transport_params params;
|
||||
ngtcp2_transport_params_default(¶ms);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
ngtcp2_transport_params default_server_transport_params() {
|
||||
ngtcp2_transport_params params;
|
||||
ngtcp2_transport_params_default(¶ms);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
Sockaddr getaddrinfo(const char *host, const char *svc) {
|
||||
auto hints = addrinfo{
|
||||
.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
|
||||
.ai_family = AF_UNSPEC,
|
||||
};
|
||||
addrinfo *rp;
|
||||
|
||||
auto rv = getaddrinfo(host, svc, &hints, &rp);
|
||||
(void)rv;
|
||||
assert(0 == rv);
|
||||
|
||||
Sockaddr skaddr;
|
||||
sockaddr_set(skaddr, rp->ai_addr);
|
||||
|
||||
freeaddrinfo(rp);
|
||||
|
||||
return skaddr;
|
||||
}
|
||||
|
||||
ngtcp2_addr default_client_addr() {
|
||||
static auto skaddr = getaddrinfo("10.0.1.1", "12345");
|
||||
|
||||
return ngtcp2_addr{
|
||||
.addr = as_sockaddr(skaddr),
|
||||
.addrlen = sockaddr_size(skaddr),
|
||||
};
|
||||
}
|
||||
|
||||
ngtcp2_addr default_server_addr() {
|
||||
static auto skaddr = getaddrinfo("10.0.2.1", "443");
|
||||
|
||||
return ngtcp2_addr{
|
||||
.addr = as_sockaddr(skaddr),
|
||||
.addrlen = sockaddr_size(skaddr),
|
||||
};
|
||||
}
|
||||
|
||||
EndpointConfig default_client_endpoint_config() {
|
||||
return EndpointConfig{
|
||||
.callbacks = default_client_callbacks(),
|
||||
.settings = default_client_settings(),
|
||||
.params = default_client_transport_params(),
|
||||
.local_addr = default_client_addr(),
|
||||
};
|
||||
}
|
||||
|
||||
EndpointConfig default_server_endpoint_config() {
|
||||
return EndpointConfig{
|
||||
.server = true,
|
||||
.callbacks = default_server_callbacks(),
|
||||
.settings = default_server_settings(),
|
||||
.params = default_server_transport_params(),
|
||||
.local_addr = default_server_addr(),
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
||||
auto ep = static_cast<Endpoint *>(conn_ref->user_data);
|
||||
return ep->get_conn();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Endpoint::Endpoint()
|
||||
: conn_ref_{ngtcp2::get_conn, this}, channel_{config_.link} {}
|
||||
|
||||
Endpoint::Endpoint(const EndpointConfig &config)
|
||||
: config_{config},
|
||||
conn_ref_{ngtcp2::get_conn, this},
|
||||
channel_{config_.link} {}
|
||||
|
||||
Endpoint::Endpoint(Endpoint &&other) noexcept
|
||||
: config_{std::exchange(other.config_, {})},
|
||||
ssl_ctx_{std::exchange(other.ssl_ctx_, nullptr)},
|
||||
ssl_{std::exchange(other.ssl_, nullptr)},
|
||||
conn_{std::exchange(other.conn_, nullptr)},
|
||||
conn_ref_{ngtcp2::get_conn, this},
|
||||
channel_{std::exchange(other.channel_, {})},
|
||||
initialized_{std::exchange(other.initialized_, false)} {}
|
||||
|
||||
Endpoint::~Endpoint() {
|
||||
ngtcp2_conn_del(conn_);
|
||||
|
||||
if (ssl_) {
|
||||
wolfSSL_free(ssl_);
|
||||
}
|
||||
|
||||
if (ssl_ctx_) {
|
||||
wolfSSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
}
|
||||
|
||||
Endpoint &Endpoint::operator=(Endpoint &&other) noexcept {
|
||||
ngtcp2_conn_del(conn_);
|
||||
|
||||
if (ssl_) {
|
||||
wolfSSL_free(ssl_);
|
||||
}
|
||||
|
||||
if (ssl_ctx_) {
|
||||
wolfSSL_CTX_free(ssl_ctx_);
|
||||
}
|
||||
|
||||
config_ = std::exchange(other.config_, {});
|
||||
ssl_ctx_ = std::exchange(other.ssl_ctx_, nullptr);
|
||||
ssl_ = std::exchange(other.ssl_, nullptr);
|
||||
conn_ = std::exchange(other.conn_, nullptr);
|
||||
conn_ref_ = {ngtcp2::get_conn, this};
|
||||
channel_ = std::exchange(other.channel_, {});
|
||||
initialized_ = std::exchange(other.initialized_, false);
|
||||
|
||||
if (ssl_) {
|
||||
wolfSSL_set_app_data(ssl_, &conn_ref_);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr auto tls_key = R"(-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwEvkGGgXAcRaG7Z8
|
||||
gA7C6+W2RsW9gcjV9e5ybr0ikaahRANCAASCo35bDi+Q/q/CzHI1e5QaBrbqbFhW
|
||||
G20QbVAeMK8l0oC8OGD3PSpZK1HXwALwzhMuwhxDos3ANb5naa5y17fQ
|
||||
-----END PRIVATE KEY-----
|
||||
)"sv;
|
||||
|
||||
constexpr auto tls_crt = R"(-----BEGIN CERTIFICATE-----
|
||||
MIICBzCCAa2gAwIBAgIUd2l6Pce3S0QH3dQC0Q/CjHbmggowCgYIKoZIzj0EAwIw
|
||||
WTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
|
||||
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1
|
||||
MTExNDExNTcwMFoXDTI1MTIxNDExNTcwMFowWTELMAkGA1UEBhMCQVUxEzARBgNV
|
||||
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
|
||||
ZDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
||||
gqN+Ww4vkP6vwsxyNXuUGga26mxYVhttEG1QHjCvJdKAvDhg9z0qWStR18AC8M4T
|
||||
LsIcQ6LNwDW+Z2mucte30KNTMFEwHQYDVR0OBBYEFFVgXLoLwzpf6+twP5z8Ujr2
|
||||
5mxnMB8GA1UdIwQYMBaAFFVgXLoLwzpf6+twP5z8Ujr25mxnMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAO4tnDNRAcooz62vf2m7vTyDqFCjcaIv
|
||||
SJ9Gq0lvEXEcAiBwWBNUASBqLaje3hmtgwxcF7EIqqiGo5j8f9Ufgu6SRg==
|
||||
-----END CERTIFICATE-----
|
||||
)"sv;
|
||||
} // namespace
|
||||
|
||||
int Endpoint::setup_server(std::span<const uint8_t> original_dcid,
|
||||
std::span<const uint8_t> client_scid,
|
||||
uint32_t version, const ngtcp2_addr *remote_addr) {
|
||||
int rv;
|
||||
|
||||
ngtcp2_cid scid{
|
||||
.datalen = CIDLEN,
|
||||
};
|
||||
|
||||
if (generate_secure_random({scid.data, scid.datalen}) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ngtcp2_cid dcid;
|
||||
ngtcp2_cid_init(&dcid, client_scid.data(), client_scid.size());
|
||||
|
||||
auto params = config_.params;
|
||||
ngtcp2_cid_init(¶ms.original_dcid, original_dcid.data(),
|
||||
original_dcid.size());
|
||||
params.original_dcid_present = 1;
|
||||
|
||||
if (ngtcp2_crypto_generate_stateless_reset_token(
|
||||
params.stateless_reset_token, SERVER_SECRET, sizeof(SERVER_SECRET) - 1,
|
||||
&scid)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto path = ngtcp2_path{
|
||||
.local = config_.local_addr,
|
||||
.remote = *remote_addr,
|
||||
};
|
||||
|
||||
rv = ngtcp2_conn_server_new(&conn_, &dcid, &scid, &path, version,
|
||||
&config_.callbacks, &config_.settings, ¶ms,
|
||||
nullptr, config_.user_data);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_server_method());
|
||||
if (!ssl_ctx_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_wolfssl_configure_server_context(ssl_ctx_) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_use_certificate_buffer(
|
||||
ssl_ctx_, reinterpret_cast<const uint8_t *>(tls_crt.data()),
|
||||
static_cast<long>(tls_crt.size()), SSL_FILETYPE_PEM) != SSL_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_CTX_use_PrivateKey_buffer(
|
||||
ssl_ctx_, reinterpret_cast<const uint8_t *>(tls_key.data()),
|
||||
static_cast<long>(tls_key.size()), SSL_FILETYPE_PEM) != SSL_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssl_ = wolfSSL_new(ssl_ctx_);
|
||||
if (!ssl_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_UseALPN(ssl_, const_cast<char *>(ALPN_LIST.data()),
|
||||
ALPN_LIST.size(),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH) != WOLFSSL_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfSSL_set_app_data(ssl_, &conn_ref_);
|
||||
wolfSSL_set_accept_state(ssl_);
|
||||
wolfSSL_set_quic_transport_version(ssl_, 0x39);
|
||||
|
||||
ngtcp2_conn_set_tls_native_handle(conn_, ssl_);
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Endpoint::setup_client(const ngtcp2_addr *remote_addr) {
|
||||
int rv;
|
||||
|
||||
ngtcp2_cid dcid{
|
||||
.datalen = CIDLEN,
|
||||
};
|
||||
ngtcp2_cid scid{
|
||||
.datalen = CIDLEN,
|
||||
};
|
||||
|
||||
if (generate_secure_random({dcid.data, dcid.datalen}) != 0 ||
|
||||
generate_secure_random({scid.data, scid.datalen}) != 0) {
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto path = ngtcp2_path{
|
||||
.local = config_.local_addr,
|
||||
.remote = *remote_addr,
|
||||
};
|
||||
|
||||
rv = ngtcp2_conn_client_new(&conn_, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1,
|
||||
&config_.callbacks, &config_.settings,
|
||||
&config_.params, nullptr, config_.user_data);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
||||
if (!ssl_ctx_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx_) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssl_ = wolfSSL_new(ssl_ctx_);
|
||||
if (!ssl_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wolfSSL_UseALPN(ssl_, const_cast<char *>(ALPN_LIST.data()),
|
||||
ALPN_LIST.size(),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH) != WOLFSSL_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfSSL_set_app_data(ssl_, &conn_ref_);
|
||||
wolfSSL_set_connect_state(ssl_);
|
||||
wolfSSL_set_quic_transport_version(ssl_, 0x39);
|
||||
|
||||
ngtcp2_conn_set_tls_native_handle(conn_, ssl_);
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Endpoint::on_read(const NetworkPath &path, std::span<const uint8_t> pkt,
|
||||
const Context &ctx) {
|
||||
auto ts = to_ngtcp2_tstamp(ctx.ts);
|
||||
auto cpath = to_ngtcp2_path(path);
|
||||
|
||||
auto rv =
|
||||
ngtcp2_conn_read_pkt(conn_, &cpath, nullptr, pkt.data(), pkt.size(), ts);
|
||||
if (rv != 0) {
|
||||
std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx.endpoint->get_channel().schedule_timeout(ctx.ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Endpoint::on_write(const Context &ctx) {
|
||||
if (config_.on_write(conn_, ctx) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto next_expiry_ts = ngtcp2_conn_get_expiry(conn_);
|
||||
if (next_expiry_ts == UINT64_MAX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx.endpoint->get_channel().schedule_timeout(to_timestamp(next_expiry_ts));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Endpoint::on_timeout(const Context &ctx) {
|
||||
auto rv = ngtcp2_conn_handle_expiry(conn_, to_ngtcp2_tstamp(ctx.ts));
|
||||
if (rv != 0) {
|
||||
std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv)
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return on_write(ctx);
|
||||
}
|
||||
|
||||
NetworkPath to_network_path(const ngtcp2_path *path) {
|
||||
NetworkPath res;
|
||||
|
||||
res.local.set(path->local.addr);
|
||||
res.remote.set(path->remote.addr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ngtcp2_path to_ngtcp2_path(const NetworkPath &path) {
|
||||
return {
|
||||
.local = as_ngtcp2_addr(path.local),
|
||||
.remote = as_ngtcp2_addr(path.remote),
|
||||
};
|
||||
}
|
||||
|
||||
NetworkPath NetworkPath::invert() {
|
||||
auto path = *this;
|
||||
|
||||
std::swap(path.local, path.remote);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
Channel::Channel(const LinkConfig &config)
|
||||
: link_config_{config}, gen_{link_config_.seed} {}
|
||||
|
||||
Channel::Channel(Channel &&other) noexcept
|
||||
: link_config_{std::exchange(other.link_config_, {})},
|
||||
gen_{std::exchange(other.gen_, {})},
|
||||
tx_queue_{std::exchange(other.tx_queue_, {})},
|
||||
tx_queue_size_{std::exchange(other.tx_queue_size_, 0)},
|
||||
link_free_ts_{std::exchange(other.link_free_ts_, {})},
|
||||
queue_{std::exchange(other.queue_, {})},
|
||||
timeout_{std::exchange(other.timeout_, {})},
|
||||
ts_{std::exchange(other.ts_, {})} {}
|
||||
|
||||
Channel &Channel::operator=(Channel &&other) noexcept {
|
||||
link_config_ = std::exchange(other.link_config_, {});
|
||||
gen_ = std::exchange(other.gen_, {});
|
||||
tx_queue_ = std::exchange(other.tx_queue_, {});
|
||||
tx_queue_size_ = std::exchange(other.tx_queue_size_, 0);
|
||||
link_free_ts_ = std::exchange(other.link_free_ts_, {});
|
||||
queue_ = std::exchange(other.queue_, {});
|
||||
timeout_ = std::exchange(other.timeout_, {});
|
||||
ts_ = std::exchange(other.ts_, {});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Channel::send_pkt(const NetworkPath &path, std::span<uint8_t> pkt) {
|
||||
auto rate = link_config_.rate / 8;
|
||||
|
||||
if (rate == 0) {
|
||||
queue_.emplace(Event{
|
||||
.ts = ts_ + link_config_.delay,
|
||||
.type = EVENT_TYPE_PKT,
|
||||
.path = path,
|
||||
.pkt = std::vector(std::ranges::begin(pkt), std::ranges::end(pkt)),
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (link_config_.limit && tx_queue_size_ + pkt.size() > link_config_.limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto departure_ts = std::max(ts_, link_free_ts_) +
|
||||
Timestamp::duration{pkt.size() * NGTCP2_SECONDS / rate};
|
||||
|
||||
if (!decide_pkt_lost()) {
|
||||
queue_.emplace(Event{
|
||||
.ts = departure_ts + link_config_.delay,
|
||||
.type = EVENT_TYPE_PKT,
|
||||
.path = path,
|
||||
.pkt = std::vector(std::ranges::begin(pkt), std::ranges::end(pkt)),
|
||||
});
|
||||
}
|
||||
|
||||
tx_queue_.emplace_back(TxPacket{
|
||||
.departure_ts = departure_ts,
|
||||
.size = pkt.size(),
|
||||
});
|
||||
|
||||
tx_queue_size_ += pkt.size();
|
||||
link_free_ts_ = departure_ts;
|
||||
}
|
||||
|
||||
bool Channel::decide_pkt_lost() {
|
||||
return std::uniform_real_distribution<>(0, 1.0)(gen_) < link_config_.loss;
|
||||
}
|
||||
|
||||
void Channel::pop_tx_queue() {
|
||||
size_t n = 0;
|
||||
|
||||
auto it = std::ranges::find_if(tx_queue_, [&n, this](const auto &pkt) {
|
||||
if (pkt.departure_ts > ts_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
n += pkt.size;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
assert(tx_queue_size_ >= n);
|
||||
|
||||
tx_queue_size_ -= n;
|
||||
tx_queue_.erase(std::ranges::begin(tx_queue_), it);
|
||||
}
|
||||
|
||||
void Channel::schedule_timeout(Timestamp ts) {
|
||||
timeout_ = std::min(timeout_, ts);
|
||||
}
|
||||
|
||||
Timestamp Channel::get_next_timestamp() const {
|
||||
if (queue_.empty()) {
|
||||
return timeout_;
|
||||
}
|
||||
|
||||
auto &top = queue_.top();
|
||||
|
||||
return std::min(timeout_, top.ts);
|
||||
}
|
||||
|
||||
Event Channel::get_next_event() {
|
||||
if (!queue_.empty() && queue_.top().ts <= timeout_) {
|
||||
auto &top = const_cast<Event &>(queue_.top());
|
||||
|
||||
auto ev = Event{
|
||||
.ts = top.ts,
|
||||
.type = top.type,
|
||||
.path = top.path,
|
||||
.pkt = std::move(top.pkt),
|
||||
};
|
||||
|
||||
queue_.pop();
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
return Event{
|
||||
.ts = std::exchange(timeout_, Timestamp::max()),
|
||||
.type = EVENT_TYPE_TIMEOUT,
|
||||
};
|
||||
}
|
||||
|
||||
Simulator::Simulator(Endpoint client, Endpoint server)
|
||||
: client_{std::move(client)}, server_{std::move(server)} {}
|
||||
|
||||
Simulator::Simulator(Simulator &&other) noexcept
|
||||
: client_{std::exchange(client_, {})},
|
||||
server_{std::exchange(server_, {})},
|
||||
max_events_{std::exchange(other.max_events_, 0)} {}
|
||||
|
||||
Simulator &Simulator::operator=(Simulator &&other) noexcept {
|
||||
client_ = std::exchange(other.client_, {});
|
||||
server_ = std::exchange(other.server_, {});
|
||||
max_events_ = std::exchange(other.max_events_, 0);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::optional<std::tuple<Event, Endpoint &>> Simulator::get_next_event() {
|
||||
auto &client_chan = client_.get_channel();
|
||||
auto &server_chan = server_.get_channel();
|
||||
|
||||
auto client_next_ts = client_chan.get_next_timestamp();
|
||||
auto server_next_ts = server_chan.get_next_timestamp();
|
||||
|
||||
if (client_next_ts == Timestamp::max() &&
|
||||
server_next_ts == Timestamp::max()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (client_next_ts <= server_next_ts) {
|
||||
auto ev = client_chan.get_next_event();
|
||||
return {{std::move(ev), client_}};
|
||||
}
|
||||
|
||||
auto ev = server_chan.get_next_event();
|
||||
|
||||
return {{std::move(ev), server_}};
|
||||
}
|
||||
|
||||
int Simulator::run() {
|
||||
if (client_.get_initialized() ||
|
||||
client_.setup_client(&server_.get_endpoint_config().local_addr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto ts = Timestamp{};
|
||||
auto &client_chan = client_.get_channel();
|
||||
auto &server_chan = server_.get_channel();
|
||||
|
||||
client_chan.schedule_timeout(ts);
|
||||
|
||||
size_t k = 0;
|
||||
|
||||
for (; k < max_events_; ++k) {
|
||||
auto maybe_event = get_next_event();
|
||||
if (!maybe_event) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto &[event, ep] = *maybe_event;
|
||||
|
||||
assert(ts <= event.ts);
|
||||
|
||||
ts = event.ts;
|
||||
|
||||
client_chan.set_timestamp(ts);
|
||||
server_chan.set_timestamp(ts);
|
||||
|
||||
client_chan.pop_tx_queue();
|
||||
server_chan.pop_tx_queue();
|
||||
|
||||
switch (event.type) {
|
||||
case EVENT_TYPE_TIMEOUT: {
|
||||
auto ctx = Context{
|
||||
.sim = this,
|
||||
.ts = ts,
|
||||
.endpoint = &ep,
|
||||
};
|
||||
|
||||
if (ep.on_timeout(ctx) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EVENT_TYPE_PKT:
|
||||
if (deliver_pkt(ep, event.path.invert(), event.pkt, ts) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (k == max_events_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Endpoint &Simulator::get_opposite_endpoint(const Endpoint &ep) {
|
||||
return &ep == &client_ ? server_ : client_;
|
||||
}
|
||||
|
||||
int Simulator::deliver_pkt(Endpoint &remote_ep, const NetworkPath &path,
|
||||
std::span<const uint8_t> pkt, Timestamp ts) {
|
||||
auto &local_ep = get_opposite_endpoint(remote_ep);
|
||||
|
||||
if (!local_ep.get_initialized() && local_ep.get_endpoint_config().server) {
|
||||
ngtcp2_version_cid vcid;
|
||||
|
||||
auto rv =
|
||||
ngtcp2_pkt_decode_version_cid(&vcid, pkt.data(), pkt.size(), CIDLEN);
|
||||
if (rv != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_pkt_hd hd;
|
||||
|
||||
if (ngtcp2_accept(&hd, pkt.data(), pkt.size()) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (local_ep.setup_server(
|
||||
{vcid.dcid, vcid.dcidlen}, {vcid.scid, vcid.scidlen}, vcid.version,
|
||||
&remote_ep.get_endpoint_config().local_addr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto ctx = Context{
|
||||
.sim = this,
|
||||
.ts = ts,
|
||||
.endpoint = &local_ep,
|
||||
};
|
||||
|
||||
return local_ep.on_read(path, pkt, ctx);
|
||||
}
|
||||
|
||||
void HandshakeApp::configure(EndpointConfig &config) {
|
||||
auto handshake_confirmed = [](ngtcp2_conn *conn, void *user_data) {
|
||||
auto app = static_cast<HandshakeApp *>(user_data);
|
||||
|
||||
app->handshake_confirmed();
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
if (config.server) {
|
||||
config.callbacks.handshake_completed = handshake_confirmed;
|
||||
} else {
|
||||
config.callbacks.handshake_confirmed = handshake_confirmed;
|
||||
}
|
||||
|
||||
config.on_write = [](ngtcp2_conn *conn, const Context &ctx) {
|
||||
std::array<uint8_t, MAX_UDP_PAYLOAD_SIZE> buf;
|
||||
|
||||
auto ts = to_ngtcp2_tstamp(ctx.ts);
|
||||
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
auto nwrite = ngtcp2_conn_write_pkt(conn, &ps.path, nullptr, buf.data(),
|
||||
buf.size(), ts);
|
||||
if (nwrite < 0) {
|
||||
std::cerr << "ngtcp2_conn_write_pkt: "
|
||||
<< ngtcp2_strerror(static_cast<int>(nwrite)) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_conn_update_pkt_tx_time(conn, ts);
|
||||
|
||||
ctx.endpoint->get_channel().send_pkt(
|
||||
to_network_path(&ps.path), {buf.data(), static_cast<size_t>(nwrite)});
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
config.user_data = this;
|
||||
}
|
||||
|
||||
UniStreamApp::UniStreamApp(uint64_t max_bytes) : max_bytes_{max_bytes} {}
|
||||
|
||||
namespace {
|
||||
std::array<uint8_t, 4096> nulldata;
|
||||
} // namespace
|
||||
|
||||
void UniStreamApp::configure(EndpointConfig &config) {
|
||||
config.callbacks.stream_close = [](ngtcp2_conn *conn, uint32_t flags,
|
||||
int64_t stream_id, uint64_t app_error_code,
|
||||
void *user_data, void *stream_user_data) {
|
||||
auto app = static_cast<UniStreamApp *>(user_data);
|
||||
|
||||
app->stream_close(conn, stream_id);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
config.callbacks.extend_max_local_streams_uni =
|
||||
[](ngtcp2_conn *conn, uint64_t max_streams, void *user_data) {
|
||||
auto app = static_cast<UniStreamApp *>(user_data);
|
||||
|
||||
return app->extend_max_local_streams_uni(conn);
|
||||
};
|
||||
|
||||
config.on_write = [this](ngtcp2_conn *conn, const Context &ctx) {
|
||||
return on_write(conn, ctx);
|
||||
};
|
||||
|
||||
config.user_data = this;
|
||||
}
|
||||
|
||||
uint64_t UniStreamApp::compute_goodput() const {
|
||||
auto d = get_transmit_duration();
|
||||
if (d == Timestamp::duration::zero()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<uint64_t>(static_cast<double>(bytes_sent_) *
|
||||
NGTCP2_SECONDS / static_cast<double>(d.count()) *
|
||||
8);
|
||||
}
|
||||
|
||||
void UniStreamApp::stream_close(ngtcp2_conn *conn, int64_t stream_id) {
|
||||
if (stream_id_ != stream_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_all_bytes_sent()) {
|
||||
end_ts_ = to_timestamp(ngtcp2_conn_get_timestamp(conn));
|
||||
}
|
||||
}
|
||||
|
||||
int UniStreamApp::extend_max_local_streams_uni(ngtcp2_conn *conn) {
|
||||
if (stream_id_ != -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t stream_id;
|
||||
|
||||
auto rv = ngtcp2_conn_open_uni_stream(conn, &stream_id, nullptr);
|
||||
if (rv != 0) {
|
||||
std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
|
||||
<< std::endl;
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
stream_id_ = stream_id;
|
||||
start_ts_ = to_timestamp(ngtcp2_conn_get_timestamp(conn));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UniStreamApp::on_write(ngtcp2_conn *conn, const Context &ctx) {
|
||||
std::array<uint8_t, MAX_UDP_PAYLOAD_SIZE> buf;
|
||||
|
||||
int64_t stream_id;
|
||||
ngtcp2_vec vec;
|
||||
size_t veccnt;
|
||||
uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_NONE;
|
||||
|
||||
if (stream_id_ != -1 && max_bytes_ > bytes_sent_) {
|
||||
stream_id = stream_id_;
|
||||
vec.base = nulldata.data();
|
||||
vec.len = static_cast<size_t>(
|
||||
std::min(static_cast<uint64_t>(buf.size()), max_bytes_ - bytes_sent_));
|
||||
veccnt = 1;
|
||||
|
||||
if (bytes_sent_ + vec.len == max_bytes_) {
|
||||
flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
|
||||
}
|
||||
} else {
|
||||
stream_id = -1;
|
||||
veccnt = 0;
|
||||
}
|
||||
|
||||
auto ts = to_ngtcp2_tstamp(ctx.ts);
|
||||
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
ngtcp2_ssize ndatalen;
|
||||
|
||||
auto nwrite =
|
||||
ngtcp2_conn_writev_stream(conn, &ps.path, nullptr, buf.data(), buf.size(),
|
||||
&ndatalen, flags, stream_id, &vec, veccnt, ts);
|
||||
if (nwrite < 0) {
|
||||
if (nwrite == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cerr << "ngtcp2_conn_writev_stream: "
|
||||
<< ngtcp2_strerror(static_cast<int>(nwrite)) << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ndatalen > 0) {
|
||||
bytes_sent_ += static_cast<size_t>(ndatalen);
|
||||
}
|
||||
|
||||
ngtcp2_conn_update_pkt_tx_time(conn, ts);
|
||||
|
||||
ctx.endpoint->get_channel().send_pkt(
|
||||
to_network_path(&ps.path), {buf.data(), static_cast<size_t>(nwrite)});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace ngtcp2
|
||||
289
deps/ngtcp2/ngtcp2/examples/sim.h
vendored
Normal file
289
deps/ngtcp2/ngtcp2/examples/sim.h
vendored
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SIM_H
|
||||
#define SIM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <span>
|
||||
#include <random>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
#include "network.h"
|
||||
|
||||
namespace ngtcp2 {
|
||||
inline constexpr size_t MAX_UDP_PAYLOAD_SIZE = 1500;
|
||||
|
||||
using Timestamp =
|
||||
std::chrono::time_point<std::chrono::steady_clock, std::chrono::nanoseconds>;
|
||||
|
||||
ngtcp2_tstamp to_ngtcp2_tstamp(const Timestamp &ts);
|
||||
|
||||
Timestamp to_timestamp(ngtcp2_tstamp ts);
|
||||
|
||||
class Simulator;
|
||||
class Endpoint;
|
||||
|
||||
struct Context {
|
||||
Simulator *sim;
|
||||
Timestamp ts;
|
||||
Endpoint *endpoint;
|
||||
};
|
||||
|
||||
constexpr unsigned long long operator""_kbps(unsigned long long k) {
|
||||
return k * 1'000;
|
||||
}
|
||||
|
||||
constexpr unsigned long long operator""_mbps(unsigned long long m) {
|
||||
return m * 1'000'000;
|
||||
}
|
||||
|
||||
constexpr unsigned long long operator""_gbps(unsigned long long g) {
|
||||
return g * 1'000'000'000;
|
||||
}
|
||||
|
||||
struct LinkConfig {
|
||||
// compute_expected_goodput computes the expected goodput with the
|
||||
// given |rtt| in bits per second.
|
||||
uint64_t compute_expected_goodput(Timestamp::duration rtt) const;
|
||||
|
||||
// delay is the one-way link delay.
|
||||
Timestamp::duration delay;
|
||||
// rate is the bandwidth of this link measured in bits per second
|
||||
// (e.g., 10_mbps).
|
||||
uint64_t rate{};
|
||||
// limit is the maximum queue length of the outgoing packet measured
|
||||
// in bytes.
|
||||
uint64_t limit{};
|
||||
// loss is the probability of losing a packet.
|
||||
double loss{};
|
||||
// seed is a seed value for the random number generator.
|
||||
std::mt19937::result_type seed{};
|
||||
};
|
||||
|
||||
struct EndpointConfig {
|
||||
bool server{};
|
||||
ngtcp2_callbacks callbacks{};
|
||||
ngtcp2_settings settings{};
|
||||
ngtcp2_transport_params params{};
|
||||
ngtcp2_addr local_addr{};
|
||||
void *user_data{};
|
||||
LinkConfig link;
|
||||
|
||||
std::function<int(ngtcp2_conn *, const Context &)> on_write;
|
||||
};
|
||||
|
||||
ngtcp2_callbacks default_client_callbacks();
|
||||
|
||||
ngtcp2_callbacks default_server_callbacks();
|
||||
|
||||
ngtcp2_settings default_client_settings();
|
||||
|
||||
ngtcp2_settings default_server_settings();
|
||||
|
||||
ngtcp2_transport_params default_client_transport_params();
|
||||
|
||||
ngtcp2_transport_params default_server_transport_params();
|
||||
|
||||
ngtcp2_addr default_client_addr();
|
||||
|
||||
ngtcp2_addr default_server_addr();
|
||||
|
||||
EndpointConfig default_client_endpoint_config();
|
||||
|
||||
EndpointConfig default_server_endpoint_config();
|
||||
|
||||
struct NetworkPath {
|
||||
NetworkPath invert();
|
||||
|
||||
Address local{};
|
||||
Address remote{};
|
||||
};
|
||||
|
||||
NetworkPath to_network_path(const ngtcp2_path *path);
|
||||
|
||||
ngtcp2_path to_ngtcp2_path(const NetworkPath &path);
|
||||
|
||||
enum EventType {
|
||||
EVENT_TYPE_TIMEOUT,
|
||||
EVENT_TYPE_PKT,
|
||||
};
|
||||
|
||||
struct Event {
|
||||
Timestamp ts;
|
||||
EventType type;
|
||||
|
||||
NetworkPath path;
|
||||
std::vector<uint8_t> pkt;
|
||||
};
|
||||
|
||||
constexpr bool operator>(const Event &lhs, const Event &rhs) {
|
||||
return lhs.ts > rhs.ts;
|
||||
}
|
||||
|
||||
struct TxPacket {
|
||||
Timestamp departure_ts;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
class Channel {
|
||||
public:
|
||||
Channel() = default;
|
||||
Channel(const LinkConfig &config);
|
||||
Channel(const Channel &) = delete;
|
||||
Channel(Channel &&) noexcept;
|
||||
|
||||
Channel &operator=(const Channel &) = delete;
|
||||
Channel &operator=(Channel &&) noexcept;
|
||||
|
||||
void send_pkt(const NetworkPath &path, std::span<uint8_t> pkt);
|
||||
void schedule_timeout(Timestamp ts);
|
||||
void set_timestamp(Timestamp ts) { ts_ = ts; }
|
||||
Timestamp get_next_timestamp() const;
|
||||
Event get_next_event();
|
||||
void pop_tx_queue();
|
||||
|
||||
private:
|
||||
bool decide_pkt_lost();
|
||||
|
||||
LinkConfig link_config_;
|
||||
std::mt19937 gen_;
|
||||
std::deque<TxPacket> tx_queue_;
|
||||
size_t tx_queue_size_{};
|
||||
Timestamp link_free_ts_;
|
||||
using EventQueue =
|
||||
std::priority_queue<Event, std::vector<Event>, std::greater<Event>>;
|
||||
EventQueue queue_;
|
||||
Timestamp timeout_{Timestamp::max()};
|
||||
Timestamp ts_{};
|
||||
};
|
||||
|
||||
class Endpoint {
|
||||
public:
|
||||
Endpoint();
|
||||
explicit Endpoint(const EndpointConfig &config);
|
||||
Endpoint(Endpoint &&endpoint) noexcept;
|
||||
Endpoint(const Endpoint &) = delete;
|
||||
~Endpoint();
|
||||
|
||||
Endpoint &operator=(const Endpoint &) = delete;
|
||||
Endpoint &operator=(Endpoint &&) noexcept;
|
||||
|
||||
int setup_client(const ngtcp2_addr *remote_addr);
|
||||
int setup_server(std::span<const uint8_t> original_dcid,
|
||||
std::span<const uint8_t> client_scid, uint32_t version,
|
||||
const ngtcp2_addr *remote_addr);
|
||||
ngtcp2_conn *get_conn() const { return conn_; }
|
||||
bool get_initialized() const { return initialized_; }
|
||||
const EndpointConfig &get_endpoint_config() const { return config_; }
|
||||
int on_read(const NetworkPath &path, std::span<const uint8_t> pkt,
|
||||
const Context &ctx);
|
||||
int on_write(const Context &ctx);
|
||||
int on_timeout(const Context &ctx);
|
||||
Channel &get_channel() { return channel_; }
|
||||
|
||||
private:
|
||||
EndpointConfig config_;
|
||||
WOLFSSL_CTX *ssl_ctx_{};
|
||||
WOLFSSL *ssl_{};
|
||||
ngtcp2_conn *conn_{};
|
||||
ngtcp2_crypto_conn_ref conn_ref_{};
|
||||
Channel channel_;
|
||||
bool initialized_{};
|
||||
};
|
||||
|
||||
class Simulator {
|
||||
public:
|
||||
Simulator(Endpoint client, Endpoint server);
|
||||
Simulator(const Simulator &) = delete;
|
||||
Simulator(Simulator &&) noexcept;
|
||||
|
||||
Simulator &operator=(const Simulator &) = delete;
|
||||
Simulator &operator=(Simulator &&) noexcept;
|
||||
|
||||
int run();
|
||||
void set_max_events(size_t n) { max_events_ = n; }
|
||||
|
||||
private:
|
||||
Endpoint &get_opposite_endpoint(const Endpoint &ep);
|
||||
std::optional<std::tuple<Event, Endpoint &>> get_next_event();
|
||||
int deliver_pkt(Endpoint &remote_ep, const NetworkPath &path,
|
||||
std::span<const uint8_t> pkt, Timestamp ts);
|
||||
|
||||
Endpoint client_;
|
||||
Endpoint server_;
|
||||
size_t max_events_{1'000'000};
|
||||
};
|
||||
|
||||
class HandshakeApp {
|
||||
public:
|
||||
void configure(EndpointConfig &config);
|
||||
|
||||
bool get_handshake_confirmed() const { return handshake_confirmed_; }
|
||||
|
||||
private:
|
||||
void handshake_confirmed() { handshake_confirmed_ = true; }
|
||||
|
||||
bool handshake_confirmed_{};
|
||||
};
|
||||
|
||||
class UniStreamApp {
|
||||
public:
|
||||
UniStreamApp(uint64_t max_bytes);
|
||||
|
||||
void configure(EndpointConfig &config);
|
||||
uint64_t get_bytes_sent() const { return bytes_sent_; }
|
||||
Timestamp::duration get_transmit_duration() const {
|
||||
return end_ts_ - start_ts_;
|
||||
}
|
||||
bool is_all_bytes_sent() const { return bytes_sent_ == max_bytes_; }
|
||||
// compute_goodput computes goodput in bits per second.
|
||||
uint64_t compute_goodput() const;
|
||||
|
||||
private:
|
||||
void stream_close(ngtcp2_conn *conn, int64_t stream_id);
|
||||
int extend_max_local_streams_uni(ngtcp2_conn *conn);
|
||||
int on_write(ngtcp2_conn *conn, const Context &ctx);
|
||||
|
||||
int64_t stream_id_{-1};
|
||||
uint64_t max_bytes_{};
|
||||
uint64_t bytes_sent_{};
|
||||
Timestamp start_ts_{Timestamp::max()};
|
||||
Timestamp end_ts_{Timestamp::max()};
|
||||
};
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // SIM_H
|
||||
148
deps/ngtcp2/ngtcp2/examples/sim_test.cc
vendored
Normal file
148
deps/ngtcp2/ngtcp2/examples/sim_test.cc
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "sim_test.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "sim.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
namespace {
|
||||
const MunitTest tests[]{
|
||||
munit_void_test(test_sim_handshake),
|
||||
munit_void_test(test_sim_unistream),
|
||||
munit_test_end(),
|
||||
};
|
||||
} // namespace
|
||||
|
||||
const MunitSuite sim_suite{
|
||||
.prefix = "/sim",
|
||||
.tests = tests,
|
||||
};
|
||||
|
||||
void test_sim_handshake(void) {
|
||||
struct Test {
|
||||
const char *name;
|
||||
Timestamp::duration delay;
|
||||
};
|
||||
|
||||
auto tests = std::to_array<Test>({
|
||||
{
|
||||
.name = "short delay",
|
||||
.delay = 15ms,
|
||||
},
|
||||
{
|
||||
.name = "long delay",
|
||||
.delay = 1h,
|
||||
},
|
||||
});
|
||||
|
||||
for (auto &t : tests) {
|
||||
munit_logf(MUNIT_LOG_INFO, "testcase: %s", t.name);
|
||||
|
||||
auto link = LinkConfig{
|
||||
.delay = t.delay,
|
||||
};
|
||||
|
||||
HandshakeApp clapp;
|
||||
auto cl = default_client_endpoint_config();
|
||||
clapp.configure(cl);
|
||||
cl.link = link;
|
||||
|
||||
HandshakeApp svapp;
|
||||
auto sv = default_server_endpoint_config();
|
||||
svapp.configure(sv);
|
||||
sv.link = link;
|
||||
|
||||
int rv;
|
||||
|
||||
{
|
||||
rv = Simulator{Endpoint(cl), Endpoint(sv)}.run();
|
||||
}
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
assert_true(clapp.get_handshake_confirmed());
|
||||
assert_true(svapp.get_handshake_confirmed());
|
||||
}
|
||||
}
|
||||
|
||||
void test_sim_unistream(void) {
|
||||
struct Test {
|
||||
const char *name;
|
||||
double loss;
|
||||
};
|
||||
|
||||
auto tests = std::to_array<Test>({
|
||||
{
|
||||
.name = "no loss",
|
||||
},
|
||||
{
|
||||
.name = "1% loss",
|
||||
.loss = 0.01,
|
||||
},
|
||||
});
|
||||
|
||||
for (auto &t : tests) {
|
||||
munit_logf(MUNIT_LOG_INFO, "testcase: %s", t.name);
|
||||
|
||||
auto link = LinkConfig{
|
||||
.delay = 15ms,
|
||||
.rate = 10_mbps,
|
||||
.limit = MAX_UDP_PAYLOAD_SIZE * 25,
|
||||
.loss = t.loss,
|
||||
.seed = munit_rand_uint32(),
|
||||
};
|
||||
|
||||
HandshakeApp clapp;
|
||||
auto cl = default_client_endpoint_config();
|
||||
clapp.configure(cl);
|
||||
cl.params.initial_max_streams_uni = 1;
|
||||
cl.params.initial_max_stream_data_uni = 6_m;
|
||||
cl.params.initial_max_data = 6_m;
|
||||
cl.link = link;
|
||||
|
||||
UniStreamApp svapp(10_m);
|
||||
auto sv = default_server_endpoint_config();
|
||||
svapp.configure(sv);
|
||||
sv.link = link;
|
||||
|
||||
int rv;
|
||||
|
||||
{
|
||||
rv = Simulator{Endpoint(cl), Endpoint(sv)}.run();
|
||||
}
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
assert_true(svapp.is_all_bytes_sent());
|
||||
assert_uint64(link.compute_expected_goodput(link.delay * 2), <=,
|
||||
svapp.compute_goodput());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ngtcp2
|
||||
45
deps/ngtcp2/ngtcp2/examples/sim_test.h
vendored
Normal file
45
deps/ngtcp2/ngtcp2/examples/sim_test.h
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SIM_TEST_H
|
||||
#define SIM_TEST_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // defined(HAVE_CONFIG_H)
|
||||
|
||||
#define MUNIT_ENABLE_ASSERT_ALIASES
|
||||
|
||||
#include "munitxx.h"
|
||||
|
||||
namespace ngtcp2 {
|
||||
|
||||
extern const MunitSuite sim_suite;
|
||||
|
||||
munit_void_test_decl(test_sim_handshake)
|
||||
munit_void_test_decl(test_sim_unistream)
|
||||
|
||||
} // namespace ngtcp2
|
||||
|
||||
#endif // !defined(SIM_TEST_H)
|
||||
1
deps/ngtcp2/ngtcp2/examples/siphash.h
vendored
1
deps/ngtcp2/ngtcp2/examples/siphash.h
vendored
@ -40,6 +40,7 @@
|
||||
#ifndef SIPHASH_H
|
||||
#define SIPHASH_H
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <concepts>
|
||||
#include <algorithm>
|
||||
|
||||
21
deps/ngtcp2/ngtcp2/examples/template.h
vendored
21
deps/ngtcp2/ngtcp2/examples/template.h
vendored
@ -41,20 +41,21 @@ template <std::unsigned_integral T>
|
||||
return static_cast<std::make_signed_t<T>>(n);
|
||||
}
|
||||
|
||||
// inspired by <http://blog.korfuri.fr/post/go-defer-in-cpp/>, but our
|
||||
// template can take functions returning other than void.
|
||||
template <typename F, typename... T> struct Defer {
|
||||
Defer(F &&f, T &&...t)
|
||||
: f(std::bind(std::forward<F>(f), std::forward<T>(t)...)) {}
|
||||
Defer(Defer &&o) noexcept : f(std::move(o.f)) {}
|
||||
template <typename F> struct Defer {
|
||||
explicit Defer(F &&f) noexcept(std::is_nothrow_constructible_v<F, F &&>)
|
||||
: f(std::forward<F>(f)) {}
|
||||
~Defer() { f(); }
|
||||
|
||||
using ResultType = std::invoke_result_t<F, T...>;
|
||||
std::function<ResultType()> f;
|
||||
Defer(Defer &&o) = delete;
|
||||
Defer(const Defer &) = delete;
|
||||
Defer &operator=(const Defer &) = delete;
|
||||
Defer &operator=(Defer &&) = delete;
|
||||
|
||||
F f;
|
||||
};
|
||||
|
||||
template <typename F, typename... T> Defer<F, T...> defer(F &&f, T &&...t) {
|
||||
return Defer<F, T...>(std::forward<F>(f), std::forward<T>(t)...);
|
||||
template <typename F> [[nodiscard]] Defer<std::decay_t<F>> defer(F &&f) {
|
||||
return Defer<std::decay_t<F>>(std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename T, size_t N> constexpr size_t array_size(T (&)[N]) {
|
||||
|
||||
@ -38,8 +38,6 @@
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
TLSClientContext() = default;
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
@ -43,7 +43,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
SSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_BORINGSSL_H)
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
auto _ = [] {
|
||||
if (ngtcp2_crypto_ossl_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
@ -50,8 +50,6 @@ auto _ = []() {
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
TLSClientContext() = default;
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
@ -43,7 +43,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
SSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_OSSL_H)
|
||||
|
||||
@ -92,13 +92,13 @@ ptls_cipher_suite_t *cipher_suites[] = {
|
||||
} // namespace
|
||||
|
||||
TLSClientContext::TLSClientContext()
|
||||
: ctx_{
|
||||
.random_bytes = ptls_openssl_random_bytes,
|
||||
.get_time = &ptls_get_time,
|
||||
.key_exchanges = key_exchanges,
|
||||
.cipher_suites = cipher_suites,
|
||||
.require_dhe_on_psk = 1,
|
||||
}, sign_cert_{} {}
|
||||
: ctx_{
|
||||
.random_bytes = ptls_openssl_random_bytes,
|
||||
.get_time = &ptls_get_time,
|
||||
.key_exchanges = key_exchanges,
|
||||
.cipher_suites = cipher_suites,
|
||||
.require_dhe_on_psk = 1,
|
||||
} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (sign_cert_.key) {
|
||||
@ -147,7 +147,7 @@ int TLSClientContext::load_private_key(const char *private_key_file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto fp_d = defer(fclose, fp);
|
||||
auto fp_d = defer([fp] { fclose(fp); });
|
||||
|
||||
auto pkey = PEM_read_PrivateKey(fp, nullptr, nullptr, nullptr);
|
||||
if (pkey == nullptr) {
|
||||
@ -156,7 +156,7 @@ int TLSClientContext::load_private_key(const char *private_key_file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto pkey_d = defer(EVP_PKEY_free, pkey);
|
||||
auto pkey_d = defer([pkey] { EVP_PKEY_free(pkey); });
|
||||
|
||||
if (ptls_openssl_init_sign_certificate(&sign_cert_, pkey) != 0) {
|
||||
std::cerr << "ptls_openssl_init_sign_certificate failed" << std::endl;
|
||||
|
||||
@ -47,7 +47,7 @@ private:
|
||||
int load_private_key(const char *private_key_file);
|
||||
|
||||
ptls_context_t ctx_;
|
||||
ptls_openssl_sign_certificate_t sign_cert_;
|
||||
ptls_openssl_sign_certificate_t sign_cert_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_PICOTLS_H)
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
auto _ = [] {
|
||||
if (ngtcp2_crypto_quictls_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
@ -50,8 +50,6 @@ auto _ = []() {
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
TLSClientContext() = default;
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
@ -43,7 +43,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
SSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_QUICTLS_H)
|
||||
|
||||
@ -39,8 +39,6 @@
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientContext::TLSClientContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSClientContext::~TLSClientContext() {
|
||||
if (ssl_ctx_) {
|
||||
wolfSSL_CTX_free(ssl_ctx_);
|
||||
@ -86,7 +84,7 @@ int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto f_d = defer(wolfSSL_BIO_free, f);
|
||||
auto f_d = defer([f] { wolfSSL_BIO_free(f); });
|
||||
|
||||
if (!wolfSSL_PEM_write_bio(f, "WOLFSSL SESSION PARAMETERS", "", sbuffer,
|
||||
sz)) {
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
class TLSClientContext {
|
||||
public:
|
||||
TLSClientContext();
|
||||
TLSClientContext() = default;
|
||||
~TLSClientContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file);
|
||||
@ -45,7 +45,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
WOLFSSL_CTX *ssl_ctx_;
|
||||
WOLFSSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_CLIENT_CONTEXT_WOLFSSL_H)
|
||||
|
||||
@ -33,10 +33,6 @@
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled,
|
||||
|
||||
@ -39,8 +39,7 @@ class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
TLSClientSession() = default;
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
|
||||
@ -34,10 +34,6 @@
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled,
|
||||
|
||||
@ -39,8 +39,7 @@ class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
TLSClientSession() = default;
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
|
||||
@ -44,8 +44,6 @@ using namespace std::literals;
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {
|
||||
auto &hsprops = cptls_.handshake_properties;
|
||||
|
||||
@ -126,7 +124,7 @@ int TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx,
|
||||
std::cerr << "Could not read TLS session file " << config.session_file
|
||||
<< std::endl;
|
||||
} else {
|
||||
auto f_d = defer(BIO_free, f);
|
||||
auto f_d = defer([f] { BIO_free(f); });
|
||||
|
||||
char *name, *header;
|
||||
unsigned char *data;
|
||||
|
||||
@ -39,7 +39,7 @@ class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
TLSClientSession() = default;
|
||||
~TLSClientSession();
|
||||
|
||||
int init(bool &early_data_enabled, TLSClientContext &tls_ctx,
|
||||
|
||||
@ -34,10 +34,6 @@
|
||||
#include "template.h"
|
||||
#include "util.h"
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
int TLSClientSession::init(bool &early_data_enabled,
|
||||
|
||||
@ -39,8 +39,7 @@ class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
TLSClientSession() = default;
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
|
||||
@ -35,10 +35,6 @@
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
TLSClientSession::TLSClientSession() {}
|
||||
|
||||
TLSClientSession::~TLSClientSession() {}
|
||||
|
||||
extern Config config;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -39,8 +39,7 @@ class ClientBase;
|
||||
|
||||
class TLSClientSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSClientSession();
|
||||
~TLSClientSession();
|
||||
TLSClientSession() = default;
|
||||
|
||||
int init(bool &early_data_enabled, const TLSClientContext &tls_ctx,
|
||||
const char *remote_addr, ClientBase *client, uint32_t quic_version,
|
||||
|
||||
@ -40,8 +40,6 @@
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
@ -228,10 +226,10 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file,
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto pkey_d = defer(EVP_HPKE_KEY_free, pkey);
|
||||
auto pkey_d = defer([pkey] { EVP_HPKE_KEY_free(pkey); });
|
||||
|
||||
auto keys = SSL_ECH_KEYS_new();
|
||||
auto keys_d = defer(SSL_ECH_KEYS_free, keys);
|
||||
auto keys_d = defer([keys] { SSL_ECH_KEYS_free(keys); });
|
||||
|
||||
if (SSL_ECH_KEYS_add(keys, 1, echconf.ech_config.data(),
|
||||
echconf.ech_config.size(), pkey) != 1) {
|
||||
|
||||
@ -37,7 +37,7 @@ using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
TLSServerContext() = default;
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
@ -48,7 +48,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
SSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_BORINGSSL_H)
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
auto _ = [] {
|
||||
if (ngtcp2_crypto_ossl_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
@ -51,8 +51,6 @@ auto _ = []() {
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
|
||||
@ -37,7 +37,7 @@ using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
TLSServerContext() = default;
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
@ -48,7 +48,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
SSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_OSSL_H)
|
||||
|
||||
@ -90,8 +90,6 @@ ptls_on_client_hello_t on_client_hello_hq = {on_client_hello_hq_cb};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
auto ticket_hmac = EVP_sha256();
|
||||
|
||||
std::span<const uint8_t> get_ticket_key_name() {
|
||||
static std::array<uint8_t, 16> key_name;
|
||||
ptls_openssl_random_bytes(key_name.data(), key_name.size());
|
||||
@ -123,14 +121,21 @@ int ticket_key_cb(unsigned char *key_name, unsigned char *iv,
|
||||
static const auto static_key_name = get_ticket_key_name();
|
||||
static const auto static_key = get_ticket_key();
|
||||
static const auto static_hmac_key = get_ticket_hmac_key();
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
static const auto ticket_hmac = EVP_MD_fetch(nullptr, "sha256", nullptr);
|
||||
static const auto aes_256_cbc =
|
||||
EVP_CIPHER_fetch(nullptr, "AES-256-CBC", nullptr);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
static const auto ticket_hmac = EVP_sha256();
|
||||
static const auto aes_256_cbc = EVP_aes_256_cbc();
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
|
||||
if (enc) {
|
||||
ptls_openssl_random_bytes(iv, EVP_MAX_IV_LENGTH);
|
||||
|
||||
std::ranges::copy(static_key_name, key_name);
|
||||
|
||||
if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, static_key.data(),
|
||||
iv)) {
|
||||
if (!EVP_EncryptInit_ex(ctx, aes_256_cbc, nullptr, static_key.data(), iv)) {
|
||||
return 0;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
@ -163,8 +168,7 @@ int ticket_key_cb(unsigned char *key_name, unsigned char *iv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, static_key.data(),
|
||||
iv)) {
|
||||
if (!EVP_DecryptInit_ex(ctx, aes_256_cbc, nullptr, static_key.data(), iv)) {
|
||||
return 0;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
@ -280,18 +284,16 @@ ptls_cipher_suite_t *cipher_suites[] = {
|
||||
} // namespace
|
||||
|
||||
TLSServerContext::TLSServerContext()
|
||||
: ctx_{
|
||||
.random_bytes = ptls_openssl_random_bytes,
|
||||
.get_time = &ptls_get_time,
|
||||
.key_exchanges = key_exchanges,
|
||||
.cipher_suites = cipher_suites,
|
||||
.ticket_lifetime = 86400,
|
||||
.require_dhe_on_psk = 1,
|
||||
.server_cipher_preference = 1,
|
||||
.encrypt_ticket = &encrypt_ticket,
|
||||
},
|
||||
sign_cert_{}
|
||||
{}
|
||||
: ctx_{
|
||||
.random_bytes = ptls_openssl_random_bytes,
|
||||
.get_time = &ptls_get_time,
|
||||
.key_exchanges = key_exchanges,
|
||||
.cipher_suites = cipher_suites,
|
||||
.ticket_lifetime = 86400,
|
||||
.require_dhe_on_psk = 1,
|
||||
.server_cipher_preference = 1,
|
||||
.encrypt_ticket = &encrypt_ticket,
|
||||
} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (sign_cert_.key) {
|
||||
@ -317,7 +319,7 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file,
|
||||
ctx_.on_client_hello = &on_client_hello_hq;
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_picotls_configure_server_context(&ctx_) != 0) {
|
||||
std::cerr << "ngtcp2_crypto_picotls_configure_server_context failed"
|
||||
@ -349,7 +351,7 @@ int TLSServerContext::load_private_key(const char *private_key_file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto fp_d = defer(fclose, fp);
|
||||
auto fp_d = defer([fp] { fclose(fp); });
|
||||
|
||||
auto pkey = PEM_read_PrivateKey(fp, nullptr, nullptr, nullptr);
|
||||
if (pkey == nullptr) {
|
||||
@ -358,7 +360,7 @@ int TLSServerContext::load_private_key(const char *private_key_file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto pkey_d = defer(EVP_PKEY_free, pkey);
|
||||
auto pkey_d = defer([pkey] { EVP_PKEY_free(pkey); });
|
||||
|
||||
if (ptls_openssl_init_sign_certificate(&sign_cert_, pkey) != 0) {
|
||||
std::cerr << "ptls_openssl_init_sign_certificate failed" << std::endl;
|
||||
|
||||
@ -52,7 +52,7 @@ private:
|
||||
int load_private_key(const char *private_key_file);
|
||||
|
||||
ptls_context_t ctx_;
|
||||
ptls_openssl_sign_certificate_t sign_cert_;
|
||||
ptls_openssl_sign_certificate_t sign_cert_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_PICOTLS_H)
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
#include "template.h"
|
||||
|
||||
namespace {
|
||||
auto _ = []() {
|
||||
auto _ = [] {
|
||||
if (ngtcp2_crypto_quictls_init() != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
@ -51,8 +51,6 @@ auto _ = []() {
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
SSL_CTX_free(ssl_ctx_);
|
||||
|
||||
@ -37,7 +37,7 @@ using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
TLSServerContext() = default;
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
@ -48,7 +48,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
SSL_CTX *ssl_ctx_;
|
||||
SSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_QUICTLS_H)
|
||||
|
||||
@ -37,8 +37,6 @@
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerContext::TLSServerContext() : ssl_ctx_{nullptr} {}
|
||||
|
||||
TLSServerContext::~TLSServerContext() {
|
||||
if (ssl_ctx_) {
|
||||
wolfSSL_CTX_free(ssl_ctx_);
|
||||
|
||||
@ -38,7 +38,7 @@ using namespace ngtcp2;
|
||||
|
||||
class TLSServerContext {
|
||||
public:
|
||||
TLSServerContext();
|
||||
TLSServerContext() = default;
|
||||
~TLSServerContext();
|
||||
|
||||
int init(const char *private_key_file, const char *cert_file,
|
||||
@ -49,7 +49,7 @@ public:
|
||||
void enable_keylog();
|
||||
|
||||
private:
|
||||
WOLFSSL_CTX *ssl_ctx_;
|
||||
WOLFSSL_CTX *ssl_ctx_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SERVER_CONTEXT_WOLFSSL_H)
|
||||
|
||||
@ -34,10 +34,6 @@
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
@ -36,8 +36,7 @@ class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
TLSServerSession() = default;
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
|
||||
@ -31,10 +31,6 @@
|
||||
#include "tls_server_context_ossl.h"
|
||||
#include "server_base.h"
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
@ -36,8 +36,7 @@ class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
TLSServerSession() = default;
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
|
||||
@ -37,10 +37,6 @@ using namespace ngtcp2;
|
||||
|
||||
extern Config config;
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(TLSServerContext &tls_ctx, HandlerBase *handler) {
|
||||
cptls_.ptls = ptls_server_new(tls_ctx.get_native_handle());
|
||||
if (!cptls_.ptls) {
|
||||
|
||||
@ -36,8 +36,7 @@ class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
TLSServerSession() = default;
|
||||
|
||||
int init(TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
|
||||
@ -31,10 +31,6 @@
|
||||
#include "tls_server_context_quictls.h"
|
||||
#include "server_base.h"
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
@ -36,8 +36,7 @@ class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
TLSServerSession() = default;
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
|
||||
@ -29,10 +29,6 @@
|
||||
#include "tls_server_context_wolfssl.h"
|
||||
#include "server_base.h"
|
||||
|
||||
TLSServerSession::TLSServerSession() {}
|
||||
|
||||
TLSServerSession::~TLSServerSession() {}
|
||||
|
||||
int TLSServerSession::init(const TLSServerContext &tls_ctx,
|
||||
HandlerBase *handler) {
|
||||
auto ssl_ctx = tls_ctx.get_native_handle();
|
||||
|
||||
@ -36,8 +36,7 @@ class HandlerBase;
|
||||
|
||||
class TLSServerSession : public TLSSessionBase {
|
||||
public:
|
||||
TLSServerSession();
|
||||
~TLSServerSession();
|
||||
TLSServerSession() = default;
|
||||
|
||||
int init(const TLSServerContext &tls_ctx, HandlerBase *handler);
|
||||
// ticket is sent automatically.
|
||||
|
||||
@ -33,14 +33,14 @@ using namespace ngtcp2;
|
||||
using namespace std::literals;
|
||||
|
||||
TLSSessionBase::TLSSessionBase() {
|
||||
ngtcp2_crypto_ossl_ctx_new(&ossl_ctx_, NULL);
|
||||
ngtcp2_crypto_ossl_ctx_new(&ossl_ctx_, nullptr);
|
||||
}
|
||||
|
||||
TLSSessionBase::~TLSSessionBase() {
|
||||
auto ssl = ngtcp2_crypto_ossl_ctx_get_ssl(ossl_ctx_);
|
||||
|
||||
if (ssl) {
|
||||
SSL_set_app_data(ssl, NULL);
|
||||
SSL_set_app_data(ssl, nullptr);
|
||||
SSL_free(ssl);
|
||||
}
|
||||
|
||||
|
||||
@ -32,8 +32,6 @@
|
||||
using namespace ngtcp2;
|
||||
using namespace std::literals;
|
||||
|
||||
TLSSessionBase::TLSSessionBase() : ssl_{nullptr} {}
|
||||
|
||||
TLSSessionBase::~TLSSessionBase() {
|
||||
if (ssl_) {
|
||||
SSL_free(ssl_);
|
||||
@ -68,12 +66,11 @@ std::string_view TLSSessionBase::get_negotiated_group() const {
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
auto key_del = defer(EVP_PKEY_free, key);
|
||||
auto key_del = defer([key] { EVP_PKEY_free(key); });
|
||||
|
||||
auto nid = EVP_PKEY_id(key);
|
||||
if (nid == EVP_PKEY_EC) {
|
||||
auto ec = EVP_PKEY_get1_EC_KEY(key);
|
||||
auto ec_del = defer(EC_KEY_free, ec);
|
||||
auto ec = EVP_PKEY_get0_EC_KEY(key);
|
||||
|
||||
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
class TLSSessionBase {
|
||||
public:
|
||||
TLSSessionBase();
|
||||
TLSSessionBase() = default;
|
||||
~TLSSessionBase();
|
||||
|
||||
SSL *get_native_handle() const;
|
||||
@ -48,7 +48,7 @@ public:
|
||||
void enable_keylog() {}
|
||||
|
||||
protected:
|
||||
SSL *ssl_;
|
||||
SSL *ssl_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SESSION_BASE_QUICTLS_H)
|
||||
|
||||
@ -30,8 +30,6 @@
|
||||
|
||||
using namespace ngtcp2;
|
||||
|
||||
TLSSessionBase::TLSSessionBase() : ssl_{nullptr} {}
|
||||
|
||||
TLSSessionBase::~TLSSessionBase() {
|
||||
if (ssl_) {
|
||||
wolfSSL_free(ssl_);
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
class TLSSessionBase {
|
||||
public:
|
||||
TLSSessionBase();
|
||||
TLSSessionBase() = default;
|
||||
~TLSSessionBase();
|
||||
|
||||
WOLFSSL *get_native_handle() const;
|
||||
@ -54,7 +54,7 @@ public:
|
||||
void enable_keylog() {}
|
||||
|
||||
protected:
|
||||
WOLFSSL *ssl_;
|
||||
WOLFSSL *ssl_{};
|
||||
};
|
||||
|
||||
#endif // !defined(TLS_SESSION_BASE_WOLFSSL_H)
|
||||
|
||||
@ -35,7 +35,7 @@ namespace ngtcp2 {
|
||||
|
||||
namespace tls {
|
||||
|
||||
constexpr uint16_t CERTIFICATE_COMPRESSION_ALGO_BROTLI = 2;
|
||||
inline constexpr uint16_t CERTIFICATE_COMPRESSION_ALGO_BROTLI = 2;
|
||||
|
||||
#ifdef HAVE_LIBBROTLI
|
||||
int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len);
|
||||
|
||||
47
deps/ngtcp2/ngtcp2/examples/util.cc
vendored
47
deps/ngtcp2/ngtcp2/examples/util.cc
vendored
@ -40,6 +40,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
@ -108,7 +109,7 @@ uint64_t round2even(uint64_t n) {
|
||||
} // namespace
|
||||
|
||||
std::string format_durationf(uint64_t ns) {
|
||||
static constexpr const std::string_view units[] = {"us"sv, "ms"sv, "s"sv};
|
||||
static constexpr std::string_view units[] = {"us"sv, "ms"sv, "s"sv};
|
||||
if (ns < 1000) {
|
||||
return format_uint(ns) + "ns";
|
||||
}
|
||||
@ -351,15 +352,8 @@ std::string straddr(const sockaddr *sa, socklen_t salen) {
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16_t port(const sockaddr_union *su) {
|
||||
switch (su->sa.sa_family) {
|
||||
case AF_INET:
|
||||
return ntohs(su->in.sin_port);
|
||||
case AF_INET6:
|
||||
return ntohs(su->in6.sin6_port);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
std::string straddr(const Address &addr) {
|
||||
return straddr(addr.as_sockaddr(), addr.size());
|
||||
}
|
||||
|
||||
bool prohibited_port(uint16_t port) {
|
||||
@ -796,7 +790,7 @@ std::optional<std::vector<uint8_t>> read_file(const std::string_view &path) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto fd_d = defer(close, fd);
|
||||
auto fd_d = defer([fd] { close(fd); });
|
||||
|
||||
auto size = lseek(fd, 0, SEEK_END);
|
||||
if (size == static_cast<off_t>(-1)) {
|
||||
@ -809,13 +803,28 @@ std::optional<std::vector<uint8_t>> read_file(const std::string_view &path) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto addr_d = defer(munmap, addr, static_cast<size_t>(size));
|
||||
auto addr_d =
|
||||
defer([addr, size] { munmap(addr, static_cast<size_t>(size)); });
|
||||
|
||||
auto p = static_cast<uint8_t *>(addr);
|
||||
|
||||
return {{p, p + size}};
|
||||
}
|
||||
|
||||
size_t clamp_buffer_size(ngtcp2_conn *conn, size_t buflen, size_t gso_burst) {
|
||||
return std::min(gso_burst == 0
|
||||
? ngtcp2_conn_get_send_quantum(conn)
|
||||
: ngtcp2_conn_get_path_max_tx_udp_payload_size(conn) *
|
||||
gso_burst,
|
||||
buflen);
|
||||
}
|
||||
|
||||
bool recv_pkt_time_threshold_exceeded(bool time_sensitive, ngtcp2_tstamp start,
|
||||
size_t pktcnt) {
|
||||
return time_sensitive && pktcnt &&
|
||||
util::timestamp() - start >= NGTCP2_MILLISECONDS;
|
||||
}
|
||||
|
||||
std::optional<ECHServerConfig>
|
||||
read_ech_server_config(const std::string_view &path) {
|
||||
auto pkey = read_hpke_private_key_pem(path);
|
||||
@ -835,7 +844,7 @@ read_ech_server_config(const std::string_view &path) {
|
||||
}
|
||||
|
||||
std::span<uint64_t, 2> generate_siphash_key() {
|
||||
static auto key = []() {
|
||||
static auto key = [] {
|
||||
std::array<uint64_t, 2> key;
|
||||
|
||||
auto rv = generate_secure_random(as_writable_uint8_span(std::span{key}));
|
||||
@ -852,6 +861,18 @@ std::span<uint64_t, 2> generate_siphash_key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
std::string realpath(const char *path) {
|
||||
auto cpath = ::realpath(path, nullptr);
|
||||
if (!cpath) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
auto cpath_d = defer([cpath] { free(cpath); });
|
||||
|
||||
return cpath;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ngtcp2_cid &cid) {
|
||||
|
||||
106
deps/ngtcp2/ngtcp2/examples/util.h
vendored
106
deps/ngtcp2/ngtcp2/examples/util.h
vendored
@ -80,18 +80,23 @@ inline nghttp3_nv make_nv_nn(const std::string_view &name,
|
||||
NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE);
|
||||
}
|
||||
|
||||
constinit const auto hexdigits = []() {
|
||||
constexpr char LOWER_XDIGITS[] = "0123456789abcdef";
|
||||
inline constexpr char LOWER_XDIGITS[] = "0123456789abcdef";
|
||||
|
||||
std::array<char, 512> tbl;
|
||||
template <std::weakly_incrementable O>
|
||||
requires(std::indirectly_writable<O, char>)
|
||||
constexpr O format_hex_uint8(uint8_t b, O result) {
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif // __GNUC__
|
||||
*result++ = LOWER_XDIGITS[b >> 4];
|
||||
*result++ = LOWER_XDIGITS[b & 0xf];
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif // __GNUC__
|
||||
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
tbl[i * 2] = LOWER_XDIGITS[static_cast<size_t>(i >> 4)];
|
||||
tbl[i * 2 + 1] = LOWER_XDIGITS[static_cast<size_t>(i & 0xf)];
|
||||
}
|
||||
|
||||
return tbl;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
// format_hex converts a range [|first|, |last|) in hex format, and
|
||||
// stores the result in another range, beginning at |result|. It
|
||||
@ -102,9 +107,7 @@ requires(std::indirectly_writable<O, char> &&
|
||||
sizeof(std::iter_value_t<I>) == sizeof(uint8_t))
|
||||
constexpr O format_hex(I first, I last, O result) {
|
||||
for (; first != last; ++first) {
|
||||
result = std::ranges::copy_n(
|
||||
hexdigits.data() + static_cast<uint8_t>(*first) * 2, 2, result)
|
||||
.out;
|
||||
result = format_hex_uint8(static_cast<uint8_t>(*first), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -172,7 +175,7 @@ template <std::unsigned_integral T, std::weakly_incrementable O>
|
||||
requires(std::indirectly_writable<O, char>)
|
||||
constexpr O format_hex(T n, O result) {
|
||||
if constexpr (sizeof(n) == 1) {
|
||||
return std::ranges::copy_n(hexdigits.data() + n * 2, 2, result).out;
|
||||
return format_hex_uint8(n, result);
|
||||
}
|
||||
|
||||
if constexpr (std::endian::native == std::endian::little) {
|
||||
@ -180,15 +183,14 @@ constexpr O format_hex(T n, O result) {
|
||||
auto p = end + sizeof(n);
|
||||
|
||||
for (; p != end; --p) {
|
||||
result =
|
||||
std::ranges::copy_n(hexdigits.data() + *(p - 1) * 2, 2, result).out;
|
||||
result = format_hex_uint8(*(p - 1), result);
|
||||
}
|
||||
} else {
|
||||
auto p = reinterpret_cast<uint8_t *>(&n);
|
||||
auto end = p + sizeof(n);
|
||||
|
||||
for (; p != end; ++p) {
|
||||
result = std::ranges::copy_n(hexdigits.data() + *p * 2, 2, result).out;
|
||||
result = format_hex_uint8(*p, result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,29 +233,22 @@ bool numeric_host(const char *hostname, int family);
|
||||
// or -1.
|
||||
int hexdump(FILE *out, const void *data, size_t datalen);
|
||||
|
||||
static constexpr uint8_t lowcase_tbl[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
|
||||
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
|
||||
'z', 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
|
||||
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
|
||||
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
|
||||
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
|
||||
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
|
||||
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
|
||||
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
|
||||
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
|
||||
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
|
||||
255,
|
||||
};
|
||||
inline constexpr auto lowcase_tbl = [] {
|
||||
std::array<char, 256> tbl;
|
||||
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
if ('A' <= i && i <= 'Z') {
|
||||
tbl[i] = static_cast<char>(i - 'A' + 'a');
|
||||
} else {
|
||||
tbl[i] = static_cast<char>(i);
|
||||
}
|
||||
}
|
||||
|
||||
return tbl;
|
||||
}();
|
||||
|
||||
constexpr char lowcase(char c) noexcept {
|
||||
return as_signed(lowcase_tbl[static_cast<uint8_t>(c)]);
|
||||
return lowcase_tbl[static_cast<uint8_t>(c)];
|
||||
}
|
||||
|
||||
struct CaseCmp {
|
||||
@ -277,8 +272,8 @@ ngtcp2_cid make_cid_key(std::span<const uint8_t> cid);
|
||||
// straddr stringifies |sa| of length |salen| in a format "[IP]:PORT".
|
||||
std::string straddr(const sockaddr *sa, socklen_t salen);
|
||||
|
||||
// port returns port from |su|.
|
||||
uint16_t port(const sockaddr_union *su);
|
||||
// straddr stringifies |addr| in a format "[IP]:PORT".
|
||||
std::string straddr(const Address &addr);
|
||||
|
||||
// prohibited_port returns true if |port| is prohibited as a client
|
||||
// port.
|
||||
@ -293,7 +288,7 @@ std::string_view strccalgo(ngtcp2_cc_algo cc_algo);
|
||||
std::optional<std::unordered_map<std::string, std::string>>
|
||||
read_mime_types(const std::string_view &filename);
|
||||
|
||||
constinit const auto count_digit_tbl = []() {
|
||||
inline constexpr auto count_digit_tbl = [] {
|
||||
std::array<uint64_t, std::numeric_limits<uint64_t>::digits10> tbl;
|
||||
|
||||
uint64_t x = 1;
|
||||
@ -321,7 +316,7 @@ template <std::unsigned_integral T> constexpr size_t count_digit(T x) {
|
||||
return y + 1;
|
||||
}
|
||||
|
||||
constinit const auto utos_digits = []() {
|
||||
inline constexpr auto utos_digits = [] {
|
||||
std::array<char, 200> a;
|
||||
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
@ -443,7 +438,7 @@ int generate_secret(std::span<uint8_t> secret);
|
||||
std::string normalize_path(const std::string_view &path);
|
||||
|
||||
template <std::predicate<size_t> Pred>
|
||||
constexpr auto pred_tbl_gen256(Pred pred) {
|
||||
consteval auto pred_tbl_gen256(Pred pred) {
|
||||
std::array<bool, 256> tbl;
|
||||
|
||||
for (size_t i = 0; i < tbl.size(); ++i) {
|
||||
@ -453,17 +448,19 @@ constexpr auto pred_tbl_gen256(Pred pred) {
|
||||
return tbl;
|
||||
}
|
||||
|
||||
constexpr auto digit_pred(size_t i) noexcept { return '0' <= i && i <= '9'; }
|
||||
consteval auto digit_pred(size_t i) noexcept { return '0' <= i && i <= '9'; }
|
||||
|
||||
constinit const auto is_digit_tbl = pred_tbl_gen256(digit_pred);
|
||||
inline constexpr auto is_digit_tbl = pred_tbl_gen256(digit_pred);
|
||||
|
||||
constexpr bool is_digit(char c) noexcept {
|
||||
return is_digit_tbl[static_cast<uint8_t>(c)];
|
||||
}
|
||||
|
||||
constinit const auto is_hex_digit_tbl = pred_tbl_gen256([](auto i) {
|
||||
consteval auto hex_digit_pred(size_t i) noexcept {
|
||||
return digit_pred(i) || ('A' <= i && i <= 'F') || ('a' <= i && i <= 'f');
|
||||
});
|
||||
}
|
||||
|
||||
inline constexpr auto is_hex_digit_tbl = pred_tbl_gen256(hex_digit_pred);
|
||||
|
||||
constexpr bool is_hex_digit(char c) noexcept {
|
||||
return is_hex_digit_tbl[static_cast<uint8_t>(c)];
|
||||
@ -478,7 +475,7 @@ constexpr bool is_hex_string(R &&r) {
|
||||
return !(std::ranges::size(r) & 1) && std::ranges::all_of(r, is_hex_digit);
|
||||
}
|
||||
|
||||
constinit const auto hex_to_uint_tbl = []() {
|
||||
inline constexpr auto hex_to_uint_tbl = [] {
|
||||
std::array<uint32_t, 256> tbl;
|
||||
|
||||
std::ranges::fill(tbl, 256);
|
||||
@ -531,12 +528,17 @@ std::vector<std::string_view> split_str(const std::string_view &s,
|
||||
char delim = ',');
|
||||
|
||||
// parse_version parses |s| to get 4 byte QUIC version. |s| must be a
|
||||
// hex string and must start with "0x" (.e.g, 0x00000001).
|
||||
// hex string and must start with "0x" (e.g., 0x00000001).
|
||||
std::optional<uint32_t> parse_version(const std::string_view &s);
|
||||
|
||||
// read_file reads a file denoted by |path| and returns its content.
|
||||
std::optional<std::vector<uint8_t>> read_file(const std::string_view &path);
|
||||
|
||||
size_t clamp_buffer_size(ngtcp2_conn *conn, size_t buflen, size_t gso_burst);
|
||||
|
||||
bool recv_pkt_time_threshold_exceeded(bool time_sensitive, ngtcp2_tstamp start,
|
||||
size_t pktcnt);
|
||||
|
||||
enum HPKEPrivateKeyType : uint16_t {
|
||||
HPKE_DHKEM_X25519_HKDF_SHA256 = 0x0020,
|
||||
};
|
||||
@ -576,6 +578,9 @@ constexpr std::string_view get_string(const std::string_view &uri,
|
||||
return {uri.data() + p->off, p->len};
|
||||
}
|
||||
|
||||
// realpath returns the canonicalized absolute path to |path|.
|
||||
std::string realpath(const char *path);
|
||||
|
||||
} // namespace util
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ngtcp2_cid &cid);
|
||||
@ -585,7 +590,8 @@ std::ostream &operator<<(std::ostream &os, const ngtcp2_cid &cid);
|
||||
namespace std {
|
||||
template <> struct hash<ngtcp2_cid> {
|
||||
hash() {
|
||||
std::ranges::copy(ngtcp2::util::generate_siphash_key(), key.begin());
|
||||
std::ranges::copy(ngtcp2::util::generate_siphash_key(),
|
||||
std::ranges::begin(key));
|
||||
}
|
||||
|
||||
std::size_t operator()(const ngtcp2_cid &cid) const noexcept {
|
||||
|
||||
29
deps/ngtcp2/ngtcp2/examples/util_openssl.cc
vendored
29
deps/ngtcp2/ngtcp2/examples/util_openssl.cc
vendored
@ -68,10 +68,17 @@ int generate_secret(std::span<uint8_t> secret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto ctx_deleter = defer(EVP_MD_CTX_free, ctx);
|
||||
auto ctx_deleter = defer([ctx] { EVP_MD_CTX_free(ctx); });
|
||||
|
||||
static const auto sha256 =
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
EVP_MD_fetch(nullptr, "sha256", nullptr);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
EVP_sha256();
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
|
||||
auto mdlen = static_cast<unsigned int>(secret.size());
|
||||
if (!EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr) ||
|
||||
if (!EVP_DigestInit_ex(ctx, sha256, nullptr) ||
|
||||
!EVP_DigestUpdate(ctx, rand.data(), rand.size()) ||
|
||||
!EVP_DigestFinal_ex(ctx, secret.data(), &mdlen)) {
|
||||
return -1;
|
||||
@ -80,10 +87,6 @@ int generate_secret(std::span<uint8_t> secret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void openssl_free_wrap(void *ptr) { OPENSSL_free(ptr); }
|
||||
} // namespace
|
||||
|
||||
std::optional<HPKEPrivateKey>
|
||||
read_hpke_private_key_pem(const std::string_view &filename) {
|
||||
auto f = BIO_new_file(filename.data(), "r");
|
||||
@ -92,7 +95,7 @@ read_hpke_private_key_pem(const std::string_view &filename) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto f_d = defer(BIO_free, f);
|
||||
auto f_d = defer([f] { BIO_free(f); });
|
||||
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
@ -100,7 +103,7 @@ read_hpke_private_key_pem(const std::string_view &filename) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pkey_d = defer(EVP_PKEY_free, pkey);
|
||||
auto pkey_d = defer([pkey] { EVP_PKEY_free(pkey); });
|
||||
|
||||
HPKEPrivateKey res;
|
||||
|
||||
@ -134,7 +137,7 @@ std::optional<std::vector<uint8_t>> read_pem(const std::string_view &filename,
|
||||
return {};
|
||||
}
|
||||
|
||||
auto f_d = defer(BIO_free, f);
|
||||
auto f_d = defer([f] { BIO_free(f); });
|
||||
|
||||
for (;;) {
|
||||
char *pem_type, *header;
|
||||
@ -147,9 +150,11 @@ std::optional<std::vector<uint8_t>> read_pem(const std::string_view &filename,
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pem_type_d = defer(openssl_free_wrap, pem_type);
|
||||
auto pem_header = defer(openssl_free_wrap, header);
|
||||
auto data_d = defer(openssl_free_wrap, data);
|
||||
auto pem_d = defer([pem_type, header, data] {
|
||||
OPENSSL_free(pem_type);
|
||||
OPENSSL_free(header);
|
||||
OPENSSL_free(data);
|
||||
});
|
||||
|
||||
if (type != pem_type) {
|
||||
continue;
|
||||
|
||||
44
deps/ngtcp2/ngtcp2/examples/util_test.cc
vendored
44
deps/ngtcp2/ngtcp2/examples/util_test.cc
vendored
@ -419,6 +419,50 @@ void test_util_format_hex() {
|
||||
assert_stdstring_equal("deadbeef"s, util::format_hex(a));
|
||||
assert_stdstring_equal("deadbeef"s, util::format_hex(0xdeadbeef));
|
||||
assert_stdstring_equal("beef"s, util::format_hex(a.data() + 2, 2));
|
||||
|
||||
std::array<char, 64> buf;
|
||||
|
||||
assert_stdsv_equal(
|
||||
"00"sv, (std::string_view{std::ranges::begin(buf),
|
||||
util::format_hex(static_cast<uint8_t>(0u),
|
||||
std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"ec"sv, (std::string_view{std::ranges::begin(buf),
|
||||
util::format_hex(static_cast<uint8_t>(0xecu),
|
||||
std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"00000000"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_hex(0u, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"0000ab01"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_hex(0xab01u, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"deadbeefbaadf00d"sv,
|
||||
(std::string_view{
|
||||
std::ranges::begin(buf),
|
||||
util::format_hex(0xdeadbeefbaadf00du, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"ffffffffffffffff"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_hex(std::numeric_limits<uint64_t>::max(),
|
||||
std::ranges::begin(buf))}));
|
||||
|
||||
std::vector<char> char_vec;
|
||||
util::format_hex(a, std::back_inserter(char_vec));
|
||||
|
||||
assert_stdsv_equal("deadbeef"sv,
|
||||
(std::string_view{std::ranges::begin(char_vec),
|
||||
std::ranges::end(char_vec)}));
|
||||
|
||||
std::vector<uint8_t> uint8_vec;
|
||||
util::format_hex(a, std::back_inserter(uint8_vec));
|
||||
|
||||
assert_stdsv_equal(
|
||||
"deadbeef"sv,
|
||||
(std::string_view{reinterpret_cast<const char *>(uint8_vec.data()),
|
||||
uint8_vec.size()}));
|
||||
}
|
||||
|
||||
void test_util_decode_hex() {
|
||||
|
||||
16
deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc
vendored
16
deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc
vendored
@ -87,7 +87,7 @@ std::optional<std::vector<uint8_t>> read_pem(const std::string_view &filename,
|
||||
return {};
|
||||
}
|
||||
|
||||
auto f_d = defer(wolfSSL_BIO_free, f);
|
||||
auto f_d = defer([f] { wolfSSL_BIO_free(f); });
|
||||
|
||||
char *pem_type, *header;
|
||||
unsigned char *data;
|
||||
@ -98,9 +98,11 @@ std::optional<std::vector<uint8_t>> read_pem(const std::string_view &filename,
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pem_type_d = defer(wolfSSL_OPENSSL_free, pem_type);
|
||||
auto header_d = defer(wolfSSL_OPENSSL_free, header);
|
||||
auto data_d = defer(wolfSSL_OPENSSL_free, data);
|
||||
auto pem_d = defer([pem_type, header, data] {
|
||||
wolfSSL_OPENSSL_free(pem_type);
|
||||
wolfSSL_OPENSSL_free(header);
|
||||
wolfSSL_OPENSSL_free(data);
|
||||
});
|
||||
|
||||
if (type != pem_type) {
|
||||
std::cerr << name << " file " << filename << " contains unexpected type"
|
||||
@ -134,8 +136,12 @@ const char *crypto_default_ciphers() {
|
||||
const char *crypto_default_groups() {
|
||||
return "X25519:P-256:P-384:P-521"
|
||||
#ifdef WOLFSSL_HAVE_MLKEM
|
||||
# if LIBWOLFSSL_VERSION_HEX < 0x05008004
|
||||
":X25519_ML_KEM_768"
|
||||
#endif // WOLFSSL_HAVE_MLKEM
|
||||
# else // LIBWOLFSSL_VERSION_HEX >= 0x05008004
|
||||
":X25519MLKEM768"
|
||||
# endif // LIBWOLFSSL_VERSION_HEX >= 0x05008004
|
||||
#endif // WOLFSSL_HAVE_MLKEM
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
202
deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
vendored
202
deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
vendored
@ -306,15 +306,29 @@ typedef struct ngtcp2_mem {
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE` is the default maximum UDP
|
||||
* datagram payload size that the local endpoint transmits.
|
||||
* datagram payload size that the local endpoint transmits without
|
||||
* Path MTU Discovery (PMTUD) or the custom settings (see
|
||||
* :member:`ngtcp2_settings.max_tx_udp_payload_size` and
|
||||
* :member:`ngtcp2_settings.no_tx_udp_payload_size_shaping`).
|
||||
*/
|
||||
#define NGTCP2_MAX_UDP_PAYLOAD_SIZE 1200
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE` is the maximum UDP
|
||||
* :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE` is the maximum UDP datagram
|
||||
* payload size that this library can output.
|
||||
*/
|
||||
#define NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE 65527
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE` was the maximum UDP
|
||||
* datagram payload size that Path MTU Discovery can discover.
|
||||
*
|
||||
* Deprecated since v1.17.0. Path MTU Discovery is not capped to this
|
||||
* value anymore.
|
||||
*/
|
||||
#define NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE 1452
|
||||
|
||||
@ -1561,7 +1575,8 @@ typedef struct ngtcp2_transport_params {
|
||||
} ngtcp2_transport_params;
|
||||
|
||||
#define NGTCP2_CONN_INFO_V1 1
|
||||
#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V1
|
||||
#define NGTCP2_CONN_INFO_V2 2
|
||||
#define NGTCP2_CONN_INFO_VERSION NGTCP2_CONN_INFO_V2
|
||||
|
||||
/**
|
||||
* @struct
|
||||
@ -1600,6 +1615,52 @@ typedef struct ngtcp2_conn_info {
|
||||
* packets which have not been acknowledged.
|
||||
*/
|
||||
uint64_t bytes_in_flight;
|
||||
/* The following fields have been added since NGTCP2_CONN_INFO_V2. */
|
||||
/**
|
||||
* :member:`pkt_sent` is the number of QUIC packets sent. This
|
||||
* field has been available since v1.16.0.
|
||||
*/
|
||||
uint64_t pkt_sent;
|
||||
/**
|
||||
* :member:`bytes_sent` is the number of bytes (the sum of QUIC
|
||||
* packet length) sent. This field has been available since
|
||||
* v1.16.0.
|
||||
*/
|
||||
uint64_t bytes_sent;
|
||||
/**
|
||||
* :member:`pkt_recv` is the number of QUIC packets received,
|
||||
* excluding discarded ones. This field has been available since
|
||||
* v1.16.0.
|
||||
*/
|
||||
uint64_t pkt_recv;
|
||||
/**
|
||||
* :member:`bytes_recv` is the number of bytes (the sum of QUIC
|
||||
* packet length) received, excluding discarded ones. This field
|
||||
* has been available since v1.16.0.
|
||||
*/
|
||||
uint64_t bytes_recv;
|
||||
/**
|
||||
* :member:`pkt_lost` is the number of QUIC packets that are
|
||||
* considered lost, excluding PMTUD packets. This field has been
|
||||
* available since v1.16.0.
|
||||
*/
|
||||
uint64_t pkt_lost;
|
||||
/**
|
||||
* :member:`bytes_lost` is the number of bytes (the sum of QUIC
|
||||
* packet length) lost, excluding PMTUD packets. This field has
|
||||
* been available since v1.16.0.
|
||||
*/
|
||||
uint64_t bytes_lost;
|
||||
/**
|
||||
* :member:`ping_recv` is the number of PING frames received. This
|
||||
* field has been available since v1.16.0.
|
||||
*/
|
||||
uint64_t ping_recv;
|
||||
/**
|
||||
* :member:`pkt_discarded` is the number of QUIC packets discarded.
|
||||
* This field has been available since v1.16.0.
|
||||
*/
|
||||
uint64_t pkt_discarded;
|
||||
} ngtcp2_conn_info;
|
||||
|
||||
/**
|
||||
@ -1739,7 +1800,9 @@ typedef struct ngtcp2_settings {
|
||||
ngtcp2_printf log_printf;
|
||||
/**
|
||||
* :member:`max_tx_udp_payload_size` is the maximum size of UDP
|
||||
* datagram payload that the local endpoint transmits.
|
||||
* datagram payload that the local endpoint transmits. This must be
|
||||
* larger than or equal to :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE`, and
|
||||
* less then or equal to :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE`.
|
||||
*/
|
||||
size_t max_tx_udp_payload_size;
|
||||
/**
|
||||
@ -1904,12 +1967,13 @@ typedef struct ngtcp2_settings {
|
||||
/**
|
||||
* :member:`pmtud_probes` is the array of UDP datagram payload size
|
||||
* to probe during Path MTU Discovery. The discovery is done in the
|
||||
* order appeared in this array. The size must be strictly larger
|
||||
* than 1200, otherwise the behavior is undefined. The maximum
|
||||
* value in this array should be set to
|
||||
* :member:`max_tx_udp_payload_size`. If this field is not set, the
|
||||
* predefined PMTUD probes are made. This field has been available
|
||||
* since v1.4.0.
|
||||
* order appeared in this array. The payload size must be strictly
|
||||
* larger than :macro:`NGTCP2_MAX_UDP_PAYLOAD_SIZE`, and less than
|
||||
* or equal to :macro:`NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE`. Otherwise
|
||||
* the behavior is undefined. The maximum value in this array
|
||||
* should be set to :member:`max_tx_udp_payload_size`. If this
|
||||
* field is not set, the predefined PMTUD probes are made. This
|
||||
* field has been available since v1.4.0.
|
||||
*/
|
||||
const uint16_t *pmtud_probes;
|
||||
/**
|
||||
@ -4108,9 +4172,7 @@ NGTCP2_EXTERN void ngtcp2_conn_set_keep_alive_timeout(ngtcp2_conn *conn,
|
||||
* `ngtcp2_conn_get_expiry` returns the next expiry time. It returns
|
||||
* ``UINT64_MAX`` if there is no next expiry.
|
||||
*
|
||||
* Call `ngtcp2_conn_handle_expiry` and then
|
||||
* `ngtcp2_conn_writev_stream` (or `ngtcp2_conn_writev_datagram`) when
|
||||
* the expiry time has passed.
|
||||
* Call `ngtcp2_conn_handle_expiry` when the expiry time has passed.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn);
|
||||
|
||||
@ -4118,6 +4180,20 @@ NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_expiry(ngtcp2_conn *conn);
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_conn_handle_expiry` handles expired timer.
|
||||
*
|
||||
* If it returns :macro:`NGTCP2_ERR_IDLE_CLOSE`, it means that an idle
|
||||
* timer has fired for this particular connection. In this case, drop
|
||||
* the connection without calling
|
||||
* `ngtcp2_conn_write_connection_close`. If it returns any of the
|
||||
* other negative error codes, close the connection by sending the
|
||||
* terminal packet produced by `ngtcp2_conn_write_connection_close`.
|
||||
* Otherwise, schedule `ngtcp2_conn_writev_stream` call. An
|
||||
* application may call any number of additional
|
||||
* `ngtcp2_conn_read_pkt` and `ngtcp2_conn_handle_expiry` before
|
||||
* calling `ngtcp2_conn_writev_stream`. After calling
|
||||
* `ngtcp2_conn_writev_stream`, new expiry is set. The application
|
||||
* should call `ngtcp2_conn_get_expiry` to get a new deadline and set
|
||||
* the timer.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_conn_handle_expiry(ngtcp2_conn *conn,
|
||||
ngtcp2_tstamp ts);
|
||||
@ -5503,7 +5579,9 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr,
|
||||
* |destlen| could be shorten by some factors (e.g., server side
|
||||
* amplification limit). This function returns
|
||||
* :macro:`NGTCP2_ERR_NOBUF` if the resulting buffer is too small even
|
||||
* if the given buffer has enough space.
|
||||
* if the given buffer has enough space. This can happen if sending a
|
||||
* packet would exceed a transmission limit (e.g., for amplification
|
||||
* attack protection).
|
||||
*
|
||||
* This function must not be called from inside the callback
|
||||
* functions.
|
||||
@ -5518,7 +5596,8 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr,
|
||||
* :macro:`NGTCP2_ERR_NOMEM`
|
||||
* Out of memory
|
||||
* :macro:`NGTCP2_ERR_NOBUF`
|
||||
* Buffer is too small
|
||||
* Buffer is too small or packet would exceed the transmission
|
||||
* limit (e.g., for amplification attack protection).
|
||||
* :macro:`NGTCP2_ERR_INVALID_STATE`
|
||||
* The current state does not allow sending CONNECTION_CLOSE
|
||||
* frame.
|
||||
@ -5582,6 +5661,26 @@ NGTCP2_EXTERN int ngtcp2_conn_set_stream_user_data(ngtcp2_conn *conn,
|
||||
int64_t stream_id,
|
||||
void *stream_user_data);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_conn_get_stream_user_data` returns stream_user_data
|
||||
* associated to the stream identified by |stream_id|. If the stream
|
||||
* is not found, or no stream data is associated to the stream, this
|
||||
* function returns NULL.
|
||||
*
|
||||
* The stream_user_data can be associated to the stream by one of the
|
||||
* following functions:
|
||||
*
|
||||
* - `ngtcp2_conn_open_bidi_stream`
|
||||
* - `ngtcp2_conn_open_uni_stream`
|
||||
* - `ngtcp2_conn_set_stream_user_data`
|
||||
*
|
||||
* This function has been available since v1.17.0.
|
||||
*/
|
||||
NGTCP2_EXTERN void *ngtcp2_conn_get_stream_user_data(ngtcp2_conn *conn,
|
||||
int64_t stream_id);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
@ -5667,14 +5766,23 @@ typedef ngtcp2_ssize (*ngtcp2_write_pkt)(ngtcp2_conn *conn, ngtcp2_path *path,
|
||||
* first packet is `ngtcp2_conn_get_path_max_tx_udp_payload_size(conn)
|
||||
* <ngtcp2_conn_get_path_max_tx_udp_payload_size>` bytes long. The
|
||||
* application can adjust the length of the buffer to limit the number
|
||||
* of packets to aggregate. If this function returns positive
|
||||
* integer, all packets share the same :type:`ngtcp2_path` and
|
||||
* :type:`ngtcp2_pkt_info` values, and they are assigned to the
|
||||
* objects pointed by |path| and |pi| respectively. The length of all
|
||||
* packets other than the last packet is assigned to |*pgsolen|. The
|
||||
* length of last packet is equal to or less than |*pgsolen|.
|
||||
* |write_pkt| must write a single packet. After all packets are
|
||||
* written, this function calls `ngtcp2_conn_update_pkt_tx_time`.
|
||||
* of packets to aggregate (or use `ngtcp2_conn_write_aggregate_pkt2`
|
||||
* to control the number of packets to write directly). If this
|
||||
* function returns positive integer, all packets share the same
|
||||
* :type:`ngtcp2_path` and :type:`ngtcp2_pkt_info` values, and they
|
||||
* are assigned to the objects pointed by |path| and |pi|
|
||||
* respectively. The length of all packets other than the last packet
|
||||
* is assigned to |*pgsolen|. The length of last packet is equal to
|
||||
* or less than |*pgsolen|. |write_pkt| must write a single packet.
|
||||
* After all packets are written, this function calls
|
||||
* `ngtcp2_conn_update_pkt_tx_time`.
|
||||
*
|
||||
* This function is equivalent to call
|
||||
* `ngtcp2_conn_write_aggregate_pkt2` with |buflen| = min(|buflen|,
|
||||
* `ngtcp2_conn_get_send_quantum(conn)
|
||||
* <ngtcp2_conn_get_send_quantum>`) and |num_pkts| = 0 followed by
|
||||
* `ngtcp2_conn_update_pkt_tx_time(conn)
|
||||
* <ngtcp2_conn_update_pkt_tx_time>`.
|
||||
*
|
||||
* This function returns the number of bytes written to the buffer, or
|
||||
* a negative error code returned by |write_pkt|.
|
||||
@ -5686,6 +5794,39 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt_versioned(
|
||||
ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
|
||||
ngtcp2_write_pkt write_pkt, ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_conn_write_aggregate_pkt2` behaves like
|
||||
* `ngtcp2_conn_write_aggregate_pkt`, but it accepts |num_pkts| to
|
||||
* specify the maximum number of packets to write. If |num_pkts| is
|
||||
* 0, this function writes packets as much as possible. The actual
|
||||
* number of packets to write is determined by the connection state
|
||||
* (e.g., the congestion controller, data available to send) and the
|
||||
* length of packet produced. It also does not clamp |buflen|, and
|
||||
* does not call `ngtcp2_conn_update_pkt_tx_time`.
|
||||
*
|
||||
* This function offers more flexibility and optimization chances to
|
||||
* an application. It can experiment different GSO buffer size
|
||||
* strategy and number of GSO writes per event loop.
|
||||
*
|
||||
* This function has been available since v1.17.0.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_aggregate_pkt2_versioned(
|
||||
ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version,
|
||||
ngtcp2_pkt_info *pi, uint8_t *buf, size_t buflen, size_t *pgsolen,
|
||||
ngtcp2_write_pkt write_pkt, size_t num_pkts, ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_conn_get_timestamp` returns the latest timestamp that is
|
||||
* known to |conn|.
|
||||
*
|
||||
* This function has been available since v1.16.0.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_tstamp ngtcp2_conn_get_timestamp(const ngtcp2_conn *conn);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
@ -5778,9 +5919,9 @@ NGTCP2_EXTERN void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps);
|
||||
* * :member:`handshake_timeout <ngtcp2_settings.handshake_timeout>` =
|
||||
* ``UINT64_MAX``
|
||||
* * :member:`glitch_ratelim_burst
|
||||
* <ngtcp2_settings.glitch_ratelim_burst>` = 1000
|
||||
* <ngtcp2_settings.glitch_ratelim_burst>` = 4000
|
||||
* * :member:`glitch_ratelim_rate
|
||||
* <ngtcp2_settings.glitch_ratelim_rate>` = 33
|
||||
* <ngtcp2_settings.glitch_ratelim_rate>` = 132
|
||||
*/
|
||||
NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version,
|
||||
ngtcp2_settings *settings);
|
||||
@ -6083,6 +6224,17 @@ NGTCP2_EXTERN uint32_t ngtcp2_select_version(const uint32_t *preferred_versions,
|
||||
(CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (BUF), (BUFLEN), (PGSOLEN), \
|
||||
(WRITE_PKT), (TS))
|
||||
|
||||
/*
|
||||
* `ngtcp2_conn_write_aggregate_pkt2` is a wrapper around
|
||||
* `ngtcp2_conn_write_aggregate_pkt2_versioned` to set the correct
|
||||
* struct version.
|
||||
*/
|
||||
#define ngtcp2_conn_write_aggregate_pkt2(CONN, PATH, PI, BUF, BUFLEN, PGSOLEN, \
|
||||
WRITE_PKT, NUM_PKTS, TS) \
|
||||
ngtcp2_conn_write_aggregate_pkt2_versioned( \
|
||||
(CONN), (PATH), NGTCP2_PKT_INFO_VERSION, (PI), (BUF), (BUFLEN), (PGSOLEN), \
|
||||
(WRITE_PKT), (NUM_PKTS), (TS))
|
||||
|
||||
/*
|
||||
* `ngtcp2_settings_default` is a wrapper around
|
||||
* `ngtcp2_settings_default_versioned` to set the correct struct
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
*
|
||||
* Version number of the ngtcp2 library release.
|
||||
*/
|
||||
#define NGTCP2_VERSION "1.15.1"
|
||||
#define NGTCP2_VERSION "1.19.0"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
@ -46,6 +46,6 @@
|
||||
* number, 8 bits for minor and 8 bits for patch. Version 1.2.3
|
||||
* becomes 0x010203.
|
||||
*/
|
||||
#define NGTCP2_VERSION_NUM 0x010f01
|
||||
#define NGTCP2_VERSION_NUM 0x011300
|
||||
|
||||
#endif /* !defined(NGTCP2_VERSION_H) */
|
||||
|
||||
30
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c
vendored
30
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c
vendored
@ -34,9 +34,11 @@ ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent)
|
||||
|
||||
static void acktr_entry_init(ngtcp2_acktr_entry *ent, int64_t pkt_num,
|
||||
ngtcp2_tstamp tstamp) {
|
||||
ent->pkt_num = pkt_num;
|
||||
ent->len = 1;
|
||||
ent->tstamp = tstamp;
|
||||
*ent = (ngtcp2_acktr_entry){
|
||||
.pkt_num = pkt_num,
|
||||
.len = 1,
|
||||
.tstamp = tstamp,
|
||||
};
|
||||
}
|
||||
|
||||
int ngtcp2_acktr_entry_objalloc_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
|
||||
@ -219,8 +221,10 @@ ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr,
|
||||
int64_t largest_ack) {
|
||||
ngtcp2_acktr_ack_entry *ent = ngtcp2_ringbuf_push_front(&acktr->acks.rb);
|
||||
|
||||
ent->largest_ack = largest_ack;
|
||||
ent->pkt_num = pkt_num;
|
||||
*ent = (ngtcp2_acktr_ack_entry){
|
||||
.largest_ack = largest_ack,
|
||||
.pkt_num = pkt_num,
|
||||
};
|
||||
|
||||
return ent;
|
||||
}
|
||||
@ -333,16 +337,14 @@ void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) {
|
||||
acktr->flags |= NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK;
|
||||
}
|
||||
|
||||
ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
||||
ngtcp2_frame *fr, uint8_t type,
|
||||
ngtcp2_tstamp ts,
|
||||
ngtcp2_duration ack_delay,
|
||||
uint64_t ack_delay_exponent) {
|
||||
int ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr, ngtcp2_ack *ack,
|
||||
uint8_t type, ngtcp2_tstamp ts,
|
||||
ngtcp2_duration ack_delay,
|
||||
uint64_t ack_delay_exponent) {
|
||||
int64_t last_pkt_num;
|
||||
ngtcp2_ack_range *range;
|
||||
ngtcp2_ksl_it it;
|
||||
ngtcp2_acktr_entry *rpkt;
|
||||
ngtcp2_ack *ack = &fr->ack;
|
||||
ngtcp2_tstamp largest_ack_ts;
|
||||
size_t num_acks;
|
||||
|
||||
@ -351,13 +353,13 @@ ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
||||
}
|
||||
|
||||
if (!ngtcp2_acktr_require_active_ack(acktr, ack_delay, ts)) {
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
it = ngtcp2_acktr_get(acktr);
|
||||
if (ngtcp2_ksl_it_end(&it)) {
|
||||
ngtcp2_acktr_commit_ack(acktr);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_acks = ngtcp2_ksl_len(&acktr->ents);
|
||||
@ -420,7 +422,7 @@ ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
||||
last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
|
||||
}
|
||||
|
||||
return fr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_acktr_increase_ecn_counts(ngtcp2_acktr *acktr,
|
||||
|
||||
15
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h
vendored
15
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h
vendored
@ -235,19 +235,18 @@ void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr);
|
||||
|
||||
/*
|
||||
* ngtcp2_acktr_create_ack_frame creates ACK frame in the object
|
||||
* pointed by |fr|, and returns |fr| if there are any received packets
|
||||
* to acknowledge. If there are no packets to acknowledge, this
|
||||
* function returns NULL. fr->ack.ranges must be able to contain at
|
||||
* pointed by |ack|, and returns 0 if it successfully creates ACK
|
||||
* frame in |ack|. If there are no packets to acknowledge, this
|
||||
* function returns -1. |ack|->ranges must be able to contain at
|
||||
* least NGTCP2_MAX_ACK_RANGES elements.
|
||||
*
|
||||
* Call ngtcp2_acktr_commit_ack after a created ACK frame is
|
||||
* successfully serialized into a packet.
|
||||
*/
|
||||
ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
|
||||
ngtcp2_frame *fr, uint8_t type,
|
||||
ngtcp2_tstamp ts,
|
||||
ngtcp2_duration ack_delay,
|
||||
uint64_t ack_delay_exponent);
|
||||
int ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr, ngtcp2_ack *ack,
|
||||
uint8_t type, ngtcp2_tstamp ts,
|
||||
ngtcp2_duration ack_delay,
|
||||
uint64_t ack_delay_exponent);
|
||||
|
||||
/*
|
||||
* ngtcp2_acktr_increase_ecn_counts increases ECN counts from |pi|.
|
||||
|
||||
19
deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c
vendored
19
deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c
vendored
@ -31,8 +31,11 @@
|
||||
|
||||
ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr,
|
||||
ngtcp2_socklen addrlen) {
|
||||
dest->addrlen = addrlen;
|
||||
dest->addr = (ngtcp2_sockaddr *)addr;
|
||||
*dest = (ngtcp2_addr){
|
||||
.addr = (ngtcp2_sockaddr *)addr,
|
||||
.addrlen = addrlen,
|
||||
};
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
@ -58,14 +61,12 @@ int ngtcp2_sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) {
|
||||
|
||||
switch (a->sa_family) {
|
||||
case NGTCP2_AF_INET: {
|
||||
const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
|
||||
*bi = (const ngtcp2_sockaddr_in *)(void *)b;
|
||||
const ngtcp2_sockaddr_in *ai = (void *)a, *bi = (void *)b;
|
||||
return ai->sin_port == bi->sin_port &&
|
||||
memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr)) == 0;
|
||||
}
|
||||
case NGTCP2_AF_INET6: {
|
||||
const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
|
||||
*bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
|
||||
const ngtcp2_sockaddr_in6 *ai = (void *)a, *bi = (void *)b;
|
||||
return ai->sin6_port == bi->sin6_port &&
|
||||
memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0;
|
||||
}
|
||||
@ -89,8 +90,7 @@ uint32_t ngtcp2_addr_cmp(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
|
||||
|
||||
switch (a->sa_family) {
|
||||
case NGTCP2_AF_INET: {
|
||||
const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
|
||||
*bi = (const ngtcp2_sockaddr_in *)(void *)b;
|
||||
const ngtcp2_sockaddr_in *ai = (void *)a, *bi = (void *)b;
|
||||
if (memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr))) {
|
||||
flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
|
||||
}
|
||||
@ -100,8 +100,7 @@ uint32_t ngtcp2_addr_cmp(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
|
||||
return flags;
|
||||
}
|
||||
case NGTCP2_AF_INET6: {
|
||||
const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
|
||||
*bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
|
||||
const ngtcp2_sockaddr_in6 *ai = (void *)a, *bi = (void *)b;
|
||||
if (memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr))) {
|
||||
flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
|
||||
}
|
||||
|
||||
2
deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c
vendored
2
deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c
vendored
@ -71,7 +71,7 @@ int ngtcp2_balloc_get(ngtcp2_balloc *balloc, void **pbuf, size_t n) {
|
||||
return NGTCP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
hd = (ngtcp2_memblock_hd *)(void *)p;
|
||||
hd = (void *)p;
|
||||
hd->next = balloc->head;
|
||||
balloc->head = hd;
|
||||
ngtcp2_buf_init(
|
||||
|
||||
141
deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c
vendored
141
deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.c
vendored
@ -190,20 +190,20 @@ static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr,
|
||||
static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
|
||||
ngtcp2_conn_stat *cstat);
|
||||
|
||||
static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr);
|
||||
static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr, const ngtcp2_rs *rs);
|
||||
|
||||
static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
|
||||
ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp ts);
|
||||
const ngtcp2_rs *rs, ngtcp2_tstamp ts);
|
||||
|
||||
static void bbr_note_loss(ngtcp2_cc_bbr *bbr);
|
||||
|
||||
static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
|
||||
|
||||
static uint64_t
|
||||
bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
|
||||
const ngtcp2_cc_pkt *pkt);
|
||||
static uint64_t bbr_inflight_at_loss(ngtcp2_cc_bbr *bbr,
|
||||
const ngtcp2_cc_pkt *pkt,
|
||||
const ngtcp2_rs *rs);
|
||||
|
||||
static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack,
|
||||
ngtcp2_tstamp ts);
|
||||
@ -334,9 +334,11 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
||||
|
||||
bbr->max_inflight = 0;
|
||||
|
||||
bbr->congestion_recovery_start_ts = UINT64_MAX;
|
||||
|
||||
bbr->bdp = 0;
|
||||
|
||||
bbr->undo_bw_shortterm = 0;
|
||||
bbr->undo_inflight_shortterm = 0;
|
||||
bbr->undo_inflight_longterm = 0;
|
||||
}
|
||||
|
||||
static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) {
|
||||
@ -384,15 +386,16 @@ static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr,
|
||||
|
||||
bbr->full_bw_reached = 1;
|
||||
|
||||
ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"bbr reached full bandwidth, full_bw=%" PRIu64, bbr->full_bw);
|
||||
ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"bbr reached full bandwidth, full_bw=%" PRIu64,
|
||||
bbr->full_bw);
|
||||
}
|
||||
|
||||
static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) {
|
||||
if (bbr->full_bw_reached || bbr->loss_events_in_round <= 6 ||
|
||||
(bbr->in_loss_recovery &&
|
||||
bbr->round_count <= bbr->round_count_at_recovery) ||
|
||||
!bbr_is_inflight_too_high(bbr)) {
|
||||
!bbr_is_inflight_too_high(bbr, &bbr->rst->rs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -402,11 +405,12 @@ static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) {
|
||||
}
|
||||
|
||||
static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
|
||||
cstat->pacing_interval_m =
|
||||
cstat->pacing_interval_m = ngtcp2_max_uint64(
|
||||
((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
|
||||
: cstat->smoothed_rtt)
|
||||
<< 10) *
|
||||
100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd;
|
||||
100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd,
|
||||
1);
|
||||
}
|
||||
|
||||
static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
|
||||
@ -567,7 +571,8 @@ static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_cc_ack *ack) {
|
||||
bbr_update_round(bbr, ack);
|
||||
|
||||
if (cstat->delivery_rate_sec >= bbr->max_bw || !bbr->rst->rs.is_app_limited) {
|
||||
if (cstat->delivery_rate_sec && (cstat->delivery_rate_sec >= bbr->max_bw ||
|
||||
!bbr->rst->rs.is_app_limited)) {
|
||||
ngtcp2_window_filter_update(&bbr->max_bw_filter, cstat->delivery_rate_sec,
|
||||
bbr->cycle_count);
|
||||
|
||||
@ -879,7 +884,7 @@ static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
|
||||
}
|
||||
}
|
||||
|
||||
if (!bbr_is_inflight_too_high(bbr)) {
|
||||
if (!bbr_is_inflight_too_high(bbr, &bbr->rst->rs)) {
|
||||
if (bbr->inflight_longterm == UINT64_MAX) {
|
||||
return;
|
||||
}
|
||||
@ -925,17 +930,16 @@ static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
|
||||
return ngtcp2_min_uint64(bbr->bdp, cstat->cwnd);
|
||||
}
|
||||
|
||||
static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr) {
|
||||
const ngtcp2_rs *rs = &bbr->rst->rs;
|
||||
static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr, const ngtcp2_rs *rs) {
|
||||
(void)bbr;
|
||||
return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM >
|
||||
rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER;
|
||||
}
|
||||
|
||||
static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
|
||||
ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_rs *rs,
|
||||
ngtcp2_tstamp ts) {
|
||||
const ngtcp2_rs *rs = &bbr->rst->rs;
|
||||
|
||||
bbr->bw_probe_samples = 0;
|
||||
|
||||
if (!rs->is_app_limited) {
|
||||
@ -959,7 +963,7 @@ static void bbr_note_loss(ngtcp2_cc_bbr *bbr) {
|
||||
|
||||
static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
|
||||
ngtcp2_rs *rs = &bbr->rst->rs;
|
||||
ngtcp2_rs rs = {0};
|
||||
|
||||
bbr_note_loss(bbr);
|
||||
|
||||
@ -967,22 +971,21 @@ static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
||||
return;
|
||||
}
|
||||
|
||||
rs->tx_in_flight = pkt->tx_in_flight;
|
||||
rs.tx_in_flight = pkt->tx_in_flight;
|
||||
assert(bbr->rst->lost >= pkt->lost);
|
||||
rs->lost = bbr->rst->lost - pkt->lost;
|
||||
rs->is_app_limited = pkt->is_app_limited;
|
||||
rs.lost = bbr->rst->lost - pkt->lost;
|
||||
rs.is_app_limited = pkt->is_app_limited;
|
||||
|
||||
if (bbr_is_inflight_too_high(bbr)) {
|
||||
rs->tx_in_flight = bbr_inflight_longterm_from_lost_packet(bbr, pkt);
|
||||
if (bbr_is_inflight_too_high(bbr, &rs)) {
|
||||
rs.tx_in_flight = bbr_inflight_at_loss(bbr, pkt, &rs);
|
||||
|
||||
bbr_handle_inflight_too_high(bbr, cstat, ts);
|
||||
bbr_handle_inflight_too_high(bbr, cstat, &rs, ts);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
|
||||
const ngtcp2_cc_pkt *pkt) {
|
||||
ngtcp2_rs *rs = &bbr->rst->rs;
|
||||
static uint64_t bbr_inflight_at_loss(ngtcp2_cc_bbr *bbr,
|
||||
const ngtcp2_cc_pkt *pkt,
|
||||
const ngtcp2_rs *rs) {
|
||||
uint64_t inflight_prev, lost_prev, lost_prefix;
|
||||
(void)bbr;
|
||||
|
||||
@ -1025,8 +1028,8 @@ static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack,
|
||||
bbr->min_rtt = bbr->probe_rtt_min_delay;
|
||||
bbr->min_rtt_stamp = bbr->probe_rtt_min_stamp;
|
||||
|
||||
ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"bbr update min_rtt=%" PRIu64, bbr->min_rtt);
|
||||
ngtcp2_log_infof(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"bbr update min_rtt=%" PRIu64, bbr->min_rtt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1098,13 +1101,8 @@ static void bbr_check_probe_rtt_done(ngtcp2_cc_bbr *bbr,
|
||||
|
||||
static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
|
||||
ngtcp2_conn_stat *cstat) {
|
||||
uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight;
|
||||
|
||||
if (app_limited) {
|
||||
bbr->rst->app_limited = app_limited;
|
||||
} else {
|
||||
bbr->rst->app_limited = cstat->max_tx_udp_payload_size;
|
||||
}
|
||||
bbr->rst->app_limited =
|
||||
ngtcp2_max_uint64(bbr->rst->delivered + cstat->bytes_in_flight, 1);
|
||||
}
|
||||
|
||||
static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) {
|
||||
@ -1279,28 +1277,15 @@ static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
|
||||
|
||||
static void bbr_handle_recovery(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_cc_ack *ack) {
|
||||
if (bbr->in_loss_recovery) {
|
||||
if (ack->largest_pkt_sent_ts != UINT64_MAX &&
|
||||
!in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
||||
bbr->in_loss_recovery = 0;
|
||||
bbr->round_count_at_recovery = UINT64_MAX;
|
||||
bbr_restore_cwnd(bbr, cstat);
|
||||
}
|
||||
|
||||
if (!bbr->in_loss_recovery) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bbr->congestion_recovery_start_ts != UINT64_MAX) {
|
||||
bbr->in_loss_recovery = 1;
|
||||
bbr->round_count_at_recovery =
|
||||
bbr->round_start ? bbr->round_count : bbr->round_count + 1;
|
||||
bbr_save_cwnd(bbr, cstat);
|
||||
cstat->cwnd =
|
||||
cstat->bytes_in_flight +
|
||||
ngtcp2_max_uint64(ack->bytes_delivered, cstat->max_tx_udp_payload_size);
|
||||
|
||||
cstat->congestion_recovery_start_ts = bbr->congestion_recovery_start_ts;
|
||||
bbr->congestion_recovery_start_ts = UINT64_MAX;
|
||||
if (ack->largest_pkt_sent_ts != UINT64_MAX &&
|
||||
!in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
||||
bbr->in_loss_recovery = 0;
|
||||
bbr->round_count_at_recovery = UINT64_MAX;
|
||||
bbr_restore_cwnd(bbr, cstat);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1312,18 +1297,25 @@ static void bbr_cc_on_pkt_lost(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
}
|
||||
|
||||
static void bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp sent_ts, uint64_t bytes_lost,
|
||||
ngtcp2_tstamp sent_ts,
|
||||
const ngtcp2_cc_ack *ack,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
|
||||
(void)bytes_lost;
|
||||
(void)ack;
|
||||
|
||||
if (bbr->in_loss_recovery ||
|
||||
bbr->congestion_recovery_start_ts != UINT64_MAX ||
|
||||
in_congestion_recovery(cstat, sent_ts)) {
|
||||
if (bbr->in_loss_recovery || in_congestion_recovery(cstat, sent_ts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bbr->congestion_recovery_start_ts = ts;
|
||||
bbr->in_loss_recovery = 1;
|
||||
bbr->round_count_at_recovery =
|
||||
bbr->round_start ? bbr->round_count : bbr->round_count + 1;
|
||||
bbr_save_cwnd(bbr, cstat);
|
||||
bbr->undo_bw_shortterm = bbr->bw_shortterm;
|
||||
bbr->undo_inflight_shortterm = bbr->inflight_shortterm;
|
||||
bbr->undo_inflight_longterm = bbr->inflight_longterm;
|
||||
|
||||
cstat->congestion_recovery_start_ts = ts;
|
||||
}
|
||||
|
||||
static void bbr_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
||||
@ -1332,14 +1324,19 @@ static void bbr_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
||||
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
|
||||
(void)ts;
|
||||
|
||||
bbr->congestion_recovery_start_ts = UINT64_MAX;
|
||||
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
||||
|
||||
if (bbr->in_loss_recovery) {
|
||||
bbr->in_loss_recovery = 0;
|
||||
bbr->round_count_at_recovery = UINT64_MAX;
|
||||
bbr_restore_cwnd(bbr, cstat);
|
||||
}
|
||||
bbr->in_loss_recovery = 0;
|
||||
bbr->round_count_at_recovery = UINT64_MAX;
|
||||
bbr_reset_full_bw(bbr);
|
||||
bbr->loss_in_round = 0;
|
||||
bbr_restore_cwnd(bbr, cstat);
|
||||
bbr->bw_shortterm =
|
||||
ngtcp2_max_uint64(bbr->bw_shortterm, bbr->undo_bw_shortterm);
|
||||
bbr->inflight_shortterm =
|
||||
ngtcp2_max_uint64(bbr->inflight_shortterm, bbr->undo_inflight_shortterm);
|
||||
bbr->inflight_longterm =
|
||||
ngtcp2_max_uint64(bbr->inflight_longterm, bbr->undo_inflight_longterm);
|
||||
}
|
||||
|
||||
static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
||||
@ -1349,7 +1346,6 @@ static void bbr_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
||||
(void)ts;
|
||||
|
||||
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
||||
bbr->congestion_recovery_start_ts = UINT64_MAX;
|
||||
bbr->in_loss_recovery = 0;
|
||||
bbr->round_count_at_recovery = UINT64_MAX;
|
||||
|
||||
@ -1364,6 +1360,11 @@ static void bbr_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
|
||||
|
||||
bbr_handle_recovery(bbr, cstat, ack);
|
||||
|
||||
if (ack->bytes_delivered == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bbr_update_on_ack(bbr, cstat, ack, ts);
|
||||
}
|
||||
|
||||
|
||||
6
deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h
vendored
6
deps/ngtcp2/ngtcp2/lib/ngtcp2_bbr.h
vendored
@ -106,6 +106,11 @@ typedef struct ngtcp2_cc_bbr {
|
||||
ngtcp2_bbr_state state;
|
||||
uint64_t cwnd_gain_h;
|
||||
|
||||
/* Backup for spurious losses */
|
||||
uint64_t undo_bw_shortterm;
|
||||
uint64_t undo_inflight_shortterm;
|
||||
uint64_t undo_inflight_longterm;
|
||||
|
||||
int loss_round_start;
|
||||
uint64_t loss_round_delivered;
|
||||
uint64_t rounds_since_bw_probe;
|
||||
@ -130,7 +135,6 @@ typedef struct ngtcp2_cc_bbr {
|
||||
int in_loss_recovery;
|
||||
uint64_t round_count_at_recovery;
|
||||
uint64_t max_inflight;
|
||||
ngtcp2_tstamp congestion_recovery_start_ts;
|
||||
uint64_t bdp;
|
||||
} ngtcp2_cc_bbr;
|
||||
|
||||
|
||||
8
deps/ngtcp2/ngtcp2/lib/ngtcp2_buf.c
vendored
8
deps/ngtcp2/ngtcp2/lib/ngtcp2_buf.c
vendored
@ -26,8 +26,12 @@
|
||||
#include "ngtcp2_mem.h"
|
||||
|
||||
void ngtcp2_buf_init(ngtcp2_buf *buf, uint8_t *begin, size_t len) {
|
||||
buf->begin = buf->pos = buf->last = begin;
|
||||
buf->end = begin + len;
|
||||
*buf = (ngtcp2_buf){
|
||||
.begin = begin,
|
||||
.end = begin + len,
|
||||
.pos = begin,
|
||||
.last = begin,
|
||||
};
|
||||
}
|
||||
|
||||
void ngtcp2_buf_reset(ngtcp2_buf *buf) { buf->pos = buf->last = buf->begin; }
|
||||
|
||||
171
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c
vendored
171
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c
vendored
@ -41,6 +41,40 @@ uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) {
|
||||
return ngtcp2_min_uint64(10 * max_udp_payload_size, n);
|
||||
}
|
||||
|
||||
/* 1.25 is the under-utilization avoidance factor described in
|
||||
https://datatracker.ietf.org/doc/html/rfc9002#section-7.7 */
|
||||
#define NGTCP2_CC_PACING_GAIN_H 125
|
||||
|
||||
static void init_pacing_rate(ngtcp2_conn_stat *cstat) {
|
||||
assert(cstat->cwnd);
|
||||
|
||||
cstat->pacing_interval_m = ngtcp2_max_uint64(
|
||||
(NGTCP2_MILLISECONDS << 10) * 100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd,
|
||||
1);
|
||||
cstat->send_quantum = 10 * cstat->max_tx_udp_payload_size;
|
||||
}
|
||||
|
||||
static void set_pacing_rate(ngtcp2_conn_stat *cstat) {
|
||||
size_t send_quantum = 64 * 1024;
|
||||
|
||||
assert(cstat->cwnd);
|
||||
|
||||
cstat->pacing_interval_m =
|
||||
((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
|
||||
: cstat->smoothed_rtt)
|
||||
<< 10) *
|
||||
100 / NGTCP2_CC_PACING_GAIN_H / cstat->cwnd;
|
||||
|
||||
cstat->pacing_interval_m = ngtcp2_max_uint64(cstat->pacing_interval_m, 1);
|
||||
|
||||
send_quantum =
|
||||
ngtcp2_min_size(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) /
|
||||
cstat->pacing_interval_m));
|
||||
|
||||
cstat->send_quantum =
|
||||
ngtcp2_max_size(send_quantum, 10 * cstat->max_tx_udp_payload_size);
|
||||
}
|
||||
|
||||
ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
|
||||
size_t pktlen, ngtcp2_pktns_id pktns_id,
|
||||
ngtcp2_tstamp sent_ts, uint64_t lost,
|
||||
@ -56,9 +90,14 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void reno_cc_reset(ngtcp2_cc_reno *reno) { reno->pending_add = 0; }
|
||||
static void reno_cc_reset(ngtcp2_cc_reno *reno, ngtcp2_conn_stat *cstat) {
|
||||
reno->pending_add = 0;
|
||||
|
||||
void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) {
|
||||
init_pacing_rate(cstat);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log,
|
||||
ngtcp2_conn_stat *cstat) {
|
||||
*reno = (ngtcp2_cc_reno){
|
||||
.cc =
|
||||
{
|
||||
@ -70,7 +109,7 @@ void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) {
|
||||
},
|
||||
};
|
||||
|
||||
reno_cc_reset(reno);
|
||||
reno_cc_reset(reno, cstat);
|
||||
}
|
||||
|
||||
static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
|
||||
@ -92,9 +131,12 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
|
||||
if (cstat->cwnd < cstat->ssthresh) {
|
||||
cstat->cwnd += pkt->pktlen;
|
||||
ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
|
||||
pkt->pkt_num, cstat->cwnd);
|
||||
|
||||
set_pacing_rate(cstat);
|
||||
|
||||
ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
|
||||
pkt->pkt_num, cstat->cwnd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -102,14 +144,17 @@ void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
reno->pending_add = m % cstat->cwnd;
|
||||
|
||||
cstat->cwnd += m / cstat->cwnd;
|
||||
|
||||
set_pacing_rate(cstat);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp sent_ts,
|
||||
uint64_t bytes_lost, ngtcp2_tstamp ts) {
|
||||
const ngtcp2_cc_ack *ack,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc);
|
||||
uint64_t min_cwnd;
|
||||
(void)bytes_lost;
|
||||
(void)ack;
|
||||
|
||||
if (in_congestion_recovery(cstat, sent_ts)) {
|
||||
return;
|
||||
@ -123,9 +168,11 @@ void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
|
||||
reno->pending_add = 0;
|
||||
|
||||
ngtcp2_log_info(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"reduce cwnd because of packet loss cwnd=%" PRIu64,
|
||||
cstat->cwnd);
|
||||
set_pacing_rate(cstat);
|
||||
|
||||
ngtcp2_log_infof(reno->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"reduce cwnd because of packet loss cwnd=%" PRIu64,
|
||||
cstat->cwnd);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
||||
@ -136,15 +183,16 @@ void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
||||
|
||||
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
|
||||
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
||||
|
||||
set_pacing_rate(cstat);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_cc_reno *reno = ngtcp2_struct_of(cc, ngtcp2_cc_reno, cc);
|
||||
(void)cstat;
|
||||
(void)ts;
|
||||
|
||||
reno_cc_reset(reno);
|
||||
reno_cc_reset(reno, cstat);
|
||||
}
|
||||
|
||||
static void cubic_vars_reset(ngtcp2_cubic_vars *v) {
|
||||
@ -156,11 +204,11 @@ static void cubic_vars_reset(ngtcp2_cubic_vars *v) {
|
||||
|
||||
v->app_limited_start_ts = UINT64_MAX;
|
||||
v->app_limited_duration = 0;
|
||||
v->pending_bytes_delivered = 0;
|
||||
v->pending_est_bytes_delivered = 0;
|
||||
v->pending_bytes_acked = 0;
|
||||
v->pending_est_bytes_acked = 0;
|
||||
}
|
||||
|
||||
static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) {
|
||||
static void cubic_cc_reset(ngtcp2_cc_cubic *cubic, ngtcp2_conn_stat *cstat) {
|
||||
cubic_vars_reset(&cubic->current);
|
||||
cubic_vars_reset(&cubic->undo.v);
|
||||
cubic->undo.cwnd = 0;
|
||||
@ -174,10 +222,12 @@ static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) {
|
||||
cubic->hs.css_round = 0;
|
||||
|
||||
cubic->next_round_delivered = 0;
|
||||
|
||||
init_pacing_rate(cstat);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log,
|
||||
ngtcp2_rst *rst) {
|
||||
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst) {
|
||||
*cubic = (ngtcp2_cc_cubic){
|
||||
.cc =
|
||||
{
|
||||
@ -191,7 +241,7 @@ void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log,
|
||||
.rst = rst,
|
||||
};
|
||||
|
||||
cubic_cc_reset(cubic);
|
||||
cubic_cc_reset(cubic, cstat);
|
||||
}
|
||||
|
||||
uint64_t ngtcp2_cbrt(uint64_t n) {
|
||||
@ -211,7 +261,6 @@ uint64_t ngtcp2_cbrt(uint64_t n) {
|
||||
y <<= 1;
|
||||
b = 3 * y * (y + 1) + 1;
|
||||
if (n >= b) {
|
||||
n -= b;
|
||||
y++;
|
||||
}
|
||||
|
||||
@ -266,12 +315,14 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
||||
uint64_t w_cubic, w_cubic_next;
|
||||
uint64_t target, m;
|
||||
uint64_t bytes_acked;
|
||||
ngtcp2_duration rtt_thresh;
|
||||
int round_start;
|
||||
int is_app_limited =
|
||||
cubic->rst->rs.is_app_limited && !cubic->rst->is_cwnd_limited;
|
||||
|
||||
if (in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
||||
if (ack->bytes_delivered == 0 ||
|
||||
in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -291,9 +342,11 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
cstat->cwnd += ack->bytes_delivered;
|
||||
}
|
||||
|
||||
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64,
|
||||
ack->bytes_delivered, cstat->cwnd);
|
||||
set_pacing_rate(cstat);
|
||||
|
||||
ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64,
|
||||
ack->bytes_delivered, cstat->cwnd);
|
||||
}
|
||||
|
||||
if (round_start) {
|
||||
@ -379,35 +432,46 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
target = w_cubic_next;
|
||||
}
|
||||
|
||||
m = ack->bytes_delivered * cstat->max_tx_udp_payload_size +
|
||||
cubic->current.pending_est_bytes_delivered;
|
||||
cubic->current.pending_est_bytes_delivered = m % cstat->cwnd;
|
||||
bytes_acked = ack->bytes_delivered * cstat->max_tx_udp_payload_size;
|
||||
m = (bytes_acked + cubic->current.pending_est_bytes_acked) / cstat->cwnd;
|
||||
|
||||
cubic->current.pending_est_bytes_acked += bytes_acked;
|
||||
cubic->current.pending_est_bytes_acked -= m * cstat->cwnd;
|
||||
|
||||
assert(cubic->current.pending_est_bytes_acked < cstat->cwnd);
|
||||
|
||||
if (cubic->current.w_est < cubic->current.cwnd_prior) {
|
||||
cubic->current.w_est += m * 9 / 17 / cstat->cwnd;
|
||||
cubic->current.w_est += m * 9 / 17;
|
||||
} else {
|
||||
cubic->current.w_est += m / cstat->cwnd;
|
||||
cubic->current.w_est += m;
|
||||
}
|
||||
|
||||
if (cubic->current.w_est > w_cubic) {
|
||||
cstat->cwnd = cubic->current.w_est;
|
||||
} else {
|
||||
m = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size +
|
||||
cubic->current.pending_bytes_delivered;
|
||||
cubic->current.pending_bytes_delivered = m % cstat->cwnd;
|
||||
cstat->cwnd += m / cstat->cwnd;
|
||||
bytes_acked = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size;
|
||||
m = (bytes_acked + cubic->current.pending_bytes_acked) / cstat->cwnd;
|
||||
|
||||
cubic->current.pending_bytes_acked += bytes_acked;
|
||||
cubic->current.pending_bytes_acked -= m * cstat->cwnd;
|
||||
|
||||
assert(cubic->current.pending_bytes_acked < cstat->cwnd);
|
||||
|
||||
cstat->cwnd += m;
|
||||
}
|
||||
|
||||
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
|
||||
" k_m=%" PRIu64 " target=%" PRIu64 " w_est=%" PRIu64,
|
||||
ack->bytes_delivered, cstat->cwnd, cubic->current.k_m, target,
|
||||
cubic->current.w_est);
|
||||
set_pacing_rate(cstat);
|
||||
|
||||
ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
|
||||
" k_m=%" PRIu64 " target=%" PRIu64 " w_est=%" PRIu64,
|
||||
ack->bytes_delivered, cstat->cwnd, cubic->current.k_m,
|
||||
target, cubic->current.w_est);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp sent_ts,
|
||||
uint64_t bytes_lost,
|
||||
const ngtcp2_cc_ack *ack,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
||||
uint64_t flight_size;
|
||||
@ -428,8 +492,8 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
cubic->current.epoch_start = ts;
|
||||
cubic->current.app_limited_start_ts = UINT64_MAX;
|
||||
cubic->current.app_limited_duration = 0;
|
||||
cubic->current.pending_bytes_delivered = 0;
|
||||
cubic->current.pending_est_bytes_delivered = 0;
|
||||
cubic->current.pending_bytes_acked = 0;
|
||||
cubic->current.pending_est_bytes_acked = 0;
|
||||
|
||||
if (cstat->cwnd < cubic->current.w_max) {
|
||||
cubic->current.w_max = cstat->cwnd * 17 / 20;
|
||||
@ -443,7 +507,7 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
cstat->ssthresh = cstat->cwnd * 7 / 10;
|
||||
|
||||
if (cubic->rst->rs.delivered * 2 < cstat->cwnd) {
|
||||
flight_size = cstat->bytes_in_flight + bytes_lost;
|
||||
flight_size = cstat->bytes_in_flight + ack->bytes_lost;
|
||||
cstat->ssthresh = ngtcp2_min_uint64(
|
||||
cstat->ssthresh,
|
||||
ngtcp2_max_uint64(cubic->rst->rs.delivered, flight_size));
|
||||
@ -464,9 +528,11 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
cubic->current.k_m =
|
||||
ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 / cstat->max_tx_udp_payload_size);
|
||||
|
||||
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"reduce cwnd because of packet loss cwnd=%" PRIu64,
|
||||
cstat->cwnd);
|
||||
set_pacing_rate(cstat);
|
||||
|
||||
ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"reduce cwnd because of packet loss cwnd=%" PRIu64,
|
||||
cstat->cwnd);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
||||
@ -482,10 +548,12 @@ void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *cc,
|
||||
cstat->cwnd = cubic->undo.cwnd;
|
||||
cstat->ssthresh = cubic->undo.ssthresh;
|
||||
|
||||
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"spurious congestion is detected and congestion state is "
|
||||
"restored cwnd=%" PRIu64,
|
||||
cstat->cwnd);
|
||||
set_pacing_rate(cstat);
|
||||
|
||||
ngtcp2_log_infof(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
|
||||
"spurious congestion is detected and congestion state is "
|
||||
"restored cwnd=%" PRIu64,
|
||||
cstat->cwnd);
|
||||
}
|
||||
|
||||
cubic_vars_reset(&cubic->undo.v);
|
||||
@ -499,17 +567,18 @@ void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
||||
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
||||
(void)ts;
|
||||
|
||||
cubic_cc_reset(cubic);
|
||||
cubic_cc_reset(cubic, cstat);
|
||||
|
||||
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
|
||||
cstat->congestion_recovery_start_ts = UINT64_MAX;
|
||||
|
||||
set_pacing_rate(cstat);
|
||||
}
|
||||
|
||||
void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
|
||||
(void)cstat;
|
||||
(void)ts;
|
||||
|
||||
cubic_cc_reset(cubic);
|
||||
cubic_cc_reset(cubic, cstat);
|
||||
}
|
||||
|
||||
75
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h
vendored
75
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h
vendored
@ -88,11 +88,6 @@ typedef struct ngtcp2_cc_pkt {
|
||||
* acknowledged and lost bytes.
|
||||
*/
|
||||
typedef struct ngtcp2_cc_ack {
|
||||
/**
|
||||
* :member:`prior_bytes_in_flight` is the in-flight bytes before
|
||||
* processing this ACK.
|
||||
*/
|
||||
uint64_t prior_bytes_in_flight;
|
||||
/**
|
||||
* :member:`bytes_delivered` is the number of bytes acknowledged.
|
||||
*/
|
||||
@ -143,13 +138,16 @@ typedef void (*ngtcp2_cc_on_pkt_lost)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
* @functypedef
|
||||
*
|
||||
* :type:`ngtcp2_cc_congestion_event` is a callback function which is
|
||||
* called when congestion event happens (e.g., when packet is lost).
|
||||
* |bytes_lost| is the number of bytes lost in this congestion event.
|
||||
* called when congestion event happens (e.g., when packet is lost or
|
||||
* due to ECN). |ack| contains information after ACK processing.
|
||||
* This callback may be called from non-ACK processing context. In
|
||||
* that case, the information only taken from |ack| processing has
|
||||
* default values, like 0 or UINT64_MAX;
|
||||
*/
|
||||
typedef void (*ngtcp2_cc_congestion_event)(ngtcp2_cc *cc,
|
||||
ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp sent_ts,
|
||||
uint64_t bytes_lost,
|
||||
const ngtcp2_cc_ack *ack,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
@ -186,20 +184,12 @@ typedef void (*ngtcp2_cc_on_ack_recv)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
* @functypedef
|
||||
*
|
||||
* :type:`ngtcp2_cc_on_pkt_sent` is a callback function which is
|
||||
* called when an ack-eliciting packet is sent.
|
||||
* called when an ack-eliciting packet is sent. The lost,
|
||||
* tx_in_flight, and is_app_limited fields in |pkt| are set to 0.
|
||||
*/
|
||||
typedef void (*ngtcp2_cc_on_pkt_sent)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_cc_pkt *pkt);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
* :type:`ngtcp2_cc_new_rtt_sample` is a callback function which is
|
||||
* called when new RTT sample is obtained.
|
||||
*/
|
||||
typedef void (*ngtcp2_cc_new_rtt_sample)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
@ -209,28 +199,6 @@ typedef void (*ngtcp2_cc_new_rtt_sample)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
typedef void (*ngtcp2_cc_reset)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @enum
|
||||
*
|
||||
* :type:`ngtcp2_cc_event_type` defines congestion control events.
|
||||
*/
|
||||
typedef enum ngtcp2_cc_event_type {
|
||||
/**
|
||||
* :enum:`NGTCP2_CC_EVENT_TX_START` occurs when ack-eliciting packet
|
||||
* is sent and no other ack-eliciting packet is present.
|
||||
*/
|
||||
NGTCP2_CC_EVENT_TYPE_TX_START
|
||||
} ngtcp2_cc_event_type;
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
* :type:`ngtcp2_cc_event` is a callback function which is called when
|
||||
* a specific event happens.
|
||||
*/
|
||||
typedef void (*ngtcp2_cc_event)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_cc_event_type event, ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @struct
|
||||
*
|
||||
@ -254,7 +222,7 @@ typedef struct ngtcp2_cc {
|
||||
ngtcp2_cc_on_pkt_lost on_pkt_lost;
|
||||
/**
|
||||
* :member:`congestion_event` is a callback function which is called
|
||||
* when congestion event happens (.e.g, packet is lost).
|
||||
* when congestion event happens (e.g., packet is lost).
|
||||
*/
|
||||
ngtcp2_cc_congestion_event congestion_event;
|
||||
/**
|
||||
@ -277,21 +245,11 @@ typedef struct ngtcp2_cc {
|
||||
* ack-eliciting packet is sent.
|
||||
*/
|
||||
ngtcp2_cc_on_pkt_sent on_pkt_sent;
|
||||
/**
|
||||
* :member:`new_rtt_sample` is a callback function which is called
|
||||
* when new RTT sample is obtained.
|
||||
*/
|
||||
ngtcp2_cc_new_rtt_sample new_rtt_sample;
|
||||
/**
|
||||
* :member:`reset` is a callback function which is called when
|
||||
* congestion control state must be reset.
|
||||
*/
|
||||
ngtcp2_cc_reset reset;
|
||||
/**
|
||||
* :member:`event` is a callback function which is called when a
|
||||
* specific event happens.
|
||||
*/
|
||||
ngtcp2_cc_event event;
|
||||
} ngtcp2_cc;
|
||||
|
||||
/*
|
||||
@ -310,14 +268,16 @@ typedef struct ngtcp2_cc_reno {
|
||||
uint64_t pending_add;
|
||||
} ngtcp2_cc_reno;
|
||||
|
||||
void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log);
|
||||
void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log,
|
||||
ngtcp2_conn_stat *cstat);
|
||||
|
||||
void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
|
||||
|
||||
void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp sent_ts,
|
||||
uint64_t bytes_lost, ngtcp2_tstamp ts);
|
||||
const ngtcp2_cc_ack *ack,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
|
||||
ngtcp2_conn_stat *cstat,
|
||||
@ -340,8 +300,8 @@ typedef struct ngtcp2_cubic_vars {
|
||||
/* app_limited_duration is the cumulative duration where a
|
||||
connection is under app limited when ACK is received. */
|
||||
ngtcp2_duration app_limited_duration;
|
||||
uint64_t pending_bytes_delivered;
|
||||
uint64_t pending_est_bytes_delivered;
|
||||
uint64_t pending_bytes_acked;
|
||||
uint64_t pending_est_bytes_acked;
|
||||
} ngtcp2_cubic_vars;
|
||||
|
||||
/* ngtcp2_cc_cubic is CUBIC congestion controller. */
|
||||
@ -371,14 +331,15 @@ typedef struct ngtcp2_cc_cubic {
|
||||
} ngtcp2_cc_cubic;
|
||||
|
||||
void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cc, ngtcp2_log *log,
|
||||
ngtcp2_rst *rst);
|
||||
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst);
|
||||
|
||||
void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
|
||||
|
||||
void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp sent_ts,
|
||||
uint64_t bytes_lost, ngtcp2_tstamp ts);
|
||||
const ngtcp2_cc_ack *ack,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *ccx,
|
||||
ngtcp2_conn_stat *cstat,
|
||||
|
||||
12
deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c
vendored
12
deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c
vendored
@ -58,11 +58,13 @@ int ngtcp2_cid_less(const ngtcp2_cid *lhs, const ngtcp2_cid *rhs) {
|
||||
int ngtcp2_cid_empty(const ngtcp2_cid *cid) { return cid->datalen == 0; }
|
||||
|
||||
void ngtcp2_scid_init(ngtcp2_scid *scid, uint64_t seq, const ngtcp2_cid *cid) {
|
||||
scid->pe.index = NGTCP2_PQ_BAD_INDEX;
|
||||
scid->seq = seq;
|
||||
scid->cid = *cid;
|
||||
scid->retired_ts = UINT64_MAX;
|
||||
scid->flags = NGTCP2_SCID_FLAG_NONE;
|
||||
*scid = (ngtcp2_scid){
|
||||
.pe.index = NGTCP2_PQ_BAD_INDEX,
|
||||
.seq = seq,
|
||||
.cid = *cid,
|
||||
.retired_ts = UINT64_MAX,
|
||||
.flags = NGTCP2_SCID_FLAG_NONE,
|
||||
};
|
||||
}
|
||||
|
||||
void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) {
|
||||
|
||||
787
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c
vendored
787
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c
vendored
File diff suppressed because it is too large
Load Diff
27
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h
vendored
27
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h
vendored
@ -77,10 +77,6 @@ typedef enum {
|
||||
unreceived data. */
|
||||
#define NGTCP2_MAX_REORDERED_CRYPTO_DATA 65536
|
||||
|
||||
/* NGTCP2_MAX_RETRIES is the number of Retry packet which client can
|
||||
accept. */
|
||||
#define NGTCP2_MAX_RETRIES 3
|
||||
|
||||
/* NGTCP2_MAX_SCID_POOL_SIZE is the maximum number of source
|
||||
connection ID the local endpoint provides to the remote endpoint.
|
||||
The chosen value was described in old draft. Now a remote endpoint
|
||||
@ -116,19 +112,6 @@ typedef enum {
|
||||
packet as much as possible if the packet is not empty. */
|
||||
#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08u
|
||||
|
||||
/*
|
||||
* ngtcp2_max_frame is defined so that it covers the largest ACK
|
||||
* frame.
|
||||
*/
|
||||
typedef union ngtcp2_max_frame {
|
||||
ngtcp2_frame fr;
|
||||
struct {
|
||||
ngtcp2_ack ack;
|
||||
/* ack includes 1 ngtcp2_ack_range. */
|
||||
ngtcp2_ack_range ranges[NGTCP2_MAX_ACK_RANGES - 1];
|
||||
} ackfr;
|
||||
} ngtcp2_max_frame;
|
||||
|
||||
typedef struct ngtcp2_path_challenge_entry {
|
||||
ngtcp2_path_storage ps;
|
||||
uint8_t data[8];
|
||||
@ -772,15 +755,9 @@ int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, ngtcp2_strm *strm);
|
||||
* ack_delay included in ACK frame. |ack_delay| is actually tainted
|
||||
* (sent by peer), so don't assume that |ack_delay| is always smaller
|
||||
* than, or equals to |rtt|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_INVALID_ARGUMENT
|
||||
* RTT sample is ignored.
|
||||
*/
|
||||
int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
||||
ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
|
||||
void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
||||
ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
|
||||
|
||||
void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts);
|
||||
|
||||
|
||||
50
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_info.c
vendored
Normal file
50
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_info.c
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ngtcp2_conn_info.h"
|
||||
#include "ngtcp2_conn_stat.h"
|
||||
|
||||
void ngtcp2_conn_info_init_versioned(int conn_info_version,
|
||||
ngtcp2_conn_info *cinfo,
|
||||
const ngtcp2_conn_stat *cstat) {
|
||||
cinfo->latest_rtt = cstat->latest_rtt;
|
||||
cinfo->min_rtt = cstat->min_rtt;
|
||||
cinfo->smoothed_rtt = cstat->smoothed_rtt;
|
||||
cinfo->rttvar = cstat->rttvar;
|
||||
cinfo->cwnd = cstat->cwnd;
|
||||
cinfo->ssthresh = cstat->ssthresh;
|
||||
cinfo->bytes_in_flight = cstat->bytes_in_flight;
|
||||
|
||||
switch (conn_info_version) {
|
||||
case NGTCP2_CONN_INFO_V2:
|
||||
cinfo->pkt_sent = cstat->pkt_sent;
|
||||
cinfo->bytes_sent = cstat->bytes_sent;
|
||||
cinfo->pkt_recv = cstat->pkt_recv;
|
||||
cinfo->bytes_recv = cstat->bytes_recv;
|
||||
cinfo->pkt_lost = cstat->pkt_lost;
|
||||
cinfo->bytes_lost = cstat->bytes_lost;
|
||||
cinfo->ping_recv = cstat->ping_recv;
|
||||
cinfo->pkt_discarded = cstat->pkt_discarded;
|
||||
}
|
||||
}
|
||||
45
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_info.h
vendored
Normal file
45
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_info.h
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2025 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGTCP2_CONN_INFO_H
|
||||
#define NGTCP2_CONN_INFO_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* defined(HAVE_CONFIG_H) */
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
typedef struct ngtcp2_conn_stat ngtcp2_conn_stat;
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_info_init_versioned initializes |cinfo| of version
|
||||
* |conn_info_version| from |cstat|. This function only fills the
|
||||
* fields of |cinfo| that are available in the specified version.
|
||||
*/
|
||||
void ngtcp2_conn_info_init_versioned(int conn_info_version,
|
||||
ngtcp2_conn_info *cinfo,
|
||||
const ngtcp2_conn_stat *cstat);
|
||||
|
||||
#endif /* !defined(NGTCP2_CONN_INFO_H) */
|
||||
39
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h
vendored
39
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn_stat.h
vendored
@ -31,6 +31,8 @@
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#include "ngtcp2_pktns_id.h"
|
||||
|
||||
/**
|
||||
* @struct
|
||||
*
|
||||
@ -128,6 +130,43 @@ typedef struct ngtcp2_conn_stat {
|
||||
* scheduled and transmitted together.
|
||||
*/
|
||||
size_t send_quantum;
|
||||
/*
|
||||
* pkt_sent is the number of QUIC packets sent.
|
||||
*/
|
||||
uint64_t pkt_sent;
|
||||
/*
|
||||
* bytes_sent is the number of bytes (the sum of QUIC packet length)
|
||||
* sent.
|
||||
*/
|
||||
uint64_t bytes_sent;
|
||||
/*
|
||||
* pkt_recv is the number of QUIC packets received, excluding
|
||||
* discarded ones.
|
||||
*/
|
||||
uint64_t pkt_recv;
|
||||
/*
|
||||
* bytes_recv is the number of bytes (the sum of QUIC packet length)
|
||||
* received, excluding discarded ones.
|
||||
*/
|
||||
uint64_t bytes_recv;
|
||||
/*
|
||||
* pkt_lost is the number of QUIC packets that are considered lost,
|
||||
* excluding PMTUD packets.
|
||||
*/
|
||||
uint64_t pkt_lost;
|
||||
/*
|
||||
* bytes_lost is the number of bytes (the sum of QUIC packet length)
|
||||
* lost, excluding PMTUD packets.
|
||||
*/
|
||||
uint64_t bytes_lost;
|
||||
/*
|
||||
* ping_recv is the number of PING frames received.
|
||||
*/
|
||||
uint64_t ping_recv;
|
||||
/*
|
||||
* pkt_discarded is the number of QUIC packets discarded.
|
||||
*/
|
||||
uint64_t pkt_discarded;
|
||||
} ngtcp2_conn_stat;
|
||||
|
||||
#endif /* !defined(NGTCP2_CONN_STAT_H) */
|
||||
|
||||
30
deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c
vendored
30
deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c
vendored
@ -63,33 +63,33 @@ const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p) {
|
||||
}
|
||||
|
||||
static const uint8_t *get_uvarint(uint64_t *dest, const uint8_t *p) {
|
||||
union {
|
||||
uint8_t n8;
|
||||
uint16_t n16;
|
||||
uint32_t n32;
|
||||
uint64_t n64;
|
||||
} n;
|
||||
uint16_t n16;
|
||||
uint32_t n32;
|
||||
uint64_t n64;
|
||||
|
||||
switch (*p >> 6) {
|
||||
case 0:
|
||||
*dest = *p++;
|
||||
return p;
|
||||
case 1:
|
||||
memcpy(&n, p, 2);
|
||||
n.n8 &= 0x3f;
|
||||
*dest = ngtcp2_ntohs(n.n16);
|
||||
memcpy(&n16, p, 2);
|
||||
n16 = ngtcp2_ntohs(n16);
|
||||
n16 &= 0x3fff;
|
||||
*dest = n16;
|
||||
|
||||
return p + 2;
|
||||
case 2:
|
||||
memcpy(&n, p, 4);
|
||||
n.n8 &= 0x3f;
|
||||
*dest = ngtcp2_ntohl(n.n32);
|
||||
memcpy(&n32, p, 4);
|
||||
n32 = ngtcp2_ntohl(n32);
|
||||
n32 &= 0x3fffffff;
|
||||
*dest = n32;
|
||||
|
||||
return p + 4;
|
||||
case 3:
|
||||
memcpy(&n, p, 8);
|
||||
n.n8 &= 0x3f;
|
||||
*dest = ngtcp2_ntohl64(n.n64);
|
||||
memcpy(&n64, p, 8);
|
||||
n64 = ngtcp2_ntohl64(n64);
|
||||
n64 &= 0x3fffffffffffffff;
|
||||
*dest = n64;
|
||||
|
||||
return p + 8;
|
||||
default:
|
||||
|
||||
24
deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c
vendored
24
deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c
vendored
@ -65,15 +65,21 @@ int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
|
||||
}
|
||||
|
||||
p = (uint8_t *)(*pckm) + sizeof(ngtcp2_crypto_km);
|
||||
(*pckm)->secret.base = p;
|
||||
(*pckm)->secret.len = secretlen;
|
||||
p += secretlen;
|
||||
(*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;
|
||||
|
||||
**pckm = (ngtcp2_crypto_km){
|
||||
.secret =
|
||||
{
|
||||
.base = p,
|
||||
.len = secretlen,
|
||||
},
|
||||
.iv =
|
||||
{
|
||||
.base = p + secretlen,
|
||||
.len = ivlen,
|
||||
},
|
||||
.pkt_num = -1,
|
||||
.flags = NGTCP2_CRYPTO_KM_FLAG_NONE,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
28
deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c
vendored
28
deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.c
vendored
@ -57,14 +57,26 @@ int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc,
|
||||
size_t datacnt,
|
||||
ngtcp2_objalloc *objalloc,
|
||||
const ngtcp2_mem *mem) {
|
||||
int rv;
|
||||
|
||||
if (datacnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
|
||||
return ngtcp2_frame_chain_extralen_new(pfrc,
|
||||
sizeof(ngtcp2_vec) * (datacnt - 1) -
|
||||
NGTCP2_FRAME_CHAIN_STREAM_AVAIL,
|
||||
mem);
|
||||
rv = ngtcp2_frame_chain_extralen_new(
|
||||
pfrc,
|
||||
sizeof(ngtcp2_vec) * (datacnt - NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES),
|
||||
mem);
|
||||
} else {
|
||||
rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc);
|
||||
}
|
||||
|
||||
return ngtcp2_frame_chain_objalloc_new(pfrc, objalloc);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
(*pfrc)->fr.stream.data =
|
||||
(ngtcp2_vec *)(void *)((uint8_t *)*pfrc +
|
||||
offsetof(ngtcp2_frame_chain, buf));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
|
||||
@ -87,9 +99,9 @@ int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
|
||||
}
|
||||
|
||||
fr = &(*pfrc)->fr;
|
||||
fr->type = NGTCP2_FRAME_NEW_TOKEN;
|
||||
fr->new_token.type = NGTCP2_FRAME_NEW_TOKEN;
|
||||
|
||||
p = (uint8_t *)fr + sizeof(ngtcp2_new_token);
|
||||
p = (uint8_t *)*pfrc + offsetof(ngtcp2_frame_chain, buf);
|
||||
memcpy(p, token, tokenlen);
|
||||
|
||||
fr->new_token.token = p;
|
||||
@ -122,7 +134,7 @@ void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
|
||||
return;
|
||||
}
|
||||
|
||||
switch (frc->fr.type) {
|
||||
switch (frc->fr.hd.type) {
|
||||
case NGTCP2_FRAME_CRYPTO:
|
||||
case NGTCP2_FRAME_STREAM:
|
||||
if (frc->fr.stream.datacnt > NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES) {
|
||||
|
||||
34
deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h
vendored
34
deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h
vendored
@ -57,6 +57,19 @@ typedef struct ngtcp2_frame_chain_binder {
|
||||
int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder,
|
||||
const ngtcp2_mem *mem);
|
||||
|
||||
/* NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES is the number of datacnt
|
||||
that changes allocation method. If datacnt is more than this
|
||||
value, ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
||||
Otherwise, it is allocated using ngtcp2_objalloc. */
|
||||
#define NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES 4
|
||||
|
||||
/* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES is the length of a token that
|
||||
changes allocation method. If the length is more than this value,
|
||||
ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
||||
Otherwise, it is allocated using ngtcp2_objalloc. */
|
||||
#define NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES \
|
||||
(NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES * sizeof(ngtcp2_vec))
|
||||
|
||||
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
|
||||
|
||||
/*
|
||||
@ -68,6 +81,7 @@ struct ngtcp2_frame_chain {
|
||||
ngtcp2_frame_chain *next;
|
||||
ngtcp2_frame_chain_binder *binder;
|
||||
ngtcp2_frame fr;
|
||||
uint8_t buf[sizeof(ngtcp2_vec) * NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES];
|
||||
};
|
||||
|
||||
ngtcp2_opl_entry oplent;
|
||||
@ -104,26 +118,6 @@ int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc,
|
||||
int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
|
||||
const ngtcp2_mem *mem);
|
||||
|
||||
/* NGTCP2_FRAME_CHAIN_STREAM_AVAIL is the number of additional bytes
|
||||
available after ngtcp2_stream when it is embedded in
|
||||
ngtcp2_frame. */
|
||||
#define NGTCP2_FRAME_CHAIN_STREAM_AVAIL \
|
||||
(sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream))
|
||||
|
||||
/* NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES is the number of datacnt
|
||||
that changes allocation method. If datacnt is more than this
|
||||
value, ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
||||
Otherwise, it is allocated using ngtcp2_objalloc. */
|
||||
#define NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES \
|
||||
(NGTCP2_FRAME_CHAIN_STREAM_AVAIL / sizeof(ngtcp2_vec) + 1)
|
||||
|
||||
/* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES is the length of a token that
|
||||
changes allocation method. If the length is more than this value,
|
||||
ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
|
||||
Otherwise, it is allocated using ngtcp2_objalloc. */
|
||||
#define NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES \
|
||||
(sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token))
|
||||
|
||||
/*
|
||||
* ngtcp2_frame_chain_stream_datacnt_objalloc_new allocates enough
|
||||
* data to store additional |datacnt| - 1 ngtcp2_vec object after
|
||||
|
||||
20
deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c
vendored
20
deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c
vendored
@ -35,11 +35,11 @@ void ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) {
|
||||
}
|
||||
|
||||
static int gaptr_gap_init(ngtcp2_gaptr *gaptr) {
|
||||
ngtcp2_range range = {
|
||||
.end = UINT64_MAX,
|
||||
};
|
||||
|
||||
return ngtcp2_ksl_insert(&gaptr->gap, NULL, &range, NULL);
|
||||
return ngtcp2_ksl_insert(&gaptr->gap, NULL,
|
||||
&(ngtcp2_range){
|
||||
.end = UINT64_MAX,
|
||||
},
|
||||
NULL);
|
||||
}
|
||||
|
||||
void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr) {
|
||||
@ -116,10 +116,6 @@ uint64_t ngtcp2_gaptr_first_gap_offset(const ngtcp2_gaptr *gaptr) {
|
||||
|
||||
ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
|
||||
uint64_t offset) {
|
||||
ngtcp2_range q = {
|
||||
.begin = offset,
|
||||
.end = offset + 1,
|
||||
};
|
||||
ngtcp2_ksl_it it;
|
||||
|
||||
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
|
||||
@ -129,7 +125,11 @@ ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
|
||||
return r;
|
||||
}
|
||||
|
||||
it = ngtcp2_ksl_lower_bound_search(&gaptr->gap, &q,
|
||||
it = ngtcp2_ksl_lower_bound_search(&gaptr->gap,
|
||||
&(ngtcp2_range){
|
||||
.begin = offset,
|
||||
.end = offset + 1,
|
||||
},
|
||||
ngtcp2_ksl_range_exclusive_search);
|
||||
|
||||
assert(!ngtcp2_ksl_it_end(&it));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user