diff --git a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c index 0409a4e50cae7a..e43faa76850a25 100644 --- a/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c @@ -402,7 +402,7 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { - static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00"; + static const uint8_t PLAINTEXT[16] = {0}; ngtcp2_crypto_boringssl_cipher_ctx *ctx = hp_ctx->native_handle; uint32_t counter; @@ -420,7 +420,7 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, #else /* !defined(WORDS_BIGENDIAN) */ memcpy(&counter, sample, sizeof(counter)); #endif /* !defined(WORDS_BIGENDIAN) */ - CRYPTO_chacha_20(dest, PLAINTEXT, ngtcp2_strlen_lit(PLAINTEXT), ctx->key, + CRYPTO_chacha_20(dest, PLAINTEXT, sizeof(PLAINTEXT), ctx->key, sample + sizeof(counter), counter); return 0; default: @@ -436,7 +436,8 @@ int ngtcp2_crypto_read_write_crypto_data( int rv; int err; - if (SSL_provide_quic_data( + if (datalen && + SSL_provide_quic_data( ssl, ngtcp2_crypto_boringssl_from_ngtcp2_encryption_level(encryption_level), data, datalen) != 1) { @@ -465,6 +466,16 @@ int ngtcp2_crypto_read_write_crypto_data( } goto retry; + case SSL_ERROR_WANT_X509_LOOKUP: + case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION: + case SSL_ERROR_WANT_CERTIFICATE_VERIFY: + /* It might be better to return this error, but ngtcp2 does + not need to know whether handshake has been interrupted or + not. We expect that necessary plumbing should be done by + application when handshake is interrupted (e.g., via + SSL_PRIVATE_KEY_METHOD). If it does not work, we will + reconsider this. */ + return 0; default: return -1; } @@ -568,6 +579,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data, return 0; } +int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn, + ngtcp2_path_challenge_data *data, + void *user_data) { + (void)conn; + (void)user_data; + + if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + int ngtcp2_crypto_random(uint8_t *data, size_t datalen) { if (RAND_bytes(data, datalen) != 1) { return -1; diff --git a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h index c2099d24950ac2..28eeeb5ead8061 100644 --- a/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h +++ b/deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h @@ -524,11 +524,14 @@ NGTCP2_EXTERN int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn, * completes. It is allowed to call this function with |datalen| == * 0. In this case, no additional read operation is done. * + * This function is implemented per TLS backend. See + * :ref:`tls-integration` for more details. + * * This function returns 0 if it succeeds, or a negative error code. * The generic error code is -1 if a specific error code is not * suitable. The error codes less than -10000 are specific to - * underlying TLS implementation. For quictls, the error codes are - * defined in *ngtcp2_crypto_quictls.h*. + * underlying TLS implementation. Refer to the implementation + * specific header files for error codes. */ NGTCP2_EXTERN int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, @@ -542,11 +545,22 @@ ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn, * `ngtcp2_crypto_read_write_crypto_data`. It can be directly passed * to :member:`ngtcp2_callbacks.recv_crypto_data` field. * + * For quictls and OpenSSL, the following error codes are treated as + * success: + * + * - -10001 (e.g., :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP`) + * - -10002 (e.g., :macro:`NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB`) + * + * To continue the interrupted handshake, call + * `ngtcp2_conn_continue_handshake`. + * + * See :ref:`tls-integration` for more details. + * * If this function is used, the TLS implementation specific error * codes described in `ngtcp2_crypto_read_write_crypto_data` are - * treated as if it returns -1. Do not use this function if an - * application wishes to use the TLS implementation specific error - * codes. + * treated as if it returns -1 except for those that are listed above. + * Do not use this function if an application wishes to use the TLS + * implementation specific error codes. */ NGTCP2_EXTERN int ngtcp2_crypto_recv_crypto_data_cb( ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level, uint64_t offset, @@ -583,7 +597,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token( * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY` is the magic byte for * Retry token generated by `ngtcp2_crypto_generate_retry_token`. */ -#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY 0xb6 +#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY 0xB6 /** * @macro @@ -591,7 +605,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token( * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2` is the magic byte for * Retry token generated by `ngtcp2_crypto_generate_retry_token2`. */ -#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 0xb7 +#define NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2 0xB7 /** * @macro @@ -978,11 +992,29 @@ NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_cipher_ctx_cb( * * This function can be directly passed to * :member:`ngtcp2_callbacks.get_path_challenge_data` field. + * + * Deprecated since v1.22.0. Use + * `ngtcp2_crypto_get_path_challenge_data2_cb` instead. */ NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data, void *user_data); +/** + * @function + * + * `ngtcp2_crypto_get_path_challenge_data2_cb` writes unpredictable + * sequence of :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes to |data| + * which is sent with PATH_CHALLENGE frame. + * + * This function can be directly passed to + * :member:`ngtcp2_callbacks.get_path_challenge_data2` field. + * + * This function has been available since v1.22.0. + */ +NGTCP2_EXTERN int ngtcp2_crypto_get_path_challenge_data2_cb( + ngtcp2_conn *conn, ngtcp2_path_challenge_data *data, void *user_data); + /** * @function * diff --git a/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c b/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c index 81cadc6424b3e7..fa393c8ece5200 100644 --- a/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c +++ b/deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c @@ -49,8 +49,8 @@ static EVP_CIPHER *crypto_aes_128_gcm; static EVP_CIPHER *crypto_aes_256_gcm; static EVP_CIPHER *crypto_aes_128_ccm; -static EVP_CIPHER *crypto_aes_128_ctr; -static EVP_CIPHER *crypto_aes_256_ctr; +static EVP_CIPHER *crypto_aes_128_ecb; +static EVP_CIPHER *crypto_aes_256_ecb; #ifndef NGTCP2_NO_CHACHA_POLY1305 static EVP_CIPHER *crypto_chacha20_poly1305; static EVP_CIPHER *crypto_chacha20; @@ -66,8 +66,8 @@ int ngtcp2_crypto_ossl_init(void) { crypto_aes_128_gcm = EVP_CIPHER_fetch(NULL, "AES-128-GCM", NULL); crypto_aes_256_gcm = EVP_CIPHER_fetch(NULL, "AES-256-GCM", NULL); crypto_aes_128_ccm = EVP_CIPHER_fetch(NULL, "AES-128-CCM", NULL); - crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL); - crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL); + crypto_aes_128_ecb = EVP_CIPHER_fetch(NULL, "AES-128-ECB", NULL); + crypto_aes_256_ecb = EVP_CIPHER_fetch(NULL, "AES-256-ECB", NULL); #ifndef NGTCP2_NO_CHACHA_POLY1305 crypto_chacha20_poly1305 = EVP_CIPHER_fetch(NULL, "ChaCha20-Poly1305", NULL); crypto_chacha20 = EVP_CIPHER_fetch(NULL, "ChaCha20", NULL); @@ -113,20 +113,20 @@ static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) { return EVP_aes_128_ccm(); } -static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) { - if (crypto_aes_128_ctr) { - return crypto_aes_128_ctr; +static const EVP_CIPHER *crypto_cipher_aes_128_ecb(void) { + if (crypto_aes_128_ecb) { + return crypto_aes_128_ecb; } - return EVP_aes_128_ctr(); + return EVP_aes_128_ecb(); } -static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) { - if (crypto_aes_256_ctr) { - return crypto_aes_256_ctr; +static const EVP_CIPHER *crypto_cipher_aes_256_ecb(void) { + if (crypto_aes_256_ecb) { + return crypto_aes_256_ecb; } - return EVP_aes_256_ctr(); + return EVP_aes_256_ecb(); } #ifndef NGTCP2_NO_CHACHA_POLY1305 @@ -198,7 +198,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) { ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) { ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm()); ctx->md.native_handle = (void *)crypto_md_sha256(); - ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr(); + ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ecb(); ctx->max_encryption = 0; ctx->max_decryption_failure = 0; return ctx; @@ -269,9 +269,9 @@ static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) { switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_128_CCM_SHA256: - return crypto_cipher_aes_128_ctr(); + return crypto_cipher_aes_128_ecb(); case TLS1_3_CK_AES_256_GCM_SHA384: - return crypto_cipher_aes_256_ctr(); + return crypto_cipher_aes_256_ecb(); #ifndef NGTCP2_NO_CHACHA_POLY1305 case TLS1_3_CK_CHACHA20_POLY1305_SHA256: return crypto_cipher_chacha20(); @@ -838,17 +838,31 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { - static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00"; + static const uint8_t PLAINTEXT[16] = {0}; EVP_CIPHER_CTX *actx = hp_ctx->native_handle; int len; (void)hp; - if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) || - !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, - ngtcp2_strlen_lit(PLAINTEXT)) || - !EVP_EncryptFinal_ex(actx, dest + ngtcp2_strlen_lit(PLAINTEXT), &len)) { - return -1; + switch (EVP_CIPHER_CTX_nid(actx)) { + case NID_aes_128_ecb: + case NID_aes_256_ecb: + if (!EVP_EncryptUpdate(actx, dest, &len, sample, NGTCP2_HP_SAMPLELEN)) { + return -1; + } + + break; + case NID_chacha20: + if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) || + !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT)) || + !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len)) { + return -1; + } + + break; + default: + assert(0); + abort(); } return 0; @@ -983,6 +997,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data, return 0; } +int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn, + ngtcp2_path_challenge_data *data, + void *user_data) { + (void)conn; + (void)user_data; + + if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + int ngtcp2_crypto_random(uint8_t *data, size_t datalen) { if (RAND_bytes(data, (int)datalen) != 1) { return -1; diff --git a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c index d9a388e3699ce1..bd29a541277b0f 100644 --- a/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c +++ b/deps/ngtcp2/ngtcp2/crypto/picotls/picotls.c @@ -50,7 +50,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) { ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) { ngtcp2_crypto_aead_init(&ctx->aead, (void *)&ptls_openssl_aes128gcm); ctx->md.native_handle = (void *)&ptls_openssl_sha256; - ctx->hp.native_handle = (void *)&ptls_openssl_aes128ctr; + ctx->hp.native_handle = (void *)&ptls_openssl_aes128ecb; ctx->max_encryption = 0; ctx->max_decryption_failure = 0; return ctx; @@ -104,11 +104,11 @@ crypto_cipher_suite_get_aead_max_decryption_failure(ptls_cipher_suite_t *cs) { static const ptls_cipher_algorithm_t * crypto_cipher_suite_get_hp(ptls_cipher_suite_t *cs) { if (cs->aead == &ptls_openssl_aes128gcm) { - return &ptls_openssl_aes128ctr; + return &ptls_openssl_aes128ecb; } if (cs->aead == &ptls_openssl_aes256gcm) { - return &ptls_openssl_aes256ctr; + return &ptls_openssl_aes256ecb; } #ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 @@ -238,6 +238,11 @@ int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx, return -1; } + if (cipher->native_handle == &ptls_openssl_aes128ecb || + cipher->native_handle == &ptls_openssl_aes256ecb) { + ptls_cipher_init(actx, NULL); + } + cipher_ctx->native_handle = actx; return 0; @@ -352,13 +357,20 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { + static const uint8_t PLAINTEXT[16] = {0}; ptls_cipher_context_t *actx = hp_ctx->native_handle; - static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00"; (void)hp; + if (hp->native_handle == &ptls_openssl_aes128ecb || + hp->native_handle == &ptls_openssl_aes256ecb) { + ptls_cipher_encrypt(actx, dest, sample, NGTCP2_HP_SAMPLELEN); + + return 0; + } + ptls_cipher_init(actx, sample); - ptls_cipher_encrypt(actx, dest, PLAINTEXT, ngtcp2_strlen_lit(PLAINTEXT)); + ptls_cipher_encrypt(actx, dest, PLAINTEXT, sizeof(PLAINTEXT)); return 0; } @@ -377,7 +389,7 @@ int ngtcp2_crypto_read_write_crypto_data( ptls_buffer_init(&sendbuf, (void *)"", 0); - assert(epoch == ptls_get_read_epoch(cptls->ptls)); + assert(datalen == 0 || epoch == ptls_get_read_epoch(cptls->ptls)); rv = ptls_handle_message(cptls->ptls, &sendbuf, epoch_offsets, epoch, data, datalen, &cptls->handshake_properties); @@ -493,6 +505,17 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data, return 0; } +int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn, + ngtcp2_path_challenge_data *data, + void *user_data) { + (void)conn; + (void)user_data; + + ptls_openssl_random_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN); + + return 0; +} + int ngtcp2_crypto_random(uint8_t *data, size_t datalen) { ptls_openssl_random_bytes(data, datalen); @@ -500,8 +523,7 @@ int ngtcp2_crypto_random(uint8_t *data, size_t datalen) { } void ngtcp2_crypto_picotls_ctx_init(ngtcp2_crypto_picotls_ctx *cptls) { - cptls->ptls = NULL; - memset(&cptls->handshake_properties, 0, sizeof(cptls->handshake_properties)); + *cptls = (ngtcp2_crypto_picotls_ctx){0}; } static int set_additional_extensions(ptls_handshake_properties_t *hsprops, diff --git a/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c index 742321ec857690..1076d97bfc0e26 100644 --- a/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c +++ b/deps/ngtcp2/ngtcp2/crypto/quictls/quictls.c @@ -49,8 +49,8 @@ static EVP_CIPHER *crypto_aes_128_gcm; static EVP_CIPHER *crypto_aes_256_gcm; static EVP_CIPHER *crypto_chacha20_poly1305; static EVP_CIPHER *crypto_aes_128_ccm; -static EVP_CIPHER *crypto_aes_128_ctr; -static EVP_CIPHER *crypto_aes_256_ctr; +static EVP_CIPHER *crypto_aes_128_ecb; +static EVP_CIPHER *crypto_aes_256_ecb; static EVP_CIPHER *crypto_chacha20; static EVP_MD *crypto_sha256; static EVP_MD *crypto_sha384; @@ -77,13 +77,13 @@ int ngtcp2_crypto_quictls_init(void) { return -1; } - crypto_aes_128_ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", NULL); - if (crypto_aes_128_ctr == NULL) { + crypto_aes_128_ecb = EVP_CIPHER_fetch(NULL, "AES-128-ECB", NULL); + if (crypto_aes_128_ecb == NULL) { return -1; } - crypto_aes_256_ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", NULL); - if (crypto_aes_256_ctr == NULL) { + crypto_aes_256_ecb = EVP_CIPHER_fetch(NULL, "AES-256-ECB", NULL); + if (crypto_aes_256_ecb == NULL) { return -1; } @@ -144,20 +144,20 @@ static const EVP_CIPHER *crypto_aead_aes_128_ccm(void) { return EVP_aes_128_ccm(); } -static const EVP_CIPHER *crypto_cipher_aes_128_ctr(void) { - if (crypto_aes_128_ctr) { - return crypto_aes_128_ctr; +static const EVP_CIPHER *crypto_cipher_aes_128_ecb(void) { + if (crypto_aes_128_ecb) { + return crypto_aes_128_ecb; } - return EVP_aes_128_ctr(); + return EVP_aes_128_ecb(); } -static const EVP_CIPHER *crypto_cipher_aes_256_ctr(void) { - if (crypto_aes_256_ctr) { - return crypto_aes_256_ctr; +static const EVP_CIPHER *crypto_cipher_aes_256_ecb(void) { + if (crypto_aes_256_ecb) { + return crypto_aes_256_ecb; } - return EVP_aes_256_ctr(); + return EVP_aes_256_ecb(); } static const EVP_CIPHER *crypto_cipher_chacha20(void) { @@ -196,8 +196,8 @@ static EVP_KDF *crypto_kdf_hkdf(void) { # define crypto_aead_aes_256_gcm EVP_aes_256_gcm # define crypto_aead_chacha20_poly1305 EVP_chacha20_poly1305 # define crypto_aead_aes_128_ccm EVP_aes_128_ccm -# define crypto_cipher_aes_128_ctr EVP_aes_128_ctr -# define crypto_cipher_aes_256_ctr EVP_aes_256_ctr +# define crypto_cipher_aes_128_ecb EVP_aes_128_ecb +# define crypto_cipher_aes_256_ecb EVP_aes_256_ecb # define crypto_cipher_chacha20 EVP_chacha20 # define crypto_md_sha256 EVP_sha256 # define crypto_md_sha384 EVP_sha384 @@ -232,7 +232,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) { ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) { ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_aead_aes_128_gcm()); ctx->md.native_handle = (void *)crypto_md_sha256(); - ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ctr(); + ctx->hp.native_handle = (void *)crypto_cipher_aes_128_ecb(); ctx->max_encryption = 0; ctx->max_decryption_failure = 0; return ctx; @@ -297,9 +297,9 @@ static const EVP_CIPHER *crypto_cipher_id_get_hp(uint32_t cipher_id) { switch (cipher_id) { case TLS1_3_CK_AES_128_GCM_SHA256: case TLS1_3_CK_AES_128_CCM_SHA256: - return crypto_cipher_aes_128_ctr(); + return crypto_cipher_aes_128_ecb(); case TLS1_3_CK_AES_256_GCM_SHA384: - return crypto_cipher_aes_256_ctr(); + return crypto_cipher_aes_256_ecb(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: return crypto_cipher_chacha20(); default: @@ -779,17 +779,31 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { - static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00"; + static const uint8_t PLAINTEXT[16] = {0}; EVP_CIPHER_CTX *actx = hp_ctx->native_handle; int len; (void)hp; - if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) || - !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, - ngtcp2_strlen_lit(PLAINTEXT)) || - !EVP_EncryptFinal_ex(actx, dest + ngtcp2_strlen_lit(PLAINTEXT), &len)) { - return -1; + switch (EVP_CIPHER_CTX_nid(actx)) { + case NID_aes_128_ecb: + case NID_aes_256_ecb: + if (!EVP_EncryptUpdate(actx, dest, &len, sample, NGTCP2_HP_SAMPLELEN)) { + return -1; + } + + break; + case NID_chacha20: + if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) || + !EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT)) || + !EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len)) { + return -1; + } + + break; + default: + assert(0); + abort(); } return 0; @@ -802,7 +816,8 @@ int ngtcp2_crypto_read_write_crypto_data( int rv; int err; - if (SSL_provide_quic_data( + if (datalen && + SSL_provide_quic_data( ssl, ngtcp2_crypto_quictls_from_ngtcp2_encryption_level(encryption_level), data, datalen) != 1) { @@ -922,6 +937,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data, return 0; } +int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn, + ngtcp2_path_challenge_data *data, + void *user_data) { + (void)conn; + (void)user_data; + + if (RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + int ngtcp2_crypto_random(uint8_t *data, size_t datalen) { if (RAND_bytes(data, (int)datalen) != 1) { return -1; diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.c b/deps/ngtcp2/ngtcp2/crypto/shared.c index 1d8d1d68f78fd7..f1bb90267213da 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.c +++ b/deps/ngtcp2/ngtcp2/crypto/shared.c @@ -37,6 +37,22 @@ #include "ngtcp2_macro.h" #include "ngtcp2_net.h" +/* + * NGTCP2_INITIAL_SALT_V1 is a salt value which is used to derive + * initial secret. It is used for QUIC v1. + */ +static const uint8_t NGTCP2_INITIAL_SALT_V1[] = { + 0x38, 0x76, 0x2C, 0xF7, 0xF5, 0x59, 0x34, 0xB3, 0x4D, 0x17, + 0x9A, 0xE6, 0xA4, 0xC8, 0x0C, 0xAD, 0xCC, 0xBB, 0x7F, 0x0A}; + +/* + * NGTCP2_INITIAL_SALT_V2 is a salt value which is used to derive + * initial secret. It is used for QUIC v2. + */ +static const uint8_t NGTCP2_INITIAL_SALT_V2[] = { + 0x0D, 0xED, 0xE3, 0xDE, 0xF7, 0x00, 0xA6, 0xDB, 0x81, 0x93, + 0x81, 0xBE, 0x6E, 0x26, 0x9D, 0xCB, 0xF9, 0xBD, 0x2E, 0xD9}; + ngtcp2_crypto_md *ngtcp2_crypto_md_init(ngtcp2_crypto_md *md, void *md_native_handle) { md->native_handle = md_native_handle; @@ -87,12 +103,12 @@ int ngtcp2_crypto_derive_initial_secrets(uint8_t *rx_secret, uint8_t *tx_secret, switch (version) { case NGTCP2_PROTO_VER_V1: default: - salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V1; - saltlen = ngtcp2_strlen_lit(NGTCP2_INITIAL_SALT_V1); + salt = NGTCP2_INITIAL_SALT_V1; + saltlen = sizeof(NGTCP2_INITIAL_SALT_V1); break; case NGTCP2_PROTO_VER_V2: - salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V2; - saltlen = ngtcp2_strlen_lit(NGTCP2_INITIAL_SALT_V2); + salt = NGTCP2_INITIAL_SALT_V2; + saltlen = sizeof(NGTCP2_INITIAL_SALT_V2); break; } @@ -922,8 +938,8 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token( uint8_t *token, const uint8_t *secret, size_t secretlen, uint32_t version, const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen, const ngtcp2_cid *retry_scid, const ngtcp2_cid *odcid, ngtcp2_tstamp ts) { - uint8_t - plaintext[/* cid len = */ 1 + NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)]; + uint8_t plaintext[/* cid len = */ 1 + NGTCP2_MAX_CIDLEN + + sizeof(ngtcp2_tstamp)] = {0}; uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN]; uint8_t key[16]; uint8_t iv[12]; @@ -942,8 +958,6 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token( assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union)); - memset(plaintext, 0, sizeof(plaintext)); - *p++ = (uint8_t)odcid->datalen; memcpy(p, odcid->data, odcid->datalen); p += NGTCP2_MAX_CIDLEN; @@ -1104,7 +1118,7 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token2( const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen, const ngtcp2_cid *retry_scid, const ngtcp2_cid *odcid, ngtcp2_tstamp ts) { uint8_t plaintext[sizeof(ngtcp2_sockaddr_union) + /* cid len = */ 1 + - NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)]; + NGTCP2_MAX_CIDLEN + sizeof(ngtcp2_tstamp)] = {0}; uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN]; uint8_t key[16]; uint8_t iv[12]; @@ -1121,8 +1135,6 @@ ngtcp2_ssize ngtcp2_crypto_generate_retry_token2( assert((size_t)remote_addrlen <= sizeof(ngtcp2_sockaddr_union)); - memset(plaintext, 0, sizeof(plaintext)); - memcpy(p, remote_addr, (size_t)remote_addrlen); p += sizeof(ngtcp2_sockaddr_union); *p++ = (uint8_t)odcid->datalen; @@ -1717,8 +1729,21 @@ int ngtcp2_crypto_recv_crypto_data_cb(ngtcp2_conn *conn, (void)offset; (void)user_data; - if (ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data, - datalen) != 0) { + rv = + ngtcp2_crypto_read_write_crypto_data(conn, encryption_level, data, datalen); + if (rv != 0) { + switch (rv) { + case /* NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_CLIENT_HELLO_CB */ -10001: + case /* NGTCP2_CRYPTO_QUICTLS_ERR_TLS_WANT_X509_LOOKUP */ -10002: + /* These errors are not unrecoverable error, and they just + indicate that handshake has been interrupted. ngtcp2 does + not mind whether handshake is interrupted or not. Just + return 0 in this case. There are OSSL version and they have + the same enum value, therefore we cannot enumerate them + here. */ + return 0; + } + rv = ngtcp2_conn_get_tls_error(conn); if (rv) { return rv; diff --git a/deps/ngtcp2/ngtcp2/crypto/shared.h b/deps/ngtcp2/ngtcp2/crypto/shared.h index 34158d3d02dbc0..c517b7f2249041 100644 --- a/deps/ngtcp2/ngtcp2/crypto/shared.h +++ b/deps/ngtcp2/ngtcp2/crypto/shared.h @@ -31,26 +31,6 @@ #include -/** - * @macro - * - * :macro:`NGTCP2_INITIAL_SALT_V1` is a salt value which is used to - * derive initial secret. It is used for QUIC v1. - */ -#define NGTCP2_INITIAL_SALT_V1 \ - "\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb" \ - "\x7f\x0a" - -/** - * @macro - * - * :macro:`NGTCP2_INITIAL_SALT_V2` is a salt value which is used to - * derive initial secret. It is used for QUIC v2. - */ -#define NGTCP2_INITIAL_SALT_V2 \ - "\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb\xf9\xbd" \ - "\x2e\xd9" - /* Maximum key usage (encryption) limits */ #define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM (1ULL << 23) #define NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305 (1ULL << 62) diff --git a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c index 168d32ce109a8d..fa2b147b6ba1be 100644 --- a/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c +++ b/deps/ngtcp2/ngtcp2/crypto/wolfssl/wolfssl.c @@ -56,7 +56,7 @@ ngtcp2_crypto_md *ngtcp2_crypto_md_sha256(ngtcp2_crypto_md *md) { ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) { ngtcp2_crypto_aead_init(&ctx->aead, (void *)wolfSSL_EVP_aes_128_gcm()); ctx->md.native_handle = (void *)wolfSSL_EVP_sha256(); - ctx->hp.native_handle = (void *)wolfSSL_EVP_aes_128_ctr(); + ctx->hp.native_handle = (void *)wolfSSL_EVP_aes_128_ecb(); ctx->max_encryption = 0; ctx->max_decryption_failure = 0; return ctx; @@ -107,6 +107,21 @@ static int supported_aead(const WOLFSSL_EVP_CIPHER *aead) { wolfSSL_quic_aead_is_chacha20(aead) || wolfSSL_quic_aead_is_ccm(aead); } +static const WOLFSSL_EVP_CIPHER * +crypto_aead_get_hp(const WOLFSSL_EVP_CIPHER *aead) { + switch (wolfSSL_EVP_CIPHER_nid(aead)) { + case NID_aes_128_gcm: + case NID_aes_128_ccm: + return wolfSSL_EVP_aes_128_ecb(); + case NID_aes_256_gcm: + return wolfSSL_EVP_aes_256_ecb(); + case NID_chacha20_poly1305: + return wolfSSL_EVP_chacha20(); + default: + return NULL; + } +} + ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, void *tls_native_handle) { WOLFSSL *ssl = tls_native_handle; @@ -122,7 +137,7 @@ ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx, ngtcp2_crypto_aead_init(&ctx->aead, (void *)aead); ctx->md.native_handle = (void *)wolfSSL_quic_get_md(ssl); - ctx->hp.native_handle = (void *)wolfSSL_quic_get_hp(ssl); + ctx->hp.native_handle = (void *)crypto_aead_get_hp(aead); ctx->max_encryption = crypto_aead_get_aead_max_encryption(aead); ctx->max_decryption_failure = crypto_aead_get_aead_max_decryption_failure(aead); @@ -289,21 +304,33 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead, int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp, const ngtcp2_crypto_cipher_ctx *hp_ctx, const uint8_t *sample) { - static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00"; + static const uint8_t PLAINTEXT[16] = {0}; WOLFSSL_EVP_CIPHER_CTX *actx = hp_ctx->native_handle; int len; (void)hp; - if (wolfSSL_EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) != - WOLFSSL_SUCCESS || - wolfSSL_EVP_CipherUpdate(actx, dest, &len, PLAINTEXT, - ngtcp2_strlen_lit(PLAINTEXT)) != - WOLFSSL_SUCCESS || - wolfSSL_EVP_EncryptFinal_ex(actx, dest + ngtcp2_strlen_lit(PLAINTEXT), - &len) != WOLFSSL_SUCCESS) { - DEBUG_MSG("WOLFSSL: hp_mask FAILED\n"); - return -1; + switch (wolfSSL_EVP_CIPHER_CTX_nid(actx)) { + case NID_aes_128_ecb: + case NID_aes_256_ecb: + if (!wolfSSL_EVP_CipherUpdate(actx, dest, &len, sample, + NGTCP2_HP_SAMPLELEN)) { + return -1; + } + + break; + case NID_chacha20: + if (wolfSSL_EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) != + WOLFSSL_SUCCESS || + wolfSSL_EVP_CipherUpdate(actx, dest, &len, PLAINTEXT, + sizeof(PLAINTEXT)) != WOLFSSL_SUCCESS || + wolfSSL_EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT), &len) != + WOLFSSL_SUCCESS) { + DEBUG_MSG("WOLFSSL: hp_mask FAILED\n"); + return -1; + } + + break; } return 0; @@ -444,6 +471,19 @@ int ngtcp2_crypto_get_path_challenge_data_cb(ngtcp2_conn *conn, uint8_t *data, return 0; } +int ngtcp2_crypto_get_path_challenge_data2_cb(ngtcp2_conn *conn, + ngtcp2_path_challenge_data *data, + void *user_data) { + (void)conn; + (void)user_data; + + DEBUG_MSG("WOLFSSL: get path challenge data\n"); + if (wolfSSL_RAND_bytes(data->data, NGTCP2_PATH_CHALLENGE_DATALEN) != 1) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + return 0; +} + int ngtcp2_crypto_random(uint8_t *data, size_t datalen) { DEBUG_MSG("WOLFSSL: get random\n"); if (wolfSSL_RAND_bytes(data, (int)datalen) != 1) { diff --git a/deps/ngtcp2/ngtcp2/examples/client.cc b/deps/ngtcp2/ngtcp2/examples/client.cc index 56b757b2d91ed1..0c10e7bbdc0483 100644 --- a/deps/ngtcp2/ngtcp2/examples/client.cc +++ b/deps/ngtcp2/ngtcp2/examples/client.cc @@ -73,7 +73,7 @@ Stream::~Stream() { } } -int Stream::open_file(const std::string_view &path) { +std::expected Stream::open_file(std::string_view path) { assert(fd == -1); std::string_view filename; @@ -84,8 +84,8 @@ int Stream::open_file(const std::string_view &path) { } else { filename = std::string_view{it, std::ranges::end(path)}; if (filename == ".."sv || filename == "."sv) { - std::cerr << "Invalid file name: " << filename << std::endl; - return -1; + std::println(stderr, "Invalid file name: {}", filename); + return std::unexpected{Error::INVALID_ARGUMENT}; } } @@ -96,12 +96,12 @@ int Stream::open_file(const std::string_view &path) { fd = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd == -1) { - std::cerr << "open: Could not open file " << fname << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "open: Could not open file {}: {}", fname, + strerror(errno)); + return std::unexpected{Error::IO}; } - return 0; + return {}; } namespace { @@ -117,7 +117,7 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) { auto ep = static_cast(w->data); auto c = ep->client; - if (c->on_read(*ep) != 0) { + if (!c->on_read(*ep)) { return; } @@ -127,11 +127,9 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) { namespace { void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { - int rv; auto c = static_cast(w->data); - rv = c->handle_expiry(); - if (rv != 0) { + if (auto rv = c->handle_expiry(); !rv) { return; } @@ -151,7 +149,7 @@ namespace { void key_updatecb(struct ev_loop *loop, ev_timer *w, int revents) { auto c = static_cast(w->data); - if (c->initiate_key_update() != 0) { + if (!c->initiate_key_update()) { c->disconnect(); } } @@ -258,7 +256,7 @@ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, auto c = static_cast(user_data); - if (c->recv_stream_data(flags, stream_id, {data, datalen}) != 0) { + if (!c->recv_stream_data(flags, stream_id, {data, datalen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -271,7 +269,7 @@ int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id, uint64_t offset, uint64_t datalen, void *user_data, void *stream_user_data) { auto c = static_cast(user_data); - if (c->acked_stream_data_offset(stream_id, datalen) != 0) { + if (!c->acked_stream_data_offset(stream_id, datalen)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; @@ -286,7 +284,7 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { debug::handshake_completed(conn, user_data); } - if (c->handshake_completed() != 0) { + if (!c->handshake_completed()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -294,10 +292,10 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { } } // namespace -int Client::handshake_completed() { +std::expected Client::handshake_completed() { if (early_data_ && !tls_session_.get_early_data_accepted()) { if (!config.quiet) { - std::cerr << "Early data was rejected by server" << std::endl; + std::println(stderr, "Early data was rejected by server"); } // Some TLS backends only report early data rejection after @@ -305,27 +303,27 @@ int Client::handshake_completed() { // report it early (e.g., BoringSSL and PicoTLS), the following // functions are noop. if (auto rv = ngtcp2_conn_tls_early_data_rejected(conn_); rv != 0) { - std::cerr << "ngtcp2_conn_tls_early_data_rejected: " - << ngtcp2_strerror(rv) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_tls_early_data_rejected: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - if (setup_httpconn() != 0) { - return -1; + if (auto rv = setup_httpconn(); !rv) { + return rv; } } if (!config.quiet) { - std::cerr << "Negotiated cipher suite is " << tls_session_.get_cipher_name() - << std::endl; + std::println(stderr, "Negotiated cipher suite is {}", + tls_session_.get_cipher_name()); if (auto group = tls_session_.get_negotiated_group(); !group.empty()) { - std::cerr << "Negotiated group is " << group << std::endl; + std::println(stderr, "Negotiated group is {}", group); } - std::cerr << "Negotiated ALPN is " << tls_session_.get_selected_alpn() - << std::endl; + std::println(stderr, "Negotiated ALPN is {}", + tls_session_.get_selected_alpn()); if (!config.ech_config_list.empty() && tls_session_.get_ech_accepted()) { - std::cerr << "ECH was accepted" << std::endl; + std::println(stderr, "ECH was accepted"); } } @@ -334,17 +332,16 @@ int Client::handshake_completed() { auto datalen = ngtcp2_conn_encode_0rtt_transport_params(conn_, data.data(), data.size()); if (datalen < 0) { - std::cerr << "Could not encode 0-RTT transport parameters: " - << ngtcp2_strerror(static_cast(datalen)) << std::endl; - } else if (util::write_transport_params( - config.tp_file, {data.data(), static_cast(datalen)}) != - 0) { - std::cerr << "Could not write transport parameters in " << config.tp_file - << std::endl; + std::println(stderr, "Could not encode 0-RTT transport parameters: {}", + ngtcp2_strerror(static_cast(datalen))); + } else if (!util::write_transport_params( + config.tp_file, {data.data(), static_cast(datalen)})) { + std::println(stderr, "Could not write transport parameters to {}", + config.tp_file); } } - return 0; + return {}; } namespace { @@ -355,9 +352,7 @@ int handshake_confirmed(ngtcp2_conn *conn, void *user_data) { debug::handshake_confirmed(conn, user_data); } - if (c->handshake_confirmed() != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + c->handshake_confirmed(); return 0; } @@ -373,7 +368,7 @@ bool Client::should_exit() const { nstreams_closed_ == nstreams_done_)); } -int Client::handshake_confirmed() { +void Client::handshake_confirmed() { handshake_confirmed_ = true; if (config.change_local_addr) { @@ -385,8 +380,6 @@ int Client::handshake_confirmed() { if (config.delay_stream) { start_delay_stream_timer(); } - - return 0; } namespace { @@ -416,7 +409,7 @@ int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, app_error_code = NGHTTP3_H3_NO_ERROR; } - if (c->on_stream_close(stream_id, app_error_code) != 0) { + if (!c->on_stream_close(stream_id, app_error_code)) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -430,7 +423,7 @@ int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size, void *stream_user_data) { auto c = static_cast(user_data); - if (c->on_stream_reset(stream_id) != 0) { + if (!c->on_stream_reset(stream_id)) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -444,7 +437,7 @@ int stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id, void *stream_user_data) { auto c = static_cast(user_data); - if (c->on_stream_stop_sending(stream_id) != 0) { + if (!c->on_stream_stop_sending(stream_id)) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -457,9 +450,7 @@ int extend_max_local_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams, void *user_data) { auto c = static_cast(user_data); - if (c->on_extend_max_streams() != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + c->on_extend_max_streams(); return 0; } @@ -467,8 +458,7 @@ int extend_max_local_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams, namespace { void rand_bytes(uint8_t *dest, size_t destlen) { - auto rv = util::generate_secure_random({dest, destlen}); - if (rv != 0) { + if (!util::generate_secure_random({dest, destlen})) { assert(0); abort(); } @@ -482,16 +472,17 @@ void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { } // namespace namespace { -int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token, - size_t cidlen, void *user_data) { - if (util::generate_secure_random({cid->data, cidlen}) != 0) { +int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, + ngtcp2_stateless_reset_token *token, size_t cidlen, + void *user_data) { + if (!util::generate_secure_random({cid->data, cidlen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } cid->datalen = cidlen; if (ngtcp2_crypto_generate_stateless_reset_token( - token, config.static_secret.data(), config.static_secret.size(), cid) != - 0) { + token->data, config.static_secret.data(), config.static_secret.size(), + cid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -524,9 +515,10 @@ int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, void *user_data) { auto c = static_cast(user_data); - if (c->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, - tx_iv, current_rx_secret, current_tx_secret, - secretlen) != 0) { + if (auto rv = + c->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, + tx_iv, current_rx_secret, current_tx_secret, secretlen); + !rv) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -567,7 +559,7 @@ int select_preferred_address(ngtcp2_conn *conn, ngtcp2_path *dest, return 0; } - if (c->select_preferred_address(remote_addr, paddr) != 0) { + if (auto rv = c->select_preferred_address(remote_addr, paddr); !rv) { return 0; } @@ -591,20 +583,21 @@ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, uint64_t max_data, void *user_data, void *stream_user_data) { auto c = static_cast(user_data); - if (c->extend_max_stream_data(stream_id, max_data) != 0) { + if (!c->extend_max_stream_data(stream_id, max_data)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Client::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { +std::expected Client::extend_max_stream_data(int64_t stream_id, + uint64_t max_data) { if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) { - std::cerr << "nghttp3_conn_unblock_stream: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_unblock_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - return 0; + return {}; } namespace { @@ -628,7 +621,7 @@ int recv_rx_key(ngtcp2_conn *conn, ngtcp2_encryption_level level, } auto c = static_cast(user_data); - if (c->setup_httpconn() != 0) { + if (!c->setup_httpconn()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -654,9 +647,10 @@ void Client::early_data_rejected() { streams_.clear(); } -int Client::init(int fd, const Address &local_addr, const Address &remote_addr, - const char *addr, const char *port, - TLSClientContext &tls_ctx) { +std::expected Client::init(int fd, const Address &local_addr, + const Address &remote_addr, + const char *addr, const char *port, + TLSClientContext &tls_ctx) { endpoints_.reserve(4); endpoints_.emplace_back(); @@ -685,7 +679,6 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, .recv_retry = ngtcp2_crypto_recv_retry_cb, .extend_max_local_streams_bidi = extend_max_local_streams_bidi, .rand = rand, - .get_new_connection_id = get_new_connection_id, .update_key = ::update_key, .path_validation = path_validation, .select_preferred_addr = ::select_preferred_address, @@ -695,11 +688,12 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, .recv_new_token = ::recv_new_token, .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, .stream_stop_sending = stream_stop_sending, .version_negotiation = ngtcp2_crypto_version_negotiation_cb, .recv_rx_key = ::recv_rx_key, .tls_early_data_rejected = ::early_data_rejected, + .get_new_connection_id2 = get_new_connection_id, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; ngtcp2_cid scid, dcid; @@ -707,16 +701,18 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, scid = config.scid; } else { scid.datalen = 17; - if (util::generate_secure_random({scid.data, scid.datalen}) != 0) { - std::cerr << "Could not generate source connection ID" << std::endl; - return -1; + if (auto rv = util::generate_secure_random({scid.data, scid.datalen}); + !rv) { + std::println(stderr, "Could not generate source connection ID"); + return rv; } } if (config.dcid.datalen == 0) { dcid.datalen = 18; - if (util::generate_secure_random({dcid.data, dcid.datalen}) != 0) { - std::cerr << "Could not generate destination connection ID" << std::endl; - return -1; + if (auto rv = util::generate_secure_random({dcid.data, dcid.datalen}); + !rv) { + std::println(stderr, "Could not generate destination connection ID"); + return rv; } } else { dcid = config.dcid; @@ -737,9 +733,9 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, } qlog_ = fopen(path.c_str(), "w"); if (qlog_ == nullptr) { - std::cerr << "Could not open qlog file " << std::quoted(path) << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "Could not open qlog file {}: {}", path, + strerror(errno)); + return std::unexpected{Error::IO}; } settings.qlog_write = qlog_write_cb; } @@ -766,7 +762,7 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, std::vector token; if (!config.token_file.empty()) { - std::cerr << "Reading token file " << config.token_file << std::endl; + std::println(stderr, "Reading token file {}", config.token_file); auto t = util::read_token(config.token_file); if (t) { @@ -821,13 +817,14 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, &callbacks, &settings, ¶ms, nullptr, this); if (rv != 0) { - std::cerr << "ngtcp2_conn_client_new: " << ngtcp2_strerror(rv) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_client_new: {}", ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - if (tls_session_.init(early_data_, tls_ctx, addr_, this, - client_chosen_version_, AppProtocol::H3) != 0) { - return -1; + if (auto rv = tls_session_.init(early_data_, tls_ctx, addr_, this, + client_chosen_version_, AppProtocol::H3); + !rv) { + return rv; } ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle()); @@ -840,11 +837,12 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, auto rv = ngtcp2_conn_decode_and_set_0rtt_transport_params( conn_, params->data(), params->size()); if (rv != 0) { - std::cerr << "ngtcp2_conn_decode_and_set_0rtt_transport_params: " - << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, + "ngtcp2_conn_decode_and_set_0rtt_transport_params: {}", + ngtcp2_strerror(rv)); early_data_ = false; - } else if (make_stream_early() != 0) { - return -1; + } else if (auto rv = make_stream_early(); !rv) { + return rv; } } } @@ -853,12 +851,12 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, ev_signal_start(loop_, &sigintev_); - return 0; + return {}; } -int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, - const ngtcp2_pkt_info *pi, - std::span data) { +std::expected +Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, + const ngtcp2_pkt_info *pi, std::span data) { auto path = ngtcp2_path{ .local = as_ngtcp2_addr(ep.addr), .remote{ @@ -870,29 +868,28 @@ int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(), util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); if (!last_error_.error_code) { if (rv == NGTCP2_ERR_CRYPTO) { auto alert = ngtcp2_conn_get_tls_alert(conn_); ngtcp2_ccerr_set_tls_alert(&last_error_, alert, nullptr, 0); if (alert == TLS_ALERT_ECH_REQUIRED && config.ech_config_list_file && - tls_session_.write_ech_config_list(config.ech_config_list_file) != - 0) { - std::cerr << "Could not write ECH retry configs in " - << config.ech_config_list_file << std::endl; + !tls_session_.write_ech_config_list(config.ech_config_list_file)) { + std::println(stderr, "Could not write ECH retry configs in {}", + config.ech_config_list_file); } } else { ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); } } disconnect(); - return -1; + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } -int Client::on_read(const Endpoint &ep) { +std::expected Client::on_read(const Endpoint &ep) { std::array buf; sockaddr_storage ss; size_t pktcnt = 0; @@ -927,7 +924,7 @@ int Client::on_read(const Endpoint &ep) { if (nread == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - std::cerr << "recvmsg: " << strerror(errno) << std::endl; + std::println(stderr, "recvmsg: {}", strerror(errno)); } break; } @@ -953,12 +950,12 @@ int Client::on_read(const Endpoint &ep) { ++pktcnt; if (!config.quiet) { - std::cerr << "Received packet: local=" << util::straddr(ep.addr) - << " remote=" - << util::straddr(reinterpret_cast(&ss), - msg.msg_namelen) - << " ecn=0x" << std::hex << static_cast(pi.ecn) - << std::dec << " " << datalen << " bytes" << std::endl; + std::println(stderr, + "Received packet: local={} remote={} ecn={:#x} {} bytes", + util::straddr(ep.addr), + util::straddr(reinterpret_cast(&ss), + msg.msg_namelen), + pi.ecn, datalen); } // Packets less than 21 bytes never be a valid QUIC packet. @@ -968,11 +965,13 @@ int Client::on_read(const Endpoint &ep) { if (debug::packet_lost(config.rx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated incoming packet loss **" << std::endl; + std::println(stderr, "** Simulated incoming packet loss **"); } - } else if (feed_data(ep, reinterpret_cast(&ss), - msg.msg_namelen, &pi, {data.data(), datalen}) != 0) { - return -1; + } else if (auto rv = + feed_data(ep, reinterpret_cast(&ss), + msg.msg_namelen, &pi, {data.data(), datalen}); + !rv) { + return rv; } data = data.subspan(datalen); @@ -987,41 +986,38 @@ int Client::on_read(const Endpoint &ep) { ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(0), nullptr, 0); disconnect(); - return -1; + return std::unexpected{Error::INTERNAL}; } update_timer(); - return 0; + return {}; } -int Client::handle_expiry() { +std::expected Client::handle_expiry() { auto now = util::timestamp(); if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) { - std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_handle_expiry: {}", ngtcp2_strerror(rv)); ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); disconnect(); - return -1; + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } -int Client::on_write() { +std::expected Client::on_write() { if (tx_.send_blocked) { - if (auto rv = send_blocked_packet(); rv != 0) { - return rv; - } + send_blocked_packet(); if (tx_.send_blocked) { - return 0; + return {}; } } ev_io_stop(loop_, &wev_); - if (auto rv = write_streams(); rv != 0) { + if (auto rv = write_streams(); !rv) { return rv; } @@ -1029,11 +1025,11 @@ int Client::on_write() { ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(0), nullptr, 0); disconnect(); - return -1; + return std::unexpected{Error::INTERNAL}; } update_timer(); - return 0; + return {}; } namespace { @@ -1060,8 +1056,8 @@ ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin, vec.data(), vec.size()); if (sveccnt < 0) { - std::cerr << "nghttp3_conn_writev_stream: " - << nghttp3_strerror(static_cast(sveccnt)) << std::endl; + std::println(stderr, "nghttp3_conn_writev_stream: {}", + nghttp3_strerror(static_cast(sveccnt))); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(static_cast(sveccnt)), @@ -1097,8 +1093,8 @@ ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, as_unsigned(ndatalen)); rv != 0) { - std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv) - << std::endl; + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); @@ -1109,8 +1105,8 @@ ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, assert(ndatalen == -1); - std::cerr << "ngtcp2_conn_write_stream: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, 0); @@ -1121,8 +1117,8 @@ ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, as_unsigned(ndatalen)); rv != 0) { - std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv) - << std::endl; + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); @@ -1134,7 +1130,7 @@ ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, } } -int Client::write_streams() { +std::expected Client::write_streams() { ngtcp2_path_storage ps; ngtcp2_pkt_info pi; size_t gso_size; @@ -1149,36 +1145,34 @@ int Client::write_streams() { config.gso_burst, ts); if (nwrite < 0) { disconnect(); - return -1; + return std::unexpected{Error::QUIC}; } ngtcp2_conn_update_pkt_tx_time(conn_, ts); if (nwrite == 0) { - return 0; + return {}; } send_packet_or_blocked(ps.path, pi.ecn, txbuf.first(static_cast(nwrite)), gso_size); - return 0; + return {}; } -int Client::send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, - size_t gso_size) { +std::expected +Client::send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, + std::span data, size_t gso_size) { auto &ep = *static_cast(path.user_data); - auto [rest, rv] = send_packet(ep, path.remote, ecn, data, gso_size); - if (rv != 0) { - assert(NETWORK_ERR_SEND_BLOCKED == rv); - + auto rest = send_packet(ep, path.remote, ecn, data, gso_size); + if (!rest.empty()) { on_send_blocked(path, ecn, rest, gso_size); - return rv; + return std::unexpected{Error::SEND_BLOCKED}; } - return 0; + return {}; } void Client::update_timer() { @@ -1188,8 +1182,7 @@ void Client::update_timer() { if (expiry <= now) { if (!config.quiet) { auto t = static_cast(now - expiry) / NGTCP2_SECONDS; - std::cerr << "Timer has already expired: " << std::fixed << t << "s" - << std::defaultfloat << std::endl; + std::println(stderr, "Timer has already expired: {:.9f}s", t); } ev_feed_event(loop_, &timer_, EV_TIMER); @@ -1199,8 +1192,7 @@ void Client::update_timer() { auto t = static_cast(expiry - now) / NGTCP2_SECONDS; if (!config.quiet) { - std::cerr << "Set timer=" << std::fixed << t << "s" << std::defaultfloat - << std::endl; + std::println(stderr, "Set timer={:.9f}s", t); } timer_.repeat = t; ev_timer_again(loop_, &timer_); @@ -1208,7 +1200,8 @@ void Client::update_timer() { #ifdef HAVE_LINUX_RTNETLINK_H namespace { -int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) { +std::expected bind_addr(Address &local_addr, int fd, + const InAddr &ia, int family) { addrinfo hints{ .ai_flags = AI_PASSIVE, .ai_family = family, @@ -1223,16 +1216,16 @@ int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) { } 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; + std::println(stderr, "inet_ntop: {}", strerror(errno)); + return std::unexpected{Error::LIBC}; } node = nodebuf.data(); } if (auto rv = getaddrinfo(node, "0", &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } auto res_d = defer([res] { freeaddrinfo(res); }); @@ -1244,53 +1237,56 @@ int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) { } if (!rp) { - std::cerr << "Could not bind" << std::endl; - return -1; + std::println(stderr, "Could not bind"); + return std::unexpected{Error::SYSCALL}; } sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::cerr << "getsockname: " << strerror(errno) << std::endl; - return -1; + std::println(stderr, "getsockname: {}", strerror(errno)); + return std::unexpected{Error::SYSCALL}; } local_addr.set(reinterpret_cast(&ss)); - return 0; + return {}; } } // namespace #endif // defined(HAVE_LINUX_RTNETLINK_H) #ifndef HAVE_LINUX_RTNETLINK_H namespace { -int connect_sock(Address &local_addr, int fd, const Address &remote_addr) { +std::expected connect_sock(Address &local_addr, int fd, + const Address &remote_addr) { if (connect(fd, remote_addr.as_sockaddr(), remote_addr.size()) != 0) { - std::cerr << "connect: " << strerror(errno) << std::endl; - return -1; + std::println(stderr, "connect: {}", strerror(errno)); + return std::unexpected{Error::SYSCALL}; } sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::cerr << "getsockname: " << strerror(errno) << std::endl; - return -1; + std::println(stderr, "getsockname: {}", strerror(errno)); + return std::unexpected{Error::SYSCALL}; } local_addr.set(reinterpret_cast(&ss)); - return 0; + return {}; } } // namespace #endif // !defined(HAVE_LINUX_RTNETLINK_H) namespace { -int udp_sock(int family) { - auto fd = util::create_nonblock_socket(family, SOCK_DGRAM, IPPROTO_UDP); - if (fd == -1) { - return -1; +std::expected udp_sock(int family) { + auto maybe_fd = util::create_nonblock_socket(family, SOCK_DGRAM, IPPROTO_UDP); + if (!maybe_fd) { + return maybe_fd; } + auto fd = *maybe_fd; + fd_set_recv_ecn(fd, family); fd_set_ip_mtu_discover(fd, family); fd_set_ip_dontfrag(fd, family); @@ -1301,7 +1297,8 @@ int udp_sock(int family) { } // namespace namespace { -int create_sock(Address &remote_addr, const char *addr, const char *port) { +std::expected create_sock(Address &remote_addr, const char *addr, + const char *port) { addrinfo hints{ .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, @@ -1309,8 +1306,8 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) { addrinfo *res, *rp; if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } auto res_d = defer([res] { freeaddrinfo(res); }); @@ -1318,17 +1315,19 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) { int fd = -1; for (rp = res; rp; rp = rp->ai_next) { - fd = udp_sock(rp->ai_family); - if (fd == -1) { + auto maybe_fd = udp_sock(rp->ai_family); + if (!maybe_fd) { continue; } + fd = *maybe_fd; + break; } if (!rp) { - std::cerr << "Could not create socket" << std::endl; - return -1; + std::println(stderr, "Could not create socket"); + return std::unexpected{Error::SYSCALL}; } remote_addr.set(rp->ai_addr); @@ -1337,16 +1336,18 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) { } } // namespace -std::optional Client::endpoint_for(const Address &remote_addr) { +std::expected +Client::endpoint_for(const Address &remote_addr) { #ifdef HAVE_LINUX_RTNETLINK_H - InAddr ia; - - if (get_local_addr(ia, remote_addr) != 0) { - std::cerr << "Could not get local address for a selected preferred address" - << std::endl; - return nullptr; + auto maybe_ia = get_local_addr(remote_addr); + if (!maybe_ia) { + std::println( + stderr, "Could not get local address for a selected preferred address"); + return std::unexpected{maybe_ia.error()}; } + const auto &ia = *maybe_ia; + auto current_path = ngtcp2_conn_get_path(conn_); auto current_ep = static_cast(current_path->user_data); if (addreq(current_ep->addr, ia)) { @@ -1356,22 +1357,24 @@ std::optional Client::endpoint_for(const Address &remote_addr) { auto family = remote_addr.family(); - auto fd = udp_sock(family); - if (fd == -1) { - return nullptr; + auto maybe_fd = udp_sock(family); + if (!maybe_fd) { + return std::unexpected{maybe_fd.error()}; } + auto fd = *maybe_fd; + Address local_addr; #ifdef HAVE_LINUX_RTNETLINK_H - if (bind_addr(local_addr, fd, ia, family) != 0) { + if (auto rv = bind_addr(local_addr, fd, ia, family); !rv) { close(fd); - return nullptr; + return std::unexpected{rv.error()}; } #else // !defined(HAVE_LINUX_RTNETLINK_H) - if (connect_sock(local_addr, fd, remote_addr) != 0) { + if (auto rv = connect_sock(local_addr, fd, remote_addr); !rv) { close(fd); - return nullptr; + return std::unexpected{rv.error()}; } #endif // !defined(HAVE_LINUX_RTNETLINK_H) @@ -1392,43 +1395,43 @@ void Client::start_change_local_addr_timer() { ev_timer_start(loop_, &change_local_addr_timer_); } -int Client::change_local_addr() { +std::expected Client::change_local_addr() { Address local_addr; if (!config.quiet) { - std::cerr << "Changing local address" << std::endl; + std::println(stderr, "Changing local address"); } auto family = remote_addr_.family(); - auto nfd = udp_sock(family); - if (nfd == -1) { - return -1; + auto maybe_nfd = udp_sock(family); + if (!maybe_nfd) { + return std::unexpected{maybe_nfd.error()}; } -#ifdef HAVE_LINUX_RTNETLINK_H - InAddr ia; + auto nfd = *maybe_nfd; - if (get_local_addr(ia, remote_addr_) != 0) { - std::cerr << "Could not get local address" << std::endl; +#ifdef HAVE_LINUX_RTNETLINK_H + auto maybe_ia = get_local_addr(remote_addr_); + if (!maybe_ia) { + std::println(stderr, "Could not get local address"); close(nfd); - return -1; + return std::unexpected{maybe_ia.error()}; } - if (bind_addr(local_addr, nfd, ia, family) != 0) { + if (auto rv = bind_addr(local_addr, nfd, *maybe_ia, family); !rv) { close(nfd); - return -1; + return rv; } #else // !defined(HAVE_LINUX_RTNETLINK_H) - if (connect_sock(local_addr, nfd, remote_addr_) != 0) { + if (auto rv = connect_sock(local_addr, nfd, remote_addr_); !rv) { close(nfd); - return -1; + return rv; } #endif // !defined(HAVE_LINUX_RTNETLINK_H) if (!config.quiet) { - std::cerr << "Local address is now " << util::straddr(local_addr) - << std::endl; + std::println(stderr, "Local address is now {}", util::straddr(local_addr)); } endpoints_.emplace_back(); @@ -1453,27 +1456,28 @@ int Client::change_local_addr() { if (auto rv = ngtcp2_conn_initiate_immediate_migration(conn_, &path, util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_initiate_immediate_migration: " - << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, "ngtcp2_conn_initiate_immediate_migration: {}", + ngtcp2_strerror(rv)); } } ev_io_start(loop_, &ep.rev); - return 0; + return {}; } void Client::start_key_update_timer() { ev_timer_start(loop_, &key_update_timer_); } -int Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen) { +std::expected +Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, + const uint8_t *current_tx_secret, size_t secretlen) { if (!config.quiet) { - std::cerr << "Updating traffic key" << std::endl; + std::println(stderr, "Updating traffic key"); } auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); @@ -1489,73 +1493,81 @@ int Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), tx_iv, current_rx_secret, current_tx_secret, secretlen) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } if (!config.quiet && config.show_secret) { - std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic rx secret {}", nkey_update_); debug::print_secrets({rx_secret, secretlen}, {rx_key.data(), keylen}, {rx_iv, ivlen}); - std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic tx secret {}", nkey_update_); debug::print_secrets({tx_secret, secretlen}, {tx_key.data(), keylen}, {tx_iv, ivlen}); } - return 0; + return {}; } -int Client::initiate_key_update() { +std::expected Client::initiate_key_update() { if (!config.quiet) { - std::cerr << "Initiate key update" << std::endl; + std::println(stderr, "Initiate key update"); } if (auto rv = ngtcp2_conn_initiate_key_update(conn_, util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_initiate_key_update: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_initiate_key_update: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } void Client::start_delay_stream_timer() { ev_timer_start(loop_, &delay_stream_timer_); } -int Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, - unsigned int ecn, std::span data) { - auto [_, rv] = send_packet(ep, remote_addr, ecn, data, data.size()); +std::expected Client::send_packet(const Endpoint &ep, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data) { + auto rest = send_packet(ep, remote_addr, ecn, data, data.size()); + if (!rest.empty()) { + return std::unexpected{Error::SEND_BLOCKED}; + } - return rv; + return {}; } -std::pair, int> -Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, - unsigned int ecn, std::span data, - size_t gso_size) { +std::span Client::send_packet(const Endpoint &ep, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data, + size_t gso_size) { assert(gso_size); if (debug::packet_lost(config.tx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated outgoing packet loss **" << std::endl; + std::println(stderr, "** Simulated outgoing packet loss **"); } - return {{}, NETWORK_ERR_OK}; + return {}; } if (no_gso_ && data.size() > gso_size) { for (; !data.empty();) { auto len = std::min(gso_size, data.size()); - auto [_, rv] = send_packet(ep, remote_addr, ecn, data.first(len), len); - if (rv != 0) { - return {data, rv}; + auto rest = send_packet(ep, remote_addr, ecn, data.first(len), len); + if (!rest.empty()) { + assert(rest.size() == len); + + return data; } data = data.subspan(len); } - return {{}, 0}; + return {}; } iovec msg_iov{ @@ -1630,13 +1642,13 @@ Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, #if EAGAIN != EWOULDBLOCK case EWOULDBLOCK: #endif // EAGAIN != EWOULDBLOCK - return {data, NETWORK_ERR_SEND_BLOCKED}; + return data; #ifdef UDP_SEGMENT case EIO: if (data.size() > gso_size) { // GSO failure; send each packet in a separate sendmsg call. - std::cerr << "sendmsg: disabling GSO due to " << strerror(errno) - << std::endl; + std::println(stderr, "sendmsg: disabling GSO due to {}", + strerror(errno)); no_gso_ = true; @@ -1646,23 +1658,23 @@ Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, #endif // defined(UDP_SEGMENT) } - std::cerr << "sendmsg: " << strerror(errno) << std::endl; + std::println(stderr, "sendmsg: {}", strerror(errno)); // TODO We have packet which is expected to fail to send (e.g., // path validation to old path). - return {{}, NETWORK_ERR_OK}; + return {}; } assert(static_cast(nwrite) == data.size()); if (!config.quiet) { - 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; + std::println(stderr, "Sent packet: local={} remote={} ecn={:#x} {} bytes", + util::straddr(ep.addr), + util::straddr(remote_addr.addr, remote_addr.addrlen), ecn, + nwrite); } - return {{}, NETWORK_ERR_OK}; + return {}; } void Client::on_send_blocked(const ngtcp2_path &path, unsigned int ecn, @@ -1700,32 +1712,28 @@ void Client::start_wev_endpoint(const Endpoint &ep) { ev_io_start(loop_, &wev_); } -int Client::send_blocked_packet() { +void Client::send_blocked_packet() { assert(tx_.send_blocked); auto &p = tx_.blocked; - 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); - + auto rest = send_packet(*p.endpoint, as_ngtcp2_addr(p.remote_addr), p.ecn, + p.data, p.gso_size); + if (!rest.empty()) { p.data = rest; start_wev_endpoint(*p.endpoint); - return 0; + return; } tx_.send_blocked = false; - - return 0; } -int Client::handle_error() { +std::expected Client::handle_error() { if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || ngtcp2_conn_in_draining_period(conn_)) { - return 0; + return {}; } std::array buf; @@ -1740,13 +1748,13 @@ int Client::handle_error() { conn_, &ps.path, &pi, buf.data(), buf.size(), &last_error_, util::timestamp()); if (nwrite < 0) { - std::cerr << "ngtcp2_conn_write_connection_close: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_write_connection_close: {}", + ngtcp2_strerror(static_cast(nwrite))); + return std::unexpected{Error::QUIC}; } if (nwrite == 0) { - return 0; + return {}; } return send_packet(*static_cast(ps.path.user_data), @@ -1754,7 +1762,8 @@ int Client::handle_error() { {buf.data(), static_cast(nwrite)}); } -int Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) { +std::expected Client::on_stream_close(int64_t stream_id, + uint64_t app_error_code) { if (httpconn_) { if (app_error_code == 0) { app_error_code = NGHTTP3_H3_NO_ERROR; @@ -1774,58 +1783,60 @@ int Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) { } break; default: - std::cerr << "nghttp3_conn_close_stream: " << nghttp3_strerror(rv) - << std::endl; + std::println(stderr, "nghttp3_conn_close_stream: {}", + nghttp3_strerror(rv)); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); - return -1; + return std::unexpected{Error::HTTP3}; } } - return 0; + return {}; } -int Client::on_stream_reset(int64_t stream_id) { +std::expected Client::on_stream_reset(int64_t stream_id) { if (httpconn_) { if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); rv != 0) { - std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } } - return 0; + return {}; } -int Client::on_stream_stop_sending(int64_t stream_id) { +std::expected Client::on_stream_stop_sending(int64_t stream_id) { if (!httpconn_) { - return 0; + return {}; } if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); rv != 0) { - std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - return 0; + return {}; } -int Client::make_stream_early() { - if (setup_httpconn() != 0) { - return -1; +std::expected Client::make_stream_early() { + if (auto rv = setup_httpconn(); !rv) { + return rv; } - return on_extend_max_streams(); + on_extend_max_streams(); + + return {}; } -int Client::on_extend_max_streams() { +void Client::on_extend_max_streams() { int64_t stream_id; if ((config.delay_stream && !handshake_confirmed_) || ev_is_active(&delay_stream_timer_)) { - return 0; + return; } for (; nstreams_done_ < config.nstreams; ++nstreams_done_) { @@ -1838,7 +1849,7 @@ int Client::on_extend_max_streams() { auto stream = std::make_unique( config.requests[nstreams_done_ % config.requests.size()], stream_id); - if (submit_http_request(stream.get()) != 0) { + if (!submit_http_request(stream.get())) { break; } @@ -1847,7 +1858,6 @@ int Client::on_extend_max_streams() { } streams_.emplace(stream_id, std::move(stream)); } - return 0; } namespace { @@ -1862,7 +1872,7 @@ nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec, } } // namespace -int Client::submit_http_request(const Stream *stream) { +std::expected Client::submit_http_request(const Stream *stream) { std::string content_length_str; const auto &req = stream->req; @@ -1892,66 +1902,69 @@ int Client::submit_http_request(const Stream *stream) { httpconn_, stream->stream_id, nva.data(), nvlen, config.fd == -1 ? nullptr : &dr, nullptr); rv != 0) { - std::cerr << "nghttp3_conn_submit_request: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_submit_request: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - return 0; + return {}; } -int Client::recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data) { +std::expected +Client::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { 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_stream2: " - << nghttp3_strerror(static_cast(nconsumed)) << std::endl; + std::println(stderr, "nghttp3_conn_read_stream2: {}", + nghttp3_strerror(static_cast(nconsumed))); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(static_cast(nconsumed)), nullptr, 0); - return -1; + return std::unexpected{Error::HTTP3}; } ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, static_cast(nconsumed)); ngtcp2_conn_extend_max_offset(conn_, static_cast(nconsumed)); - return 0; + return {}; } -int Client::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) { +std::expected Client::acked_stream_data_offset(int64_t stream_id, + uint64_t datalen) { if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen); rv != 0) { - std::cerr << "nghttp3_conn_add_ack_offset: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_add_ack_offset: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - return 0; + return {}; } -int Client::select_preferred_address(Address &selected_addr, - const ngtcp2_preferred_addr *paddr) { +std::expected +Client::select_preferred_address(Address &selected_addr, + const ngtcp2_preferred_addr *paddr) { auto path = ngtcp2_conn_get_path(conn_); switch (path->local.addr->sa_family) { case AF_INET: if (!paddr->ipv4_present) { - return -1; + return std::unexpected{Error::INTERNAL}; } selected_addr.skaddr.emplace(paddr->ipv4); break; case AF_INET6: if (!paddr->ipv6_present) { - return -1; + return std::unexpected{Error::INTERNAL}; } selected_addr.skaddr.emplace(paddr->ipv6); break; default: - return -1; + return std::unexpected{Error::INTERNAL}; } if (!config.quiet) { @@ -1960,15 +1973,15 @@ int Client::select_preferred_address(Address &selected_addr, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } - std::cerr << "selected server preferred_address is [" << host - << "]:" << service << std::endl; + std::println(stderr, "selected server preferred_address is [{}]:{}", host, + service); } - return 0; + return {}; } namespace { @@ -2012,9 +2025,20 @@ void Client::http_write_data(int64_t stream_id, std::span data) { } ssize_t nwrite; - do { - nwrite = write(stream->fd, data.data(), data.size()); - } while (nwrite == -1 && errno == EINTR); + + for (; !data.empty();) { + do { + nwrite = write(stream->fd, data.data(), data.size()); + } while (nwrite == -1 && errno == EINTR); + + if (nwrite < 0) { + std::println(stderr, "Could not write data to file: {}", strerror(errno)); + + return; + } + + data = data.subspan(static_cast(nwrite)); + } } namespace { @@ -2084,22 +2108,23 @@ int http_stop_sending(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { auto c = static_cast(user_data); - if (c->stop_sending(stream_id, app_error_code) != 0) { + if (!c->stop_sending(stream_id, app_error_code)) { return NGHTTP3_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Client::stop_sending(int64_t stream_id, uint64_t app_error_code) { +std::expected Client::stop_sending(int64_t stream_id, + uint64_t app_error_code) { if (auto rv = ngtcp2_conn_shutdown_stream_read(conn_, 0, stream_id, app_error_code); rv != 0) { - std::cerr << "ngtcp2_conn_shutdown_stream_read: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_shutdown_stream_read: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } namespace { @@ -2107,22 +2132,23 @@ int http_reset_stream(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { auto c = static_cast(user_data); - if (c->reset_stream(stream_id, app_error_code) != 0) { + if (!c->reset_stream(stream_id, app_error_code)) { return NGHTTP3_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Client::reset_stream(int64_t stream_id, uint64_t app_error_code) { +std::expected Client::reset_stream(int64_t stream_id, + uint64_t app_error_code) { if (auto rv = ngtcp2_conn_shutdown_stream_write(conn_, 0, stream_id, app_error_code); rv != 0) { - std::cerr << "ngtcp2_conn_shutdown_stream_write: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_shutdown_stream_write: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } void Client::http_stream_close(int64_t stream_id, uint64_t app_error_code) { @@ -2140,8 +2166,8 @@ void Client::http_stream_close(int64_t stream_id, uint64_t app_error_code) { } if (!config.quiet) { - std::cerr << "HTTP stream " << stream_id << " closed with error code " - << app_error_code << std::endl; + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); } streams_.erase(it); @@ -2180,15 +2206,15 @@ int http_end_origin(nghttp3_conn *conn, void *conn_user_data) { } } // namespace -int Client::setup_httpconn() { +std::expected Client::setup_httpconn() { if (httpconn_) { - return 0; + return {}; } if (ngtcp2_conn_get_streams_uni_left(conn_) < 3) { - std::cerr << "peer does not allow at least 3 unidirectional streams." - << std::endl; - return -1; + std::println(stderr, + "peer does not allow at least 3 unidirectional streams."); + return std::unexpected{Error::QUIC}; } nghttp3_callbacks callbacks{ @@ -2217,29 +2243,28 @@ int Client::setup_httpconn() { if (auto rv = nghttp3_conn_client_new(&httpconn_, &callbacks, &settings, mem, this); rv != 0) { - std::cerr << "nghttp3_conn_client_new: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_client_new: {}", nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } int64_t ctrl_stream_id; if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr); rv != 0) { - std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id); rv != 0) { - std::cerr << "nghttp3_conn_bind_control_stream: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_bind_control_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } if (!config.quiet) { - fprintf(stderr, "http: control stream=%" PRIx64 "\n", ctrl_stream_id); + std::println(stderr, "http: control stream={:#x}", ctrl_stream_id); } int64_t qpack_enc_stream_id, qpack_dec_stream_id; @@ -2247,34 +2272,33 @@ int Client::setup_httpconn() { if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr); rv != 0) { - std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr); rv != 0) { - std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id, qpack_dec_stream_id); rv != 0) { - std::cerr << "nghttp3_conn_bind_qpack_streams: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_bind_qpack_streams: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } if (!config.quiet) { - fprintf(stderr, - "http: QPACK streams encoder=%" PRIx64 " decoder=%" PRIx64 "\n", - qpack_enc_stream_id, qpack_dec_stream_id); + std::println(stderr, "http: QPACK streams encoder={:#x} decoder={:#x}", + qpack_enc_stream_id, qpack_dec_stream_id); } - return 0; + return {}; } const std::vector &Client::get_offered_versions() const { @@ -2284,64 +2308,68 @@ const std::vector &Client::get_offered_versions() const { bool Client::get_early_data() const { return early_data_; } namespace { -int run(Client &c, const char *addr, const char *port, - TLSClientContext &tls_ctx) { +std::expected run(Client &c, const char *addr, const char *port, + TLSClientContext &tls_ctx) { Address remote_addr, local_addr; - auto fd = create_sock(remote_addr, addr, port); - if (fd == -1) { - return -1; + auto maybe_fd = create_sock(remote_addr, addr, port); + if (!maybe_fd) { + return std::unexpected{maybe_fd.error()}; } -#ifdef HAVE_LINUX_RTNETLINK_H - InAddr ia; + auto fd = *maybe_fd; - if (get_local_addr(ia, remote_addr) != 0) { - std::cerr << "Could not get local address" << std::endl; +#ifdef HAVE_LINUX_RTNETLINK_H + auto maybe_ia = get_local_addr(remote_addr); + if (!maybe_ia) { + std::println(stderr, "Could not get local address"); close(fd); - return -1; + return std::unexpected{maybe_ia.error()}; } - if (bind_addr(local_addr, fd, ia, remote_addr.family()) != 0) { + if (auto rv = bind_addr(local_addr, fd, *maybe_ia, remote_addr.family()); + !rv) { close(fd); - return -1; + return rv; } #else // !defined(HAVE_LINUX_RTNETLINK_H) - if (connect_sock(local_addr, fd, remote_addr) != 0) { + if (auto rv = connect_sock(local_addr, fd, remote_addr); !rv) { close(fd); - return -1; + return rv; } #endif // !defined(HAVE_LINUX_RTNETLINK_H) - if (c.init(fd, local_addr, remote_addr, addr, port, tls_ctx) != 0) { - return -1; + if (auto rv = c.init(fd, local_addr, remote_addr, addr, port, tls_ctx); !rv) { + return rv; } // TODO Do we need this ? - if (auto rv = c.on_write(); rv != 0) { + if (auto rv = c.on_write(); !rv) { return rv; } ev_run(EV_DEFAULT, 0); - return 0; + return {}; } } // namespace namespace { -int parse_uri(Request &req, const std::string_view &uri) { +std::expected parse_uri(std::string_view uri) { urlparse_url u; if (urlparse_parse_url(uri.data(), uri.size(), /* is_connect = */ 0, &u) != 0) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } if (!(u.field_set & (1 << URLPARSE_SCHEMA)) || !(u.field_set & (1 << URLPARSE_HOST))) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } + Request req; + req.scheme = util::get_string(uri, u, URLPARSE_SCHEMA); auto host = std::string(util::get_string(uri, u, URLPARSE_HOST)); @@ -2369,22 +2397,22 @@ int parse_uri(Request &req, const std::string_view &uri) { req.path += util::get_string(uri, u, URLPARSE_QUERY); } - return 0; + return req; } } // namespace namespace { -int parse_requests(char **argv, size_t argvlen) { +std::expected parse_requests(char **argv, size_t argvlen) { for (size_t i = 0; i < argvlen; ++i) { auto uri = std::string_view{argv[i]}; - Request req; - if (parse_uri(req, uri) != 0) { - std::cerr << "Could not parse URI: " << uri << std::endl; - return -1; + auto maybe_req = parse_uri(uri); + if (!maybe_req) { + std::println(stderr, "Could not parse URI: {}", uri); + return std::unexpected{maybe_req.error()}; } - config.requests.emplace_back(std::move(req)); + config.requests.emplace_back(std::move(*maybe_req)); } - return 0; + return {}; } } // namespace @@ -2395,15 +2423,14 @@ const char *prog = "client"; } // namespace namespace { -void print_usage() { - std::cerr << "Usage: " << prog << " [OPTIONS] [...]" - << std::endl; +void print_usage(FILE *out) { + std::println(out, "Usage: {} [OPTIONS] [...]", prog); } } // namespace namespace { void print_help() { - print_usage(); + print_usage(stdout); Config config; @@ -2738,11 +2765,10 @@ int main(int argc, char **argv) { case 'n': // --streams if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "streams: invalid argument" << std::endl; + std::println(stderr, "streams: invalid argument"); exit(EXIT_FAILURE); } else if (*n > NGTCP2_MAX_VARINT) { - std::cerr << "streams: must not exceed " << NGTCP2_MAX_VARINT - << std::endl; + std::println(stderr, "streams: must not exceed {}", NGTCP2_MAX_VARINT); exit(EXIT_FAILURE); } else { config.nstreams = *n; @@ -2776,22 +2802,21 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(optarg); if (!rv) { - std::cerr << "version: invalid version " << std::quoted(optarg) - << std::endl; + std::println(stderr, "version: invalid version {}", optarg); exit(EXIT_FAILURE); } config.version = *rv; break; } case '?': - print_usage(); + print_usage(stderr); exit(EXIT_FAILURE); case 0: switch (flag) { case 1: // --ciphers if (util::crypto_default_ciphers()[0] == '\0') { - std::cerr << "ciphers: not supported" << std::endl; + std::println(stderr, "ciphers: not supported"); exit(EXIT_FAILURE); } config.ciphers = optarg; @@ -2803,7 +2828,7 @@ int main(int argc, char **argv) { case 3: // --timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "timeout: invalid argument" << std::endl; + std::println(stderr, "timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.timeout = *t; @@ -2822,12 +2847,12 @@ int main(int argc, char **argv) { auto hexcid = std::string_view{optarg}; if (hexcid.size() < NGTCP2_MIN_INITIAL_DCIDLEN * 2 || hexcid.size() > NGTCP2_MAX_CIDLEN * 2) { - std::cerr << "dcid: wrong length" << std::endl; + std::println(stderr, "dcid: wrong length"); exit(EXIT_FAILURE); } if (!util::is_hex_string(hexcid)) { - std::cerr << "dcid: not hex string" << std::endl; + std::println(stderr, "dcid: not hex string"); exit(EXIT_FAILURE); } @@ -2840,7 +2865,7 @@ int main(int argc, char **argv) { case 7: // --change-local-addr if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "change-local-addr: invalid argument" << std::endl; + std::println(stderr, "change-local-addr: invalid argument"); exit(EXIT_FAILURE); } else { config.change_local_addr = *t; @@ -2849,7 +2874,7 @@ int main(int argc, char **argv) { case 8: // --key-update if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "key-update: invalid argument" << std::endl; + std::println(stderr, "key-update: invalid argument"); exit(EXIT_FAILURE); } else { config.key_update = *t; @@ -2862,7 +2887,7 @@ int main(int argc, char **argv) { case 10: // --delay-stream if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "delay-stream: invalid argument" << std::endl; + std::println(stderr, "delay-stream: invalid argument"); exit(EXIT_FAILURE); } else { config.delay_stream = *t; @@ -2899,7 +2924,7 @@ int main(int argc, char **argv) { case 18: // --max-data if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-data: invalid argument" << std::endl; + std::println(stderr, "max-data: invalid argument"); exit(EXIT_FAILURE); } else { config.max_data = *n; @@ -2908,8 +2933,7 @@ int main(int argc, char **argv) { case 19: // --max-stream-data-bidi-local if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-local: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-local: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_local = *n; @@ -2918,8 +2942,7 @@ int main(int argc, char **argv) { case 20: // --max-stream-data-bidi-remote if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-remote: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-remote: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_remote = *n; @@ -2928,7 +2951,7 @@ int main(int argc, char **argv) { case 21: // --max-stream-data-uni if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-uni: invalid argument" << std::endl; + std::println(stderr, "max-stream-data-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_uni = *n; @@ -2937,7 +2960,7 @@ int main(int argc, char **argv) { case 22: // --max-streams-bidi if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-bidi: invalid argument" << std::endl; + std::println(stderr, "max-streams-bidi: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_bidi = *n; @@ -2946,7 +2969,7 @@ int main(int argc, char **argv) { case 23: // --max-streams-uni if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-uni: invalid argument" << std::endl; + std::println(stderr, "max-streams-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_uni = *n; @@ -2978,7 +3001,7 @@ int main(int argc, char **argv) { config.cc_algo = NGTCP2_CC_ALGO_BBR; break; } - std::cerr << "cc: specify cubic, reno, or bbr" << std::endl; + std::println(stderr, "cc: specify cubic, reno, or bbr"); exit(EXIT_FAILURE); case 28: // --exit-on-all-streams-close @@ -2995,7 +3018,7 @@ int main(int argc, char **argv) { case 31: // --initial-rtt if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "initial-rtt: invalid argument" << std::endl; + std::println(stderr, "initial-rtt: invalid argument"); exit(EXIT_FAILURE); } else { config.initial_rtt = *t; @@ -3004,7 +3027,7 @@ int main(int argc, char **argv) { case 32: // --max-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-window: invalid argument" << std::endl; + std::println(stderr, "max-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_window = *n; @@ -3013,7 +3036,7 @@ int main(int argc, char **argv) { case 33: // --max-stream-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-window: invalid argument" << std::endl; + std::println(stderr, "max-stream-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_window = *n; @@ -3023,12 +3046,12 @@ int main(int argc, char **argv) { // --scid auto hexcid = std::string_view{optarg}; if (hexcid.size() > NGTCP2_MAX_CIDLEN * 2) { - std::cerr << "scid: wrong length" << std::endl; + std::println(stderr, "scid: wrong length"); exit(EXIT_FAILURE); } if (!util::is_hex_string(hexcid)) { - std::cerr << "scid: not hex string" << std::endl; + std::println(stderr, "scid: not hex string"); exit(EXIT_FAILURE); } @@ -3042,14 +3065,14 @@ int main(int argc, char **argv) { case 35: // --max-udp-payload-size if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-udp-payload-size: invalid argument" << std::endl; + std::println(stderr, "max-udp-payload-size: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println(stderr, "max-udp-payload-size: must not exceed {}", + NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else if (*n == 0) { - std::cerr << "max-udp-payload-size: must not be 0" << std::endl; + std::println(stderr, "max-udp-payload-size: must not be 0"); } else { config.max_udp_payload_size = *n; } @@ -3057,7 +3080,7 @@ int main(int argc, char **argv) { case 36: // --handshake-timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "handshake-timeout: invalid argument" << std::endl; + std::println(stderr, "handshake-timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.handshake_timeout = *t; @@ -3083,8 +3106,7 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "available-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "available-versions: invalid version {}", k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -3099,8 +3121,9 @@ int main(int argc, char **argv) { // --preferred-versions auto l = util::split_str(optarg); if (l.size() > max_preferred_versionslen) { - std::cerr << "preferred-versions: too many versions > " - << max_preferred_versionslen << std::endl; + std::println(stderr, "preferred-versions: too many versions > {}", + max_preferred_versionslen); + exit(EXIT_FAILURE); } config.preferred_versions.resize(l.size()); auto it = std::ranges::begin(config.preferred_versions); @@ -3115,13 +3138,12 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "preferred-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: invalid version {}", k); exit(EXIT_FAILURE); } if (!ngtcp2_is_supported_version(*rv)) { - std::cerr << "preferred-versions: unsupported version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: unsupported version {}", + k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -3131,10 +3153,10 @@ int main(int argc, char **argv) { case 40: // --ack-thresh if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "ack-thresh: invalid argument" << std::endl; + std::println(stderr, "ack-thresh: invalid argument"); exit(EXIT_FAILURE); } else if (*n > 100) { - std::cerr << "ack-thresh: must not exceed 100" << std::endl; + std::println(stderr, "ack-thresh: must not exceed 100"); exit(EXIT_FAILURE); } else { config.ack_thresh = *n; @@ -3147,11 +3169,11 @@ int main(int argc, char **argv) { case 42: // --initial-pkt-num if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "initial-pkt-num: invalid argument" << std::endl; + std::println(stderr, "initial-pkt-num: invalid argument"); exit(EXIT_FAILURE); } else if (*n > INT32_MAX) { - std::cerr << "initial-pkt-num: must not exceed (1 << 31) - 1" - << std::endl; + std::println(stderr, + "initial-pkt-num: must not exceed (1 << 31) - 1"); exit(EXIT_FAILURE); } else { config.initial_pkt_num = static_cast(*n); @@ -3162,14 +3184,13 @@ int main(int argc, char **argv) { auto l = util::split_str(optarg); for (auto &s : l) { if (auto n = util::parse_uint_iec(s); !n) { - std::cerr << "pmtud-probes: invalid argument" << std::endl; + std::println(stderr, "pmtud-probes: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println( + stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", + NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else { config.pmtud_probes.push_back(static_cast(*n)); @@ -3193,13 +3214,13 @@ int main(int argc, char **argv) { // --gso-burst auto n = util::parse_uint(optarg); if (!n) { - std::cerr << "gso-burst: invalid argument" << std::endl; + std::println(stderr, "gso-burst: invalid argument"); exit(EXIT_FAILURE); } if (*n > 64) { - std::cerr << "gso-burst: must be in range [0, 64], inclusive." - << std::endl; + std::println(stderr, + "gso-burst: must be in range [0, 64], inclusive."); exit(EXIT_FAILURE); } @@ -3215,39 +3236,38 @@ int main(int argc, char **argv) { } if (argc - optind < 2) { - std::cerr << "Too few arguments" << std::endl; - print_usage(); + std::println(stderr, "Too few arguments"); + print_usage(stderr); exit(EXIT_FAILURE); } if (!config.qlog_file.empty() && !config.qlog_dir.empty()) { - std::cerr << "qlog-file and qlog-dir are mutually exclusive" << std::endl; + std::println(stderr, "qlog-file and qlog-dir are mutually exclusive"); exit(EXIT_FAILURE); } if (config.exit_on_first_stream_close && config.exit_on_all_streams_close) { - std::cerr << "exit-on-first-stream-close and exit-on-all-streams-close are " - "mutually exclusive" - << std::endl; + std::println(stderr, "exit-on-first-stream-close and " + "exit-on-all-streams-close are mutually exclusive"); exit(EXIT_FAILURE); } if (config.wait_for_ticket && !config.session_file) { - std::cerr << "wait-for-ticket: session-file must be specified" << std::endl; + std::println(stderr, "wait-for-ticket: session-file must be specified"); exit(EXIT_FAILURE); } if (data_path) { auto fd = open(data_path, O_RDONLY); if (fd == -1) { - std::cerr << "data: Could not open file " << data_path << ": " - << strerror(errno) << std::endl; + std::println(stderr, "data: Could not open file {}: {}", data_path, + strerror(errno)); exit(EXIT_FAILURE); } struct stat st; if (fstat(fd, &st) != 0) { - std::cerr << "data: Could not stat file " << data_path << ": " - << strerror(errno) << std::endl; + std::println(stderr, "data: Could not stat file {}: {}", data_path, + strerror(errno)); exit(EXIT_FAILURE); } config.fd = fd; @@ -3255,8 +3275,8 @@ int main(int argc, char **argv) { if (config.datalen) { auto addr = mmap(nullptr, config.datalen, PROT_READ, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { - std::cerr << "data: Could not mmap file " << data_path << ": " - << strerror(errno) << std::endl; + std::println(stderr, "data: Could not mmap file {}: {}", data_path, + strerror(errno)); exit(EXIT_FAILURE); } config.data = static_cast(addr); @@ -3266,8 +3286,8 @@ int main(int argc, char **argv) { if (config.ech_config_list_file) { auto ech_config = util::read_file(config.ech_config_list_file); if (!ech_config) { - std::cerr << "ech-config-list-file: Could not read ECHConfigList" - << std::endl; + std::println(stderr, + "ech-config-list-file: Could not read ECHConfigList"); } else { config.ech_config_list = std::move(*ech_config); } @@ -3276,7 +3296,7 @@ int main(int argc, char **argv) { auto addr = argv[optind++]; auto port = argv[optind++]; - if (parse_requests(&argv[optind], static_cast(argc - optind)) != 0) { + if (!parse_requests(&argv[optind], static_cast(argc - optind))) { exit(EXIT_FAILURE); } @@ -3284,16 +3304,16 @@ int main(int argc, char **argv) { if (!config.preferred_versions.empty() && std::ranges::find(config.preferred_versions, config.version) == std::ranges::end(config.preferred_versions)) { - std::cerr << "preferred-version: must include version " << std::hex - << "0x" << config.version << std::dec << std::endl; + std::println(stderr, "preferred-version: must include version {:#x}", + config.version); exit(EXIT_FAILURE); } if (!config.available_versions.empty() && std::ranges::find(config.available_versions, config.version) == std::ranges::end(config.available_versions)) { - std::cerr << "available-versions: must include version " << std::hex - << "0x" << config.version << std::dec << std::endl; + std::println(stderr, "available-versions: must include version {:#x}", + config.version); exit(EXIT_FAILURE); } } @@ -3303,7 +3323,7 @@ int main(int argc, char **argv) { } TLSClientContext tls_ctx; - if (tls_ctx.init(private_key_file, cert_file) != 0) { + if (!tls_ctx.init(private_key_file, cert_file)) { exit(EXIT_FAILURE); } @@ -3317,8 +3337,8 @@ int main(int argc, char **argv) { } } - if (util::generate_secret(config.static_secret) != 0) { - std::cerr << "Unable to generate static secret" << std::endl; + if (!util::generate_secure_random(config.static_secret)) { + std::println(stderr, "Unable to generate static secret"); exit(EXIT_FAILURE); } @@ -3327,7 +3347,7 @@ int main(int argc, char **argv) { for (;;) { Client c(EV_DEFAULT, client_chosen_version, config.version); - if (run(c, addr, port, tls_ctx) != 0) { + if (!run(c, addr, port, tls_ctx)) { exit(EXIT_FAILURE); } @@ -3345,13 +3365,13 @@ int main(int argc, char **argv) { offered_versions.data(), offered_versions.size()); if (client_chosen_version == 0) { - std::cerr << "Unable to select a version" << std::endl; + std::println(stderr, "Unable to select a version"); exit(EXIT_FAILURE); } if (!config.quiet) { - std::cerr << "Client selected version " << std::hex << "0x" - << client_chosen_version << std::dec << std::endl; + std::println(stderr, "Client selected version {:#x}", + client_chosen_version); } } diff --git a/deps/ngtcp2/ngtcp2/examples/client.h b/deps/ngtcp2/ngtcp2/examples/client.h index e2a779493172bd..81ec0de6fa4173 100644 --- a/deps/ngtcp2/ngtcp2/examples/client.h +++ b/deps/ngtcp2/ngtcp2/examples/client.h @@ -55,7 +55,7 @@ struct Stream { Stream(const Request &req, int64_t stream_id); ~Stream(); - int open_file(const std::string_view &path); + std::expected open_file(std::string_view path); Request req; int64_t stream_id; @@ -77,68 +77,81 @@ class Client : public ClientBase { uint32_t original_version); ~Client(); - int init(int fd, const Address &local_addr, const Address &remote_addr, - const char *addr, const char *port, TLSClientContext &tls_ctx); + std::expected init(int fd, const Address &local_addr, + const Address &remote_addr, const char *addr, + const char *port, TLSClientContext &tls_ctx); void disconnect(); - int on_read(const Endpoint &ep); - int on_write(); - int write_streams(); - int feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, - const ngtcp2_pkt_info *pi, std::span data); - int handle_expiry(); + std::expected on_read(const Endpoint &ep); + std::expected on_write(); + std::expected write_streams(); + std::expected feed_data(const Endpoint &ep, const sockaddr *sa, + socklen_t salen, + const ngtcp2_pkt_info *pi, + std::span data); + std::expected handle_expiry(); void update_timer(); - int handshake_completed(); - int handshake_confirmed(); + std::expected handshake_completed(); + void handshake_confirmed(); void recv_version_negotiation(const uint32_t *sv, size_t nsv); - int send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, - unsigned int ecn, std::span data); - std::pair, int> + std::expected send_packet(const Endpoint &ep, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data); + std::span send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, unsigned int ecn, std::span data, size_t gso_size); - int send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size); - int on_stream_close(int64_t stream_id, uint64_t app_error_code); - int on_extend_max_streams(); - int handle_error(); - int make_stream_early(); - int change_local_addr(); + std::expected + send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, + std::span data, size_t gso_size); + std::expected on_stream_close(int64_t stream_id, + uint64_t app_error_code); + void on_extend_max_streams(); + std::expected handle_error(); + std::expected make_stream_early(); + std::expected change_local_addr(); void start_change_local_addr_timer(); - int update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen); - int initiate_key_update(); + std::expected + update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, + size_t secretlen); + std::expected initiate_key_update(); void start_key_update_timer(); void start_delay_stream_timer(); - int select_preferred_address(Address &selected_addr, - const ngtcp2_preferred_addr *paddr); + std::expected + select_preferred_address(Address &selected_addr, + const ngtcp2_preferred_addr *paddr); - std::optional endpoint_for(const Address &remote_addr); + std::expected endpoint_for(const Address &remote_addr); void set_remote_addr(const ngtcp2_addr &remote_addr); - int setup_httpconn(); - int submit_http_request(const Stream *stream); - int recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data); - int acked_stream_data_offset(int64_t stream_id, uint64_t datalen); + std::expected setup_httpconn(); + std::expected submit_http_request(const Stream *stream); + std::expected recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + std::expected acked_stream_data_offset(int64_t stream_id, + uint64_t datalen); void http_consume(int64_t stream_id, size_t nconsumed); void http_write_data(int64_t stream_id, std::span data); - int on_stream_reset(int64_t stream_id); - int on_stream_stop_sending(int64_t stream_id); - 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); + std::expected on_stream_reset(int64_t stream_id); + std::expected on_stream_stop_sending(int64_t stream_id); + std::expected extend_max_stream_data(int64_t stream_id, + uint64_t max_data); + std::expected stop_sending(int64_t stream_id, + uint64_t app_error_code); + std::expected reset_stream(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 data, size_t gso_size); void start_wev_endpoint(const Endpoint &ep); - int send_blocked_packet(); + void send_blocked_packet(); ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts); diff --git a/deps/ngtcp2/ngtcp2/examples/client_base.cc b/deps/ngtcp2/ngtcp2/examples/client_base.cc index 57af4244697998..2a92006eb25557 100644 --- a/deps/ngtcp2/ngtcp2/examples/client_base.cc +++ b/deps/ngtcp2/ngtcp2/examples/client_base.cc @@ -61,134 +61,6 @@ ClientBase::~ClientBase() { } } -int ClientBase::write_transport_params(const char *path, - const ngtcp2_transport_params *params) { - auto f = std::ofstream(path); - if (!f) { - return -1; - } - - f << "initial_max_streams_bidi=" << params->initial_max_streams_bidi << '\n' - << "initial_max_streams_uni=" << params->initial_max_streams_uni << '\n' - << "initial_max_stream_data_bidi_local=" - << params->initial_max_stream_data_bidi_local << '\n' - << "initial_max_stream_data_bidi_remote=" - << params->initial_max_stream_data_bidi_remote << '\n' - << "initial_max_stream_data_uni=" << params->initial_max_stream_data_uni - << '\n' - << "initial_max_data=" << params->initial_max_data << '\n' - << "active_connection_id_limit=" << params->active_connection_id_limit - << '\n' - << "max_datagram_frame_size=" << params->max_datagram_frame_size << '\n'; - - f.close(); - if (!f) { - return -1; - } - - return 0; -} - -int ClientBase::read_transport_params(const char *path, - ngtcp2_transport_params *params) { - auto f = std::ifstream(path); - if (!f) { - return -1; - } - - for (std::string line; std::getline(f, line);) { - if (util::istarts_with(line, "initial_max_streams_bidi="sv)) { - if (auto n = util::parse_uint(line.c_str() + - "initial_max_streams_bidi="sv.size()); - !n) { - return -1; - } else { - params->initial_max_streams_bidi = *n; - } - continue; - } - - if (util::istarts_with(line, "initial_max_streams_uni="sv)) { - if (auto n = util::parse_uint(line.c_str() + - "initial_max_streams_uni="sv.size()); - !n) { - return -1; - } else { - params->initial_max_streams_uni = *n; - } - continue; - } - - if (util::istarts_with(line, "initial_max_stream_data_bidi_local="sv)) { - if (auto n = util::parse_uint( - line.c_str() + "initial_max_stream_data_bidi_local="sv.size()); - !n) { - return -1; - } else { - params->initial_max_stream_data_bidi_local = *n; - } - continue; - } - - if (util::istarts_with(line, "initial_max_stream_data_bidi_remote="sv)) { - if (auto n = util::parse_uint( - line.c_str() + "initial_max_stream_data_bidi_remote="sv.size()); - !n) { - return -1; - } else { - params->initial_max_stream_data_bidi_remote = *n; - } - continue; - } - - if (util::istarts_with(line, "initial_max_stream_data_uni="sv)) { - if (auto n = util::parse_uint(line.c_str() + - "initial_max_stream_data_uni="sv.size()); - !n) { - return -1; - } else { - params->initial_max_stream_data_uni = *n; - } - continue; - } - - if (util::istarts_with(line, "initial_max_data="sv)) { - if (auto n = - util::parse_uint(line.c_str() + "initial_max_data="sv.size()); - !n) { - return -1; - } else { - params->initial_max_data = *n; - } - continue; - } - - if (util::istarts_with(line, "active_connection_id_limit="sv)) { - if (auto n = util::parse_uint(line.c_str() + - "active_connection_id_limit="sv.size()); - !n) { - return -1; - } else { - params->active_connection_id_limit = *n; - } - continue; - } - - if (util::istarts_with(line, "max_datagram_frame_size="sv)) { - if (auto n = util::parse_uint(line.c_str() + - "max_datagram_frame_size="sv.size()); - !n) { - return -1; - } else { - params->max_datagram_frame_size = *n; - } - continue; - } - } - - return 0; -} - ngtcp2_conn *ClientBase::conn() const { return conn_; } void qlog_write_cb(void *user_data, uint32_t flags, const void *data, diff --git a/deps/ngtcp2/ngtcp2/examples/client_base.h b/deps/ngtcp2/ngtcp2/examples/client_base.h index 6e8a0f600c1c29..329e8ae4735304 100644 --- a/deps/ngtcp2/ngtcp2/examples/client_base.h +++ b/deps/ngtcp2/ngtcp2/examples/client_base.h @@ -214,10 +214,6 @@ class ClientBase { ngtcp2_conn *conn() const; - int write_transport_params(const char *path, - const ngtcp2_transport_params *params); - int read_transport_params(const char *path, ngtcp2_transport_params *params); - void write_qlog(const void *data, size_t datalen); ngtcp2_crypto_conn_ref *conn_ref(); diff --git a/deps/ngtcp2/ngtcp2/examples/debug.cc b/deps/ngtcp2/ngtcp2/examples/debug.cc index c5216b958558d4..7e96a3ba9fd8c1 100644 --- a/deps/ngtcp2/ngtcp2/examples/debug.cc +++ b/deps/ngtcp2/ngtcp2/examples/debug.cc @@ -48,12 +48,12 @@ auto *outfile = stderr; } // namespace int handshake_completed(ngtcp2_conn *conn, void *user_data) { - fprintf(outfile, "QUIC handshake has completed\n"); + std::println(outfile, "QUIC handshake has completed"); return 0; } int handshake_confirmed(ngtcp2_conn *conn, void *user_data) { - fprintf(outfile, "QUIC handshake has been confirmed\n"); + std::println(outfile, "QUIC handshake has been confirmed"); return 0; } @@ -79,96 +79,100 @@ void print_crypto_data(ngtcp2_encryption_level encryption_level, assert(0); abort(); } - fprintf(outfile, "Ordered CRYPTO data in %s crypto level\n", - encryption_level_str); - util::hexdump(outfile, data.data(), data.size()); + std::println(outfile, "Ordered CRYPTO data in {} crypto level", + encryption_level_str); + util::hexdump(outfile, data); } void print_stream_data(int64_t stream_id, std::span data) { - fprintf(outfile, "Ordered STREAM data stream_id=0x%" PRIx64 "\n", stream_id); - util::hexdump(outfile, data.data(), data.size()); + std::println(outfile, "Ordered STREAM data stream_id={:#x}", stream_id); + util::hexdump(outfile, data); } void print_initial_secret(std::span data) { - fprintf(outfile, "initial_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "initial_secret={}", util::format_hex(data)); } void print_client_in_secret(std::span data) { - fprintf(outfile, "client_in_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "client_in_secret={}", util::format_hex(data)); } void print_server_in_secret(std::span data) { - fprintf(outfile, "server_in_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "server_in_secret={}", util::format_hex(data)); } void print_handshake_secret(std::span data) { - fprintf(outfile, "handshake_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "handshake_secret={}", util::format_hex(data)); } void print_client_hs_secret(std::span data) { - fprintf(outfile, "client_hs_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "client_hs_secret={}", util::format_hex(data)); } void print_server_hs_secret(std::span data) { - fprintf(outfile, "server_hs_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "server_hs_secret={}", util::format_hex(data)); } void print_client_0rtt_secret(std::span data) { - fprintf(outfile, "client_0rtt_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "client_0rtt_secret={}", util::format_hex(data)); } void print_client_1rtt_secret(std::span data) { - fprintf(outfile, "client_1rtt_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "client_1rtt_secret={}", util::format_hex(data)); } void print_server_1rtt_secret(std::span data) { - fprintf(outfile, "server_1rtt_secret=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "server_1rtt_secret={}", util::format_hex(data)); } void print_client_pp_key(std::span data) { - fprintf(outfile, "+ client_pp_key=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "+ client_pp_key={}", util::format_hex(data)); } void print_server_pp_key(std::span data) { - fprintf(outfile, "+ server_pp_key=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "+ server_pp_key={}", util::format_hex(data)); } void print_client_pp_iv(std::span data) { - fprintf(outfile, "+ client_pp_iv=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "+ client_pp_iv={}", util::format_hex(data)); } void print_server_pp_iv(std::span data) { - fprintf(outfile, "+ server_pp_iv=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "+ server_pp_iv={}", util::format_hex(data)); } void print_client_pp_hp(std::span data) { - fprintf(outfile, "+ client_pp_hp=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "+ client_pp_hp={}", util::format_hex(data)); } void print_server_pp_hp(std::span data) { - fprintf(outfile, "+ server_pp_hp=%s\n", util::format_hex(data).c_str()); + std::println(outfile, "+ server_pp_hp={}", util::format_hex(data)); } void print_secrets(std::span secret, std::span key, std::span iv, std::span hp) { - std::cerr << "+ secret=" << util::format_hex(secret) << "\n" - << "+ key=" << util::format_hex(key) << "\n" - << "+ iv=" << util::format_hex(iv) << "\n" - << "+ hp=" << util::format_hex(hp) << std::endl; + std::println(stderr, R"(+ secret={} ++ key={} ++ iv={} ++ hp={})", + util::format_hex(secret), util::format_hex(key), + util::format_hex(iv), util::format_hex(hp)); } void print_secrets(std::span secret, std::span key, std::span iv) { - std::cerr << "+ secret=" << util::format_hex(secret) << "\n" - << "+ key=" << util::format_hex(key) << "\n" - << "+ iv=" << util::format_hex(iv) << std::endl; + std::println(stderr, R"(+ secret={} ++ key={} ++ iv={})", + util::format_hex(secret), util::format_hex(key), + util::format_hex(iv)); } void print_hp_mask(std::span mask, std::span sample) { - fprintf(outfile, "mask=%s sample=%s\n", util::format_hex(mask).c_str(), - util::format_hex(sample).c_str()); + std::println(outfile, "mask={} sample={}", util::format_hex(mask), + util::format_hex(sample)); } void log_printf(void *user_data, const char *fmt, ...) { @@ -197,29 +201,28 @@ void path_validation(const ngtcp2_path *path, auto remote_addr = util::straddr( reinterpret_cast(path->remote.addr), path->remote.addrlen); - std::cerr << "Path validation against path {local:" << local_addr - << ", remote:" << remote_addr << "} " - << (res == NGTCP2_PATH_VALIDATION_RESULT_SUCCESS ? "succeeded" - : "failed") - << std::endl; + std::println( + stderr, "Path validation against path {{local:{}, remote:{}}} {}", + local_addr, remote_addr, + res == NGTCP2_PATH_VALIDATION_RESULT_SUCCESS ? "succeeded" : "failed"); } void print_http_begin_request_headers(int64_t stream_id) { - fprintf(outfile, "http: stream 0x%" PRIx64 " request headers started\n", - stream_id); + std::println(outfile, "http: stream {:#x} request headers started", + stream_id); } void print_http_begin_response_headers(int64_t stream_id) { - fprintf(outfile, "http: stream 0x%" PRIx64 " response headers started\n", - stream_id); + std::println(outfile, "http: stream {:#x} response headers started", + stream_id); } namespace { void print_header(std::span name, std::span value, uint8_t flags) { - fprintf(outfile, "[%.*s: %.*s]%s\n", static_cast(name.size()), - name.data(), static_cast(value.size()), value.data(), - (flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? "(sensitive)" : ""); + std::println(outfile, "[{}: {}]{}", as_string_view(name), + as_string_view(value), + (flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? "(sensitive)" : ""); } } // namespace @@ -241,32 +244,31 @@ void print_header(const nghttp3_nv &nv) { void print_http_header(int64_t stream_id, const nghttp3_rcbuf *name, const nghttp3_rcbuf *value, uint8_t flags) { - fprintf(outfile, "http: stream 0x%" PRIx64 " ", stream_id); + std::print(outfile, "http: stream {:#x} ", stream_id); print_header(name, value, flags); } void print_http_end_headers(int64_t stream_id) { - fprintf(outfile, "http: stream 0x%" PRIx64 " headers ended\n", stream_id); + std::println(outfile, "http: stream {:#x} headers ended", stream_id); } void print_http_data(int64_t stream_id, std::span data) { - fprintf(outfile, "http: stream 0x%" PRIx64 " body %zu bytes\n", stream_id, - data.size()); - util::hexdump(outfile, data.data(), data.size()); + std::println(outfile, "http: stream {:#x} body {} bytes", stream_id, + data.size()); + util::hexdump(outfile, data); } void print_http_begin_trailers(int64_t stream_id) { - fprintf(outfile, "http: stream 0x%" PRIx64 " trailers started\n", stream_id); + std::println(outfile, "http: stream {:#x} trailers started", stream_id); } void print_http_end_trailers(int64_t stream_id) { - fprintf(outfile, "http: stream 0x%" PRIx64 " trailers ended\n", stream_id); + std::println(outfile, "http: stream {:#x} trailers ended", stream_id); } void print_http_request_headers(int64_t stream_id, const nghttp3_nv *nva, size_t nvlen) { - fprintf(outfile, "http: stream 0x%" PRIx64 " submit request headers\n", - stream_id); + std::println(outfile, "http: stream {:#x} submit request headers", stream_id); for (size_t i = 0; i < nvlen; ++i) { auto &nv = nva[i]; print_header(nv); @@ -275,8 +277,8 @@ 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) { - fprintf(outfile, "http: stream 0x%" PRIx64 " submit response headers\n", - stream_id); + std::println(outfile, "http: stream {:#x} submit response headers", + stream_id); for (size_t i = 0; i < nvlen; ++i) { auto &nv = nva[i]; print_header(nv); @@ -284,24 +286,24 @@ void print_http_response_headers(int64_t stream_id, const nghttp3_nv *nva, } void print_http_settings(const nghttp3_proto_settings *settings) { - fprintf(outfile, - "http: remote settings\n" - "http: SETTINGS_MAX_FIELD_SECTION_SIZE=%" PRIu64 "\n" - "http: SETTINGS_QPACK_MAX_TABLE_CAPACITY=%zu\n" - "http: SETTINGS_QPACK_BLOCKED_STREAMS=%zu\n" - "http: SETTINGS_ENABLE_CONNECT_PROTOCOL=%d\n" - "http: SETTINGS_H3_DATAGRAM=%d\n", - settings->max_field_section_size, settings->qpack_max_dtable_capacity, - settings->qpack_blocked_streams, settings->enable_connect_protocol, - settings->h3_datagram); + std::println(outfile, R"(http: remote settings +http: SETTINGS_MAX_FIELD_SECTION_SIZE={} +http: SETTINGS_QPACK_MAX_TABLE_CAPACITY={} +http: SETTINGS_QPACK_BLOCKED_STREAMS={} +http: SETTINGS_ENABLE_CONNECT_PROTOCOL={} +http: SETTINGS_H3_DATAGRAM={})", + settings->max_field_section_size, + settings->qpack_max_dtable_capacity, + settings->qpack_blocked_streams, + settings->enable_connect_protocol, settings->h3_datagram); } void print_http_origin(const uint8_t *origin, size_t originlen) { - fprintf(outfile, "http: origin [%.*s]\n", static_cast(originlen), - origin); + std::println(outfile, "http: origin [{}]", + as_string_view(std::span{origin, originlen})); } -void print_http_end_origin() { fprintf(outfile, "http: origin ended\n"); } +void print_http_end_origin() { std::println(outfile, "http: origin ended"); } std::string_view secret_title(ngtcp2_encryption_level level) { switch (level) { @@ -322,22 +324,26 @@ void print_conn_info(ngtcp2_conn *conn) { 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; + std::println( + R"(# Connection Statistics (see ngtcp2_conn_info for details) +min_rtt={} +smoothed_rtt={} +rttvar={} +cwnd={} +ssthresh={} +pkt_sent={} +bytes_sent={} +pkt_recv={} +bytes_recv={} +pkt_lost={} +bytes_lost={} +ping_recv={} +pkt_discarded={})", + util::format_durationf(cinfo.min_rtt), + util::format_durationf(cinfo.smoothed_rtt), + util::format_durationf(cinfo.rttvar), cinfo.cwnd, cinfo.ssthresh, + cinfo.pkt_sent, cinfo.bytes_sent, cinfo.pkt_recv, cinfo.bytes_recv, + cinfo.pkt_lost, cinfo.bytes_lost, cinfo.ping_recv, cinfo.pkt_discarded); } } // namespace debug diff --git a/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c b/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c index 34a70b77e92920..56d0802b35e658 100644 --- a/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c +++ b/deps/ngtcp2/ngtcp2/examples/gtlssimpleclient.c @@ -244,8 +244,8 @@ static void rand_cb(uint8_t *dest, size_t destlen, } static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid, - uint8_t *token, size_t cidlen, - void *user_data) { + ngtcp2_stateless_reset_token *token, + size_t cidlen, void *user_data) { (void)conn; (void)user_data; @@ -255,8 +255,7 @@ static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid, cid->datalen = cidlen; - if (gnutls_rnd(GNUTLS_RND_RANDOM, token, NGTCP2_STATELESS_RESET_TOKENLEN) != - 0) { + if (gnutls_rnd(GNUTLS_RND_RANDOM, token->data, sizeof(token->data)) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -332,12 +331,12 @@ static int client_quic_init(struct client *c, .recv_retry = ngtcp2_crypto_recv_retry_cb, .extend_max_local_streams_bidi = extend_max_local_streams_bidi, .rand = rand_cb, - .get_new_connection_id = get_new_connection_id_cb, .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, + .get_new_connection_id2 = get_new_connection_id_cb, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; ngtcp2_cid dcid, scid; ngtcp2_settings settings; @@ -632,7 +631,7 @@ static int client_init(struct client *c) { struct sockaddr_storage remote_addr, local_addr; socklen_t remote_addrlen, local_addrlen = sizeof(local_addr); - memset(c, 0, sizeof(*c)); + *c = (struct client){0}; ngtcp2_ccerr_default(&c->last_error); diff --git a/deps/ngtcp2/ngtcp2/examples/h09client.cc b/deps/ngtcp2/ngtcp2/examples/h09client.cc index ef350eb8db0fef..7d2017d68894ab 100644 --- a/deps/ngtcp2/ngtcp2/examples/h09client.cc +++ b/deps/ngtcp2/ngtcp2/examples/h09client.cc @@ -75,7 +75,7 @@ Stream::~Stream() { } } -int Stream::open_file(const std::string_view &path) { +std::expected Stream::open_file(std::string_view path) { assert(fd == -1); std::string_view filename; @@ -86,8 +86,8 @@ int Stream::open_file(const std::string_view &path) { } else { filename = std::string_view{it, std::ranges::end(path)}; if (filename == ".."sv || filename == "."sv) { - std::cerr << "Invalid file name: " << filename << std::endl; - return -1; + std::println(stderr, "Invalid file name: {}", filename); + return std::unexpected{Error::INVALID_ARGUMENT}; } } @@ -98,12 +98,12 @@ int Stream::open_file(const std::string_view &path) { fd = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd == -1) { - std::cerr << "open: Could not open file " << fname << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "open: Could not open file {}: {}", fname, + strerror(errno)); + return std::unexpected{Error::IO}; } - return 0; + return {}; } namespace { @@ -119,7 +119,7 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) { auto ep = static_cast(w->data); auto c = ep->client; - if (c->on_read(*ep) != 0) { + if (!c->on_read(*ep)) { return; } @@ -129,11 +129,9 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) { namespace { void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { - int rv; auto c = static_cast(w->data); - rv = c->handle_expiry(); - if (rv != 0) { + if (auto rv = c->handle_expiry(); !rv) { return; } @@ -153,7 +151,7 @@ namespace { void key_updatecb(struct ev_loop *loop, ev_timer *w, int revents) { auto c = static_cast(w->data); - if (c->initiate_key_update() != 0) { + if (!c->initiate_key_update()) { c->disconnect(); } } @@ -253,9 +251,7 @@ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, auto c = static_cast(user_data); - if (c->recv_stream_data(flags, stream_id, {data, datalen}) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + c->recv_stream_data(flags, stream_id, {data, datalen}); return 0; } @@ -266,9 +262,9 @@ int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id, uint64_t offset, uint64_t datalen, void *user_data, void *stream_user_data) { auto c = static_cast(user_data); - if (c->acked_stream_data_offset(stream_id, offset, datalen) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + + c->acked_stream_data_offset(stream_id, offset, datalen); + return 0; } } // namespace @@ -281,7 +277,7 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { debug::handshake_completed(conn, user_data); } - if (c->handshake_completed() != 0) { + if (!c->handshake_completed()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -289,10 +285,10 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { } } // namespace -int Client::handshake_completed() { +std::expected Client::handshake_completed() { if (early_data_ && !tls_session_.get_early_data_accepted()) { if (!config.quiet) { - std::cerr << "Early data was rejected by server" << std::endl; + std::println(stderr, "Early data was rejected by server"); } // Some TLS backends only report early data rejection after @@ -300,23 +296,23 @@ int Client::handshake_completed() { // report it early (e.g., BoringSSL and PicoTLS), the following // functions are noop. if (auto rv = ngtcp2_conn_tls_early_data_rejected(conn_); rv != 0) { - std::cerr << "ngtcp2_conn_tls_early_data_rejected: " - << ngtcp2_strerror(rv) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_tls_early_data_rejected: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } } if (!config.quiet) { - std::cerr << "Negotiated cipher suite is " << tls_session_.get_cipher_name() - << std::endl; + std::println(stderr, "Negotiated cipher suite is {}", + tls_session_.get_cipher_name()); if (auto group = tls_session_.get_negotiated_group(); !group.empty()) { - std::cerr << "Negotiated group is " << group << std::endl; + std::println(stderr, "Negotiated group is {}", group); } - std::cerr << "Negotiated ALPN is " << tls_session_.get_selected_alpn() - << std::endl; + std::println(stderr, "Negotiated ALPN is {}", + tls_session_.get_selected_alpn()); if (!config.ech_config_list.empty() && tls_session_.get_ech_accepted()) { - std::cerr << "ECH was accepted" << std::endl; + std::println(stderr, "ECH was accepted"); } } @@ -325,17 +321,16 @@ int Client::handshake_completed() { auto datalen = ngtcp2_conn_encode_0rtt_transport_params(conn_, data.data(), data.size()); if (datalen < 0) { - std::cerr << "Could not encode 0-RTT transport parameters: " - << ngtcp2_strerror(static_cast(datalen)) << std::endl; - } else if (util::write_transport_params( - config.tp_file, {data.data(), static_cast(datalen)}) != - 0) { - std::cerr << "Could not write transport parameters in " << config.tp_file - << std::endl; + std::println(stderr, "Could not encode 0-RTT transport parameters: {}", + ngtcp2_strerror(static_cast(datalen))); + } else if (!util::write_transport_params( + config.tp_file, {data.data(), static_cast(datalen)})) { + std::println(stderr, "Could not write transport parameters to {}", + config.tp_file); } } - return 0; + return {}; } namespace { @@ -346,9 +341,7 @@ int handshake_confirmed(ngtcp2_conn *conn, void *user_data) { debug::handshake_confirmed(conn, user_data); } - if (c->handshake_confirmed() != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + c->handshake_confirmed(); return 0; } @@ -364,7 +357,7 @@ bool Client::should_exit() const { nstreams_closed_ == nstreams_done_)); } -int Client::handshake_confirmed() { +void Client::handshake_confirmed() { handshake_confirmed_ = true; if (config.change_local_addr) { @@ -376,8 +369,6 @@ int Client::handshake_confirmed() { if (config.delay_stream) { start_delay_stream_timer(); } - - return 0; } namespace { @@ -403,9 +394,7 @@ int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, void *stream_user_data) { auto c = static_cast(user_data); - if (c->on_stream_close(stream_id, app_error_code) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + c->on_stream_close(stream_id, app_error_code); return 0; } @@ -416,9 +405,7 @@ int extend_max_local_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams, void *user_data) { auto c = static_cast(user_data); - if (c->on_extend_max_streams() != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + c->on_extend_max_streams(); return 0; } @@ -426,8 +413,7 @@ int extend_max_local_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams, namespace { void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { - auto rv = util::generate_secure_random({dest, destlen}); - if (rv != 0) { + if (!util::generate_secure_random({dest, destlen})) { assert(0); abort(); } @@ -435,16 +421,17 @@ void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { } // namespace namespace { -int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token, - size_t cidlen, void *user_data) { - if (util::generate_secure_random({cid->data, cidlen}) != 0) { +int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, + ngtcp2_stateless_reset_token *token, size_t cidlen, + void *user_data) { + if (!util::generate_secure_random({cid->data, cidlen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } cid->datalen = cidlen; if (ngtcp2_crypto_generate_stateless_reset_token( - token, config.static_secret.data(), config.static_secret.size(), cid) != - 0) { + token->data, config.static_secret.data(), config.static_secret.size(), + cid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -477,9 +464,10 @@ int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, void *user_data) { auto c = static_cast(user_data); - if (c->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, - tx_iv, current_rx_secret, current_tx_secret, - secretlen) != 0) { + if (auto rv = + c->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, + tx_iv, current_rx_secret, current_tx_secret, secretlen); + !rv) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -520,7 +508,7 @@ int select_preferred_address(ngtcp2_conn *conn, ngtcp2_path *dest, return 0; } - if (c->select_preferred_address(remote_addr, paddr) != 0) { + if (auto rv = c->select_preferred_address(remote_addr, paddr); !rv) { return 0; } @@ -544,14 +532,14 @@ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, uint64_t max_data, void *user_data, void *stream_user_data) { auto c = static_cast(user_data); - if (c->extend_max_stream_data(stream_id, max_data) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + + c->extend_max_stream_data(stream_id, max_data); + return 0; } } // namespace -int Client::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { +void Client::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { auto it = streams_.find(stream_id); assert(it != std::ranges::end(streams_)); auto &stream = (*it).second; @@ -559,8 +547,6 @@ int Client::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { if (nghttp3_buf_len(&stream->reqbuf)) { sendq_.emplace(stream.get()); } - - return 0; } namespace { @@ -591,9 +577,10 @@ void Client::early_data_rejected() { streams_.clear(); } -int Client::init(int fd, const Address &local_addr, const Address &remote_addr, - const char *addr, const char *port, - TLSClientContext &tls_ctx) { +std::expected Client::init(int fd, const Address &local_addr, + const Address &remote_addr, + const char *addr, const char *port, + TLSClientContext &tls_ctx) { endpoints_.reserve(4); endpoints_.emplace_back(); @@ -622,7 +609,6 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, .recv_retry = ngtcp2_crypto_recv_retry_cb, .extend_max_local_streams_bidi = extend_max_local_streams_bidi, .rand = rand, - .get_new_connection_id = get_new_connection_id, .update_key = ::update_key, .path_validation = path_validation, .select_preferred_addr = ::select_preferred_address, @@ -631,22 +617,24 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, .recv_new_token = ::recv_new_token, .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, .tls_early_data_rejected = ::early_data_rejected, + .get_new_connection_id2 = get_new_connection_id, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; ngtcp2_cid scid, dcid; scid.datalen = 17; - if (util::generate_secure_random({scid.data, scid.datalen}) != 0) { - std::cerr << "Could not generate source connection ID" << std::endl; - return -1; + if (auto rv = util::generate_secure_random({scid.data, scid.datalen}); !rv) { + std::println(stderr, "Could not generate source connection ID"); + return rv; } if (config.dcid.datalen == 0) { dcid.datalen = 18; - if (util::generate_secure_random({dcid.data, dcid.datalen}) != 0) { - std::cerr << "Could not generate destination connection ID" << std::endl; - return -1; + if (auto rv = util::generate_secure_random({dcid.data, dcid.datalen}); + !rv) { + std::println(stderr, "Could not generate destination connection ID"); + return rv; } } else { dcid = config.dcid; @@ -667,9 +655,9 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, } qlog_ = fopen(path.c_str(), "w"); if (qlog_ == nullptr) { - std::cerr << "Could not open qlog file " << std::quoted(path) << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "Could not open qlog file {}: {}", path, + strerror(errno)); + return std::unexpected{Error::IO}; } settings.qlog_write = qlog_write_cb; } @@ -696,7 +684,7 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, std::vector token; if (!config.token_file.empty()) { - std::cerr << "Reading token file " << config.token_file << std::endl; + std::println(stderr, "Reading token file {}", config.token_file); auto t = util::read_token(config.token_file); if (t) { @@ -751,13 +739,14 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, &callbacks, &settings, ¶ms, nullptr, this); if (rv != 0) { - std::cerr << "ngtcp2_conn_client_new: " << ngtcp2_strerror(rv) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_client_new: {}", ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - if (tls_session_.init(early_data_, tls_ctx, addr_, this, - client_chosen_version_, AppProtocol::HQ) != 0) { - return -1; + if (auto rv = tls_session_.init(early_data_, tls_ctx, addr_, this, + client_chosen_version_, AppProtocol::HQ); + !rv) { + return rv; } ngtcp2_conn_set_tls_native_handle(conn_, tls_session_.get_native_handle()); @@ -770,11 +759,12 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, auto rv = ngtcp2_conn_decode_and_set_0rtt_transport_params( conn_, params->data(), params->size()); if (rv != 0) { - std::cerr << "ngtcp2_conn_decode_and_set_0rtt_transport_params:" - << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, + "ngtcp2_conn_decode_and_set_0rtt_transport_params: {}", + ngtcp2_strerror(rv)); early_data_ = false; - } else if (make_stream_early() != 0) { - return -1; + } else { + make_stream_early(); } } } @@ -783,12 +773,12 @@ int Client::init(int fd, const Address &local_addr, const Address &remote_addr, ev_signal_start(loop_, &sigintev_); - return 0; + return {}; } -int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, - const ngtcp2_pkt_info *pi, - std::span data) { +std::expected +Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, + const ngtcp2_pkt_info *pi, std::span data) { auto path = ngtcp2_path{ .local = as_ngtcp2_addr(ep.addr), .remote{ @@ -800,29 +790,28 @@ int Client::feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(), util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); if (!last_error_.error_code) { if (rv == NGTCP2_ERR_CRYPTO) { auto alert = ngtcp2_conn_get_tls_alert(conn_); ngtcp2_ccerr_set_tls_alert(&last_error_, alert, nullptr, 0); if (alert == TLS_ALERT_ECH_REQUIRED && config.ech_config_list_file && - tls_session_.write_ech_config_list(config.ech_config_list_file) != - 0) { - std::cerr << "Could not write ECH retry configs in " - << config.ech_config_list_file << std::endl; + !tls_session_.write_ech_config_list(config.ech_config_list_file)) { + std::println(stderr, "Could not write ECH retry configs in {}", + config.ech_config_list_file); } } else { ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); } } disconnect(); - return -1; + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } -int Client::on_read(const Endpoint &ep) { +std::expected Client::on_read(const Endpoint &ep) { std::array buf; sockaddr_storage ss; size_t pktcnt = 0; @@ -857,7 +846,7 @@ int Client::on_read(const Endpoint &ep) { if (nread == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - std::cerr << "recvmsg: " << strerror(errno) << std::endl; + std::println(stderr, "recvmsg: {}", strerror(errno)); } break; } @@ -883,12 +872,12 @@ int Client::on_read(const Endpoint &ep) { ++pktcnt; if (!config.quiet) { - std::cerr << "Received packet: local=" << util::straddr(ep.addr) - << " remote=" - << util::straddr(reinterpret_cast(&ss), - msg.msg_namelen) - << " ecn=0x" << std::hex << static_cast(pi.ecn) - << std::dec << " " << datalen << " bytes" << std::endl; + std::println(stderr, + "Received packet: local={} remote={} ecn={:#x} {} bytes", + util::straddr(ep.addr), + util::straddr(reinterpret_cast(&ss), + msg.msg_namelen), + pi.ecn, datalen); } // Packets less than 21 bytes never be a valid QUIC packet. @@ -898,11 +887,13 @@ int Client::on_read(const Endpoint &ep) { if (debug::packet_lost(config.rx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated incoming packet loss **" << std::endl; + std::println(stderr, "** Simulated incoming packet loss **"); } - } else if (feed_data(ep, reinterpret_cast(&ss), - msg.msg_namelen, &pi, {data.data(), datalen}) != 0) { - return -1; + } else if (auto rv = + feed_data(ep, reinterpret_cast(&ss), + msg.msg_namelen, &pi, {data.data(), datalen}); + !rv) { + return rv; } data = data.subspan(datalen); @@ -914,52 +905,51 @@ int Client::on_read(const Endpoint &ep) { } if (should_exit()) { + ngtcp2_ccerr_set_application_error( + &last_error_, nghttp3_err_infer_quic_app_error_code(0), nullptr, 0); disconnect(); - return -1; + return std::unexpected{Error::INTERNAL}; } update_timer(); - return 0; + return {}; } -int Client::handle_expiry() { +std::expected Client::handle_expiry() { auto now = util::timestamp(); if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) { - std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_handle_expiry: {}", ngtcp2_strerror(rv)); ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); disconnect(); - return -1; + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } -int Client::on_write() { +std::expected Client::on_write() { if (tx_.send_blocked) { - if (auto rv = send_blocked_packet(); rv != 0) { - return rv; - } + send_blocked_packet(); if (tx_.send_blocked) { - return 0; + return {}; } } ev_io_stop(loop_, &wev_); - if (auto rv = write_streams(); rv != 0) { + if (auto rv = write_streams(); !rv) { return rv; } if (should_exit()) { disconnect(); - return -1; + return std::unexpected{Error::INTERNAL}; } update_timer(); - return 0; + return {}; } namespace { @@ -1016,8 +1006,8 @@ ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, assert(ndatalen == -1); - std::cerr << "ngtcp2_conn_write_stream: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, 0); @@ -1035,7 +1025,7 @@ ngtcp2_ssize Client::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, } } -int Client::write_streams() { +std::expected Client::write_streams() { ngtcp2_path_storage ps; ngtcp2_pkt_info pi; size_t gso_size; @@ -1050,36 +1040,34 @@ int Client::write_streams() { config.gso_burst, ts); if (nwrite < 0) { disconnect(); - return -1; + return std::unexpected{Error::QUIC}; } ngtcp2_conn_update_pkt_tx_time(conn_, ts); if (nwrite == 0) { - return 0; + return {}; } send_packet_or_blocked(ps.path, pi.ecn, txbuf.first(static_cast(nwrite)), gso_size); - return 0; + return {}; } -int Client::send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, - size_t gso_size) { +std::expected +Client::send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, + std::span data, size_t gso_size) { auto &ep = *static_cast(path.user_data); - auto [rest, rv] = send_packet(ep, path.remote, ecn, data, gso_size); - if (rv != 0) { - assert(NETWORK_ERR_SEND_BLOCKED == rv); - + auto rest = send_packet(ep, path.remote, ecn, data, gso_size); + if (!rest.empty()) { on_send_blocked(path, ecn, rest, gso_size); - return rv; + return std::unexpected{Error::SEND_BLOCKED}; } - return 0; + return {}; } void Client::update_timer() { @@ -1089,8 +1077,7 @@ void Client::update_timer() { if (expiry <= now) { if (!config.quiet) { auto t = static_cast(now - expiry) / NGTCP2_SECONDS; - std::cerr << "Timer has already expired: " << std::fixed << t << "s" - << std::defaultfloat << std::endl; + std::println(stderr, "Timer has already expired: {:.9f}s", t); } ev_feed_event(loop_, &timer_, EV_TIMER); @@ -1100,8 +1087,7 @@ void Client::update_timer() { auto t = static_cast(expiry - now) / NGTCP2_SECONDS; if (!config.quiet) { - std::cerr << "Set timer=" << std::fixed << t << "s" << std::defaultfloat - << std::endl; + std::println(stderr, "Set timer={:.9f}s", t); } timer_.repeat = t; ev_timer_again(loop_, &timer_); @@ -1109,7 +1095,8 @@ void Client::update_timer() { #ifdef HAVE_LINUX_RTNETLINK_H namespace { -int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) { +std::expected bind_addr(Address &local_addr, int fd, + const InAddr &ia, int family) { addrinfo hints{ .ai_flags = AI_PASSIVE, .ai_family = family, @@ -1124,16 +1111,16 @@ int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) { } 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; + std::println(stderr, "inet_ntop: {}", strerror(errno)); + return std::unexpected{Error::LIBC}; } node = nodebuf.data(); } if (auto rv = getaddrinfo(node, "0", &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } auto res_d = defer([res] { freeaddrinfo(res); }); @@ -1145,53 +1132,56 @@ int bind_addr(Address &local_addr, int fd, const InAddr &ia, int family) { } if (!rp) { - std::cerr << "Could not bind" << std::endl; - return -1; + std::println(stderr, "Could not bind"); + return std::unexpected{Error::SYSCALL}; } sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::cerr << "getsockname: " << strerror(errno) << std::endl; - return -1; + std::println(stderr, "getsockname: {}", strerror(errno)); + return std::unexpected{Error::SYSCALL}; } local_addr.set(reinterpret_cast(&ss)); - return 0; + return {}; } } // namespace #endif // defined(HAVE_LINUX_RTNETLINK_H) #ifndef HAVE_LINUX_RTNETLINK_H namespace { -int connect_sock(Address &local_addr, int fd, const Address &remote_addr) { +std::expected connect_sock(Address &local_addr, int fd, + const Address &remote_addr) { if (connect(fd, remote_addr.as_sockaddr(), remote_addr.size()) != 0) { - std::cerr << "connect: " << strerror(errno) << std::endl; - return -1; + std::println(stderr, "connect: {}", strerror(errno)); + return std::unexpected{Error::SYSCALL}; } sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::cerr << "getsockname: " << strerror(errno) << std::endl; - return -1; + std::println(stderr, "getsockname: {}", strerror(errno)); + return std::unexpected{Error::SYSCALL}; } local_addr.set(reinterpret_cast(&ss)); - return 0; + return {}; } } // namespace #endif // !defined(HAVE_LINUX_RTNETLINK_H) namespace { -int udp_sock(int family) { - auto fd = util::create_nonblock_socket(family, SOCK_DGRAM, IPPROTO_UDP); - if (fd == -1) { - return -1; +std::expected udp_sock(int family) { + auto maybe_fd = util::create_nonblock_socket(family, SOCK_DGRAM, IPPROTO_UDP); + if (!maybe_fd) { + return maybe_fd; } + auto fd = *maybe_fd; + fd_set_recv_ecn(fd, family); fd_set_ip_mtu_discover(fd, family); fd_set_ip_dontfrag(fd, family); @@ -1202,7 +1192,8 @@ int udp_sock(int family) { } // namespace namespace { -int create_sock(Address &remote_addr, const char *addr, const char *port) { +std::expected create_sock(Address &remote_addr, const char *addr, + const char *port) { addrinfo hints{ .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, @@ -1210,8 +1201,8 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) { addrinfo *res, *rp; if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } auto res_d = defer([res] { freeaddrinfo(res); }); @@ -1219,17 +1210,19 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) { int fd = -1; for (rp = res; rp; rp = rp->ai_next) { - fd = udp_sock(rp->ai_family); - if (fd == -1) { + auto maybe_fd = udp_sock(rp->ai_family); + if (!maybe_fd) { continue; } + fd = *maybe_fd; + break; } if (!rp) { - std::cerr << "Could not create socket" << std::endl; - return -1; + std::println(stderr, "Could not create socket"); + return std::unexpected{Error::SYSCALL}; } remote_addr.set(rp->ai_addr); @@ -1238,16 +1231,18 @@ int create_sock(Address &remote_addr, const char *addr, const char *port) { } } // namespace -std::optional Client::endpoint_for(const Address &remote_addr) { +std::expected +Client::endpoint_for(const Address &remote_addr) { #ifdef HAVE_LINUX_RTNETLINK_H - InAddr ia; - - if (get_local_addr(ia, remote_addr) != 0) { - std::cerr << "Could not get local address for a selected preferred address" - << std::endl; - return nullptr; + auto maybe_ia = get_local_addr(remote_addr); + if (!maybe_ia) { + std::println( + stderr, "Could not get local address for a selected preferred address"); + return std::unexpected{maybe_ia.error()}; } + const auto &ia = *maybe_ia; + auto current_path = ngtcp2_conn_get_path(conn_); auto current_ep = static_cast(current_path->user_data); if (addreq(current_ep->addr, ia)) { @@ -1257,22 +1252,24 @@ std::optional Client::endpoint_for(const Address &remote_addr) { auto family = remote_addr.family(); - auto fd = udp_sock(family); - if (fd == -1) { - return nullptr; + auto maybe_fd = udp_sock(family); + if (!maybe_fd) { + return std::unexpected{maybe_fd.error()}; } + auto fd = *maybe_fd; + Address local_addr; #ifdef HAVE_LINUX_RTNETLINK_H - if (bind_addr(local_addr, fd, ia, family) != 0) { + if (auto rv = bind_addr(local_addr, fd, ia, family); !rv) { close(fd); - return nullptr; + return std::unexpected{rv.error()}; } #else // !defined(HAVE_LINUX_RTNETLINK_H) - if (connect_sock(local_addr, fd, remote_addr) != 0) { + if (auto rv = connect_sock(local_addr, fd, remote_addr); !rv) { close(fd); - return nullptr; + return std::unexpected{rv.error()}; } #endif // !defined(HAVE_LINUX_RTNETLINK_H) @@ -1293,43 +1290,43 @@ void Client::start_change_local_addr_timer() { ev_timer_start(loop_, &change_local_addr_timer_); } -int Client::change_local_addr() { +std::expected Client::change_local_addr() { Address local_addr; if (!config.quiet) { - std::cerr << "Changing local address" << std::endl; + std::println(stderr, "Changing local address"); } auto family = remote_addr_.family(); - auto nfd = udp_sock(family); - if (nfd == -1) { - return -1; + auto maybe_nfd = udp_sock(family); + if (!maybe_nfd) { + return std::unexpected{maybe_nfd.error()}; } -#ifdef HAVE_LINUX_RTNETLINK_H - InAddr ia; + auto nfd = *maybe_nfd; - if (get_local_addr(ia, remote_addr_) != 0) { - std::cerr << "Could not get local address" << std::endl; +#ifdef HAVE_LINUX_RTNETLINK_H + auto maybe_ia = get_local_addr(remote_addr_); + if (!maybe_ia) { + std::println(stderr, "Could not get local address"); close(nfd); - return -1; + return std::unexpected{maybe_ia.error()}; } - if (bind_addr(local_addr, nfd, ia, family) != 0) { + if (auto rv = bind_addr(local_addr, nfd, *maybe_ia, family); !rv) { close(nfd); - return -1; + return rv; } #else // !defined(HAVE_LINUX_RTNETLINK_H) - if (connect_sock(local_addr, nfd, remote_addr_) != 0) { + if (auto rv = connect_sock(local_addr, nfd, remote_addr_); !rv) { close(nfd); - return -1; + return rv; } #endif // !defined(HAVE_LINUX_RTNETLINK_H) if (!config.quiet) { - std::cerr << "Local address is now " << util::straddr(local_addr) - << std::endl; + std::println(stderr, "Local address is now {}", util::straddr(local_addr)); } endpoints_.emplace_back(); @@ -1354,27 +1351,28 @@ int Client::change_local_addr() { if (auto rv = ngtcp2_conn_initiate_immediate_migration(conn_, &path, util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_initiate_immediate_migration: " - << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, "ngtcp2_conn_initiate_immediate_migration: {}", + ngtcp2_strerror(rv)); } } ev_io_start(loop_, &ep.rev); - return 0; + return {}; } void Client::start_key_update_timer() { ev_timer_start(loop_, &key_update_timer_); } -int Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen) { +std::expected +Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, + const uint8_t *current_tx_secret, size_t secretlen) { if (!config.quiet) { - std::cerr << "Updating traffic key" << std::endl; + std::println(stderr, "Updating traffic key"); } auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); @@ -1390,73 +1388,81 @@ int Client::update_key(uint8_t *rx_secret, uint8_t *tx_secret, rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), tx_iv, current_rx_secret, current_tx_secret, secretlen) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } if (!config.quiet && config.show_secret) { - std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic rx secret {}", nkey_update_); debug::print_secrets({rx_secret, secretlen}, {rx_key.data(), keylen}, {rx_iv, ivlen}); - std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic tx secret {}", nkey_update_); debug::print_secrets({tx_secret, secretlen}, {tx_key.data(), keylen}, {tx_iv, ivlen}); } - return 0; + return {}; } -int Client::initiate_key_update() { +std::expected Client::initiate_key_update() { if (!config.quiet) { - std::cerr << "Initiate key update" << std::endl; + std::println(stderr, "Initiate key update"); } if (auto rv = ngtcp2_conn_initiate_key_update(conn_, util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_initiate_key_update: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_initiate_key_update: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } void Client::start_delay_stream_timer() { ev_timer_start(loop_, &delay_stream_timer_); } -int Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, - unsigned int ecn, std::span data) { - auto [_, rv] = send_packet(ep, remote_addr, ecn, data, data.size()); +std::expected Client::send_packet(const Endpoint &ep, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data) { + auto rest = send_packet(ep, remote_addr, ecn, data, data.size()); + if (!rest.empty()) { + return std::unexpected{Error::SEND_BLOCKED}; + } - return rv; + return {}; } -std::pair, int> -Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, - unsigned int ecn, std::span data, - size_t gso_size) { +std::span Client::send_packet(const Endpoint &ep, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data, + size_t gso_size) { assert(gso_size); if (debug::packet_lost(config.tx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated outgoing packet loss **" << std::endl; + std::println(stderr, "** Simulated outgoing packet loss **"); } - return {{}, NETWORK_ERR_OK}; + return {}; } if (no_gso_ && data.size() > gso_size) { for (; !data.empty();) { auto len = std::min(gso_size, data.size()); - auto [_, rv] = send_packet(ep, remote_addr, ecn, data.first(len), len); - if (rv != 0) { - return {data, rv}; + auto rest = send_packet(ep, remote_addr, ecn, data.first(len), len); + if (!rest.empty()) { + assert(rest.size() == len); + + return data; } data = data.subspan(len); } - return {{}, 0}; + return {}; } iovec msg_iov{ @@ -1531,13 +1537,13 @@ Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, #if EAGAIN != EWOULDBLOCK case EWOULDBLOCK: #endif // EAGAIN != EWOULDBLOCK - return {data, NETWORK_ERR_SEND_BLOCKED}; + return data; #ifdef UDP_SEGMENT case EIO: if (data.size() > gso_size) { // GSO failure; send each packet in a separate sendmsg call. - std::cerr << "sendmsg: disabling GSO due to " << strerror(errno) - << std::endl; + std::println(stderr, "sendmsg: disabling GSO due to {}", + strerror(errno)); no_gso_ = true; @@ -1547,23 +1553,23 @@ Client::send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, #endif // defined(UDP_SEGMENT) } - std::cerr << "sendmsg: " << strerror(errno) << std::endl; + std::println(stderr, "sendmsg: {}", strerror(errno)); // TODO We have packet which is expected to fail to send (e.g., // path validation to old path). - return {{}, NETWORK_ERR_OK}; + return {}; } assert(static_cast(nwrite) == data.size()); if (!config.quiet) { - 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; + std::println(stderr, "Sent packet: local={} remote={} ecn={:#x} {} bytes", + util::straddr(ep.addr), + util::straddr(remote_addr.addr, remote_addr.addrlen), ecn, + nwrite); } - return {{}, NETWORK_ERR_OK}; + return {}; } void Client::on_send_blocked(const ngtcp2_path &path, unsigned int ecn, @@ -1601,32 +1607,28 @@ void Client::start_wev_endpoint(const Endpoint &ep) { ev_io_start(loop_, &wev_); } -int Client::send_blocked_packet() { +void Client::send_blocked_packet() { assert(tx_.send_blocked); auto &p = tx_.blocked; - 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); - + auto rest = send_packet(*p.endpoint, as_ngtcp2_addr(p.remote_addr), p.ecn, + p.data, p.gso_size); + if (!rest.empty()) { p.data = rest; start_wev_endpoint(*p.endpoint); - return 0; + return; } tx_.send_blocked = false; - - return 0; } -int Client::handle_error() { +std::expected Client::handle_error() { if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || ngtcp2_conn_in_draining_period(conn_)) { - return 0; + return {}; } std::array buf; @@ -1641,13 +1643,13 @@ int Client::handle_error() { conn_, &ps.path, &pi, buf.data(), buf.size(), &last_error_, util::timestamp()); if (nwrite < 0) { - std::cerr << "ngtcp2_conn_write_connection_close: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_write_connection_close: {}", + ngtcp2_strerror(static_cast(nwrite))); + return std::unexpected{Error::QUIC}; } if (nwrite == 0) { - return 0; + return {}; } return send_packet(*static_cast(ps.path.user_data), @@ -1655,7 +1657,7 @@ int Client::handle_error() { {buf.data(), static_cast(nwrite)}); } -int Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) { +void Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) { auto it = streams_.find(stream_id); assert(it != std::ranges::end(streams_)); auto &stream = (*it).second; @@ -1670,22 +1672,20 @@ int Client::on_stream_close(int64_t stream_id, uint64_t app_error_code) { } if (!config.quiet) { - std::cerr << "HTTP stream " << stream_id << " closed with error code " - << app_error_code << std::endl; + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); } streams_.erase(it); - - return 0; } -int Client::make_stream_early() { return on_extend_max_streams(); } +void Client::make_stream_early() { on_extend_max_streams(); } -int Client::on_extend_max_streams() { +void Client::on_extend_max_streams() { int64_t stream_id; if ((config.delay_stream && !handshake_confirmed_) || ev_is_active(&delay_stream_timer_)) { - return 0; + return; } for (; nstreams_done_ < config.nstreams; ++nstreams_done_) { @@ -1698,19 +1698,16 @@ int Client::on_extend_max_streams() { auto stream = std::make_unique( config.requests[nstreams_done_ % config.requests.size()], stream_id); - if (submit_http_request(stream.get()) != 0) { - break; - } + submit_http_request(stream.get()); if (!config.download.empty()) { stream->open_file(stream->req.path); } streams_.emplace(stream_id, std::move(stream)); } - return 0; } -int Client::submit_http_request(Stream *stream) { +void Client::submit_http_request(Stream *stream) { const auto &req = stream->req; stream->rawreqbuf = config.http_method; @@ -1734,12 +1731,10 @@ int Client::submit_http_request(Stream *stream) { } sendq_.emplace(stream); - - return 0; } -int Client::recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data) { +void Client::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { auto it = streams_.find(stream_id); assert(it != std::ranges::end(streams_)); auto &stream = (*it).second; @@ -1748,47 +1743,56 @@ int Client::recv_stream_data(uint32_t flags, int64_t stream_id, ngtcp2_conn_extend_max_offset(conn_, data.size()); if (stream->fd == -1) { - return 0; + return; } ssize_t nwrite; - do { - nwrite = write(stream->fd, data.data(), data.size()); - } while (nwrite == -1 && errno == EINTR); - return 0; + for (; !data.empty();) { + do { + nwrite = write(stream->fd, data.data(), data.size()); + } while (nwrite == -1 && errno == EINTR); + + if (nwrite < 0) { + std::println(stderr, "Could not write data to file: {}", strerror(errno)); + + return; + } + + data = data.subspan(static_cast(nwrite)); + } } -int Client::acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen) { +void Client::acked_stream_data_offset(int64_t stream_id, uint64_t offset, + uint64_t datalen) { auto it = streams_.find(stream_id); assert(it != std::ranges::end(streams_)); auto &stream = (*it).second; (void)stream; assert(static_cast(stream->reqbuf.end - stream->reqbuf.begin) >= offset + datalen); - return 0; } -int Client::select_preferred_address(Address &selected_addr, - const ngtcp2_preferred_addr *paddr) { +std::expected +Client::select_preferred_address(Address &selected_addr, + const ngtcp2_preferred_addr *paddr) { auto path = ngtcp2_conn_get_path(conn_); switch (path->local.addr->sa_family) { case AF_INET: if (!paddr->ipv4_present) { - return -1; + return std::unexpected{Error::INTERNAL}; } selected_addr.skaddr.emplace(paddr->ipv4); break; case AF_INET6: if (!paddr->ipv6_present) { - return -1; + return std::unexpected{Error::INTERNAL}; } selected_addr.skaddr.emplace(paddr->ipv6); break; default: - return -1; + return std::unexpected{Error::INTERNAL}; } if (!config.quiet) { @@ -1797,15 +1801,15 @@ int Client::select_preferred_address(Address &selected_addr, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } - std::cerr << "selected server preferred_address is [" << host - << "]:" << service << std::endl; + std::println(stderr, "selected server preferred_address is [{}]:{}", host, + service); } - return 0; + return {}; } const std::vector &Client::get_offered_versions() const { @@ -1813,70 +1817,79 @@ const std::vector &Client::get_offered_versions() const { } namespace { -int run(Client &c, const char *addr, const char *port, - TLSClientContext &tls_ctx) { +std::expected run(Client &c, const char *addr, const char *port, + TLSClientContext &tls_ctx) { Address remote_addr, local_addr; - auto fd = create_sock(remote_addr, addr, port); - if (fd == -1) { - return -1; + auto maybe_fd = create_sock(remote_addr, addr, port); + if (!maybe_fd) { + return std::unexpected{maybe_fd.error()}; } -#ifdef HAVE_LINUX_RTNETLINK_H - InAddr ia; + auto fd = *maybe_fd; - if (get_local_addr(ia, remote_addr) != 0) { - std::cerr << "Could not get local address" << std::endl; +#ifdef HAVE_LINUX_RTNETLINK_H + auto maybe_ia = get_local_addr(remote_addr); + if (!maybe_ia) { + std::println(stderr, "Could not get local address"); close(fd); - return -1; + return std::unexpected{maybe_ia.error()}; } - if (bind_addr(local_addr, fd, ia, remote_addr.family()) != 0) { + if (auto rv = bind_addr(local_addr, fd, *maybe_ia, remote_addr.family()); + !rv) { close(fd); - return -1; + return rv; } #else // !defined(HAVE_LINUX_RTNETLINK_H) - if (connect_sock(local_addr, fd, remote_addr) != 0) { + if (auto rv = connect_sock(local_addr, fd, remote_addr); !rv) { close(fd); - return -1; + return rv; } #endif // !defined(HAVE_LINUX_RTNETLINK_H) - if (c.init(fd, local_addr, remote_addr, addr, port, tls_ctx) != 0) { - return -1; + if (auto rv = c.init(fd, local_addr, remote_addr, addr, port, tls_ctx); !rv) { + return rv; } // TODO Do we need this ? - if (auto rv = c.on_write(); rv != 0) { + if (auto rv = c.on_write(); !rv) { return rv; } ev_run(EV_DEFAULT, 0); - return 0; + return {}; } } // namespace namespace { -int parse_uri(Request &req, const std::string_view &uri) { +std::expected parse_uri(std::string_view uri) { urlparse_url u; if (urlparse_parse_url(uri.data(), uri.size(), /* is_connect = */ 0, &u) != 0) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } if (!(u.field_set & (1 << URLPARSE_SCHEMA)) || !(u.field_set & (1 << URLPARSE_HOST))) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } + Request req; + req.scheme = util::get_string(uri, u, URLPARSE_SCHEMA); - req.authority = util::get_string(uri, u, URLPARSE_HOST); - if (util::numeric_host(req.authority.c_str(), AF_INET6)) { - req.authority = '[' + req.authority + ']'; + auto host = std::string(util::get_string(uri, u, URLPARSE_HOST)); + if (util::numeric_host(host.c_str(), AF_INET6)) { + req.authority = '['; + req.authority += host; + req.authority += ']'; + } else { + req.authority = std::move(host); } + if (u.field_set & (1 << URLPARSE_PORT)) { req.authority += ':'; req.authority += util::get_string(uri, u, URLPARSE_PORT); @@ -1893,22 +1906,22 @@ int parse_uri(Request &req, const std::string_view &uri) { req.path += util::get_string(uri, u, URLPARSE_QUERY); } - return 0; + return req; } } // namespace namespace { -int parse_requests(char **argv, size_t argvlen) { +std::expected parse_requests(char **argv, size_t argvlen) { for (size_t i = 0; i < argvlen; ++i) { auto uri = std::string_view{argv[i]}; - Request req; - if (parse_uri(req, uri) != 0) { - std::cerr << "Could not parse URI: " << uri << std::endl; - return -1; + auto maybe_req = parse_uri(uri); + if (!maybe_req) { + std::println(stderr, "Could not parse URI: {}", uri); + return std::unexpected{maybe_req.error()}; } - config.requests.emplace_back(std::move(req)); + config.requests.emplace_back(std::move(*maybe_req)); } - return 0; + return {}; } } // namespace @@ -1919,15 +1932,14 @@ const char *prog = "h09client"; } // namespace namespace { -void print_usage() { - std::cerr << "Usage: " << prog << " [OPTIONS] [...]" - << std::endl; +void print_usage(FILE *out) { + std::println(out, "Usage: {} [OPTIONS] [...]", prog); } } // namespace namespace { void print_help() { - print_usage(); + print_usage(stdout); Config config; @@ -2257,11 +2269,10 @@ int main(int argc, char **argv) { case 'n': // --streams if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "streams: invalid argument" << std::endl; + std::println(stderr, "streams: invalid argument"); exit(EXIT_FAILURE); } else if (*n > NGTCP2_MAX_VARINT) { - std::cerr << "streams: must not exceed " << NGTCP2_MAX_VARINT - << std::endl; + std::println(stderr, "streams: must not exceed {}", NGTCP2_MAX_VARINT); exit(EXIT_FAILURE); } else { config.nstreams = *n; @@ -2295,22 +2306,21 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(optarg); if (!rv) { - std::cerr << "version: invalid version " << std::quoted(optarg) - << std::endl; + std::println(stderr, "version: invalid version {}", optarg); exit(EXIT_FAILURE); } config.version = *rv; break; } case '?': - print_usage(); + print_usage(stderr); exit(EXIT_FAILURE); case 0: switch (flag) { case 1: // --ciphers if (util::crypto_default_ciphers()[0] == '\0') { - std::cerr << "ciphers: not supported" << std::endl; + std::println(stderr, "ciphers: not supported"); exit(EXIT_FAILURE); } config.ciphers = optarg; @@ -2322,7 +2332,7 @@ int main(int argc, char **argv) { case 3: // --timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "timeout: invalid argument" << std::endl; + std::println(stderr, "timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.timeout = *t; @@ -2341,12 +2351,12 @@ int main(int argc, char **argv) { auto hexcid = std::string_view{optarg}; if (hexcid.size() < NGTCP2_MIN_INITIAL_DCIDLEN * 2 || hexcid.size() > NGTCP2_MAX_CIDLEN * 2) { - std::cerr << "dcid: wrong length" << std::endl; + std::println(stderr, "dcid: wrong length"); exit(EXIT_FAILURE); } if (!util::is_hex_string(hexcid)) { - std::cerr << "dcid: not hex string" << std::endl; + std::println(stderr, "dcid: not hex string"); exit(EXIT_FAILURE); } @@ -2359,7 +2369,7 @@ int main(int argc, char **argv) { case 7: // --change-local-addr if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "change-local-addr: invalid argument" << std::endl; + std::println(stderr, "change-local-addr: invalid argument"); exit(EXIT_FAILURE); } else { config.change_local_addr = *t; @@ -2368,7 +2378,7 @@ int main(int argc, char **argv) { case 8: // --key-update if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "key-update: invalid argument" << std::endl; + std::println(stderr, "key-update: invalid argument"); exit(EXIT_FAILURE); } else { config.key_update = *t; @@ -2381,7 +2391,7 @@ int main(int argc, char **argv) { case 10: // --delay-stream if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "delay-stream: invalid argument" << std::endl; + std::println(stderr, "delay-stream: invalid argument"); exit(EXIT_FAILURE); } else { config.delay_stream = *t; @@ -2418,7 +2428,7 @@ int main(int argc, char **argv) { case 18: // --max-data if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-data: invalid argument" << std::endl; + std::println(stderr, "max-data: invalid argument"); exit(EXIT_FAILURE); } else { config.max_data = *n; @@ -2427,8 +2437,7 @@ int main(int argc, char **argv) { case 19: // --max-stream-data-bidi-local if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-local: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-local: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_local = *n; @@ -2437,8 +2446,7 @@ int main(int argc, char **argv) { case 20: // --max-stream-data-bidi-remote if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-remote: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-remote: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_remote = *n; @@ -2447,7 +2455,7 @@ int main(int argc, char **argv) { case 21: // --max-stream-data-uni if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-uni: invalid argument" << std::endl; + std::println(stderr, "max-stream-data-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_uni = *n; @@ -2456,7 +2464,7 @@ int main(int argc, char **argv) { case 22: // --max-streams-bidi if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-bidi: invalid argument" << std::endl; + std::println(stderr, "max-streams-bidi: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_bidi = *n; @@ -2465,7 +2473,7 @@ int main(int argc, char **argv) { case 23: // --max-streams-uni if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-uni: invalid argument" << std::endl; + std::println(stderr, "max-streams-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_uni = *n; @@ -2497,7 +2505,7 @@ int main(int argc, char **argv) { config.cc_algo = NGTCP2_CC_ALGO_BBR; break; } - std::cerr << "cc: specify cubic, reno, or bbr" << std::endl; + std::println(stderr, "cc: specify cubic, reno, or bbr"); exit(EXIT_FAILURE); case 28: // --exit-on-all-streams-close @@ -2514,7 +2522,7 @@ int main(int argc, char **argv) { case 31: // --initial-rtt if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "initial-rtt: invalid argument" << std::endl; + std::println(stderr, "initial-rtt: invalid argument"); exit(EXIT_FAILURE); } else { config.initial_rtt = *t; @@ -2523,7 +2531,7 @@ int main(int argc, char **argv) { case 32: // --max-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-window: invalid argument" << std::endl; + std::println(stderr, "max-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_window = *n; @@ -2532,7 +2540,7 @@ int main(int argc, char **argv) { case 33: // --max-stream-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-window: invalid argument" << std::endl; + std::println(stderr, "max-stream-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_window = *n; @@ -2541,14 +2549,14 @@ int main(int argc, char **argv) { case 35: // --max-udp-payload-size if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-udp-payload-size: invalid argument" << std::endl; + std::println(stderr, "max-udp-payload-size: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println(stderr, "max-udp-payload-size: must not exceed {}", + NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else if (*n == 0) { - std::cerr << "max-udp-payload-size: must not be 0" << std::endl; + std::println(stderr, "max-udp-payload-size: must not be 0"); } else { config.max_udp_payload_size = *n; } @@ -2556,7 +2564,7 @@ int main(int argc, char **argv) { case 36: // --handshake-timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "handshake-timeout: invalid argument" << std::endl; + std::println(stderr, "handshake-timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.handshake_timeout = *t; @@ -2582,8 +2590,7 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "available-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "available-versions: invalid version {}", k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -2598,8 +2605,9 @@ int main(int argc, char **argv) { // --preferred-versions auto l = util::split_str(optarg); if (l.size() > max_preferred_versionslen) { - std::cerr << "preferred-versions: too many versions > " - << max_preferred_versionslen << std::endl; + std::println(stderr, "preferred-versions: too many versions > {}", + max_preferred_versionslen); + exit(EXIT_FAILURE); } config.preferred_versions.resize(l.size()); auto it = std::ranges::begin(config.preferred_versions); @@ -2614,13 +2622,12 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "preferred-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: invalid version {}", k); exit(EXIT_FAILURE); } if (!ngtcp2_is_supported_version(*rv)) { - std::cerr << "preferred-versions: unsupported version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: unsupported version {}", + k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -2630,10 +2637,10 @@ int main(int argc, char **argv) { case 40: // --ack-thresh if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "ack-thresh: invalid argument" << std::endl; + std::println(stderr, "ack-thresh: invalid argument"); exit(EXIT_FAILURE); } else if (*n > 100) { - std::cerr << "ack-thresh: must not exceed 100" << std::endl; + std::println(stderr, "ack-thresh: must not exceed 100"); exit(EXIT_FAILURE); } else { config.ack_thresh = *n; @@ -2646,11 +2653,11 @@ int main(int argc, char **argv) { case 42: // --initial-pkt-num if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "initial-pkt-num: invalid argument" << std::endl; + std::println(stderr, "initial-pkt-num: invalid argument"); exit(EXIT_FAILURE); } else if (*n > INT32_MAX) { - std::cerr << "initial-pkt-num: must not exceed (1 << 31) - 1" - << std::endl; + std::println(stderr, + "initial-pkt-num: must not exceed (1 << 31) - 1"); exit(EXIT_FAILURE); } else { config.initial_pkt_num = static_cast(*n); @@ -2661,14 +2668,13 @@ int main(int argc, char **argv) { auto l = util::split_str(optarg); for (auto &s : l) { if (auto n = util::parse_uint_iec(s); !n) { - std::cerr << "pmtud-probes: invalid argument" << std::endl; + std::println(stderr, "pmtud-probes: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println( + stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", + NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else { config.pmtud_probes.push_back(static_cast(*n)); @@ -2692,13 +2698,13 @@ int main(int argc, char **argv) { // --gso-burst auto n = util::parse_uint(optarg); if (!n) { - std::cerr << "gso-burst: invalid argument" << std::endl; + std::println(stderr, "gso-burst: invalid argument"); exit(EXIT_FAILURE); } if (*n > 64) { - std::cerr << "gso-burst: must be in range [0, 64], inclusive." - << std::endl; + std::println(stderr, + "gso-burst: must be in range [0, 64], inclusive."); exit(EXIT_FAILURE); } @@ -2714,39 +2720,38 @@ int main(int argc, char **argv) { } if (argc - optind < 2) { - std::cerr << "Too few arguments" << std::endl; - print_usage(); + std::println(stderr, "Too few arguments"); + print_usage(stderr); exit(EXIT_FAILURE); } if (!config.qlog_file.empty() && !config.qlog_dir.empty()) { - std::cerr << "qlog-file and qlog-dir are mutually exclusive" << std::endl; + std::println(stderr, "qlog-file and qlog-dir are mutually exclusive"); exit(EXIT_FAILURE); } if (config.exit_on_first_stream_close && config.exit_on_all_streams_close) { - std::cerr << "exit-on-first-stream-close and exit-on-all-streams-close are " - "mutually exclusive" - << std::endl; + std::println(stderr, "exit-on-first-stream-close and " + "exit-on-all-streams-close are mutually exclusive"); exit(EXIT_FAILURE); } if (config.wait_for_ticket && !config.session_file) { - std::cerr << "wait-for-ticket: session-file must be specified" << std::endl; + std::println(stderr, "wait-for-ticket: session-file must be specified"); exit(EXIT_FAILURE); } if (data_path) { auto fd = open(data_path, O_RDONLY); if (fd == -1) { - std::cerr << "data: Could not open file " << data_path << ": " - << strerror(errno) << std::endl; + std::println(stderr, "data: Could not open file {}: {}", data_path, + strerror(errno)); exit(EXIT_FAILURE); } struct stat st; if (fstat(fd, &st) != 0) { - std::cerr << "data: Could not stat file " << data_path << ": " - << strerror(errno) << std::endl; + std::println(stderr, "data: Could not stat file {}: {}", data_path, + strerror(errno)); exit(EXIT_FAILURE); } config.fd = fd; @@ -2754,8 +2759,8 @@ int main(int argc, char **argv) { if (config.datalen) { auto addr = mmap(nullptr, config.datalen, PROT_READ, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { - std::cerr << "data: Could not mmap file " << data_path << ": " - << strerror(errno) << std::endl; + std::println(stderr, "data: Could not mmap file {}: {}", data_path, + strerror(errno)); exit(EXIT_FAILURE); } config.data = static_cast(addr); @@ -2765,8 +2770,8 @@ int main(int argc, char **argv) { if (config.ech_config_list_file) { auto ech_config = util::read_file(config.ech_config_list_file); if (!ech_config) { - std::cerr << "ech-config-list-file: Could not read ECHConfigList" - << std::endl; + std::println(stderr, + "ech-config-list-file: Could not read ECHConfigList"); } else { config.ech_config_list = std::move(*ech_config); } @@ -2775,7 +2780,7 @@ int main(int argc, char **argv) { auto addr = argv[optind++]; auto port = argv[optind++]; - if (parse_requests(&argv[optind], static_cast(argc - optind)) != 0) { + if (!parse_requests(&argv[optind], static_cast(argc - optind))) { exit(EXIT_FAILURE); } @@ -2783,16 +2788,16 @@ int main(int argc, char **argv) { if (!config.preferred_versions.empty() && std::ranges::find(config.preferred_versions, config.version) == std::ranges::end(config.preferred_versions)) { - std::cerr << "preferred-version: must include version " << std::hex - << "0x" << config.version << std::dec << std::endl; + std::println(stderr, "preferred-version: must include version {:#x}", + config.version); exit(EXIT_FAILURE); } if (!config.available_versions.empty() && std::ranges::find(config.available_versions, config.version) == std::ranges::end(config.available_versions)) { - std::cerr << "available-versions: must include version " << std::hex - << "0x" << config.version << std::dec << std::endl; + std::println(stderr, "available-versions: must include version {:#x}", + config.version); exit(EXIT_FAILURE); } } @@ -2802,7 +2807,7 @@ int main(int argc, char **argv) { } TLSClientContext tls_ctx; - if (tls_ctx.init(private_key_file, cert_file) != 0) { + if (!tls_ctx.init(private_key_file, cert_file)) { exit(EXIT_FAILURE); } @@ -2816,8 +2821,8 @@ int main(int argc, char **argv) { } } - if (util::generate_secret(config.static_secret) != 0) { - std::cerr << "Unable to generate static secret" << std::endl; + if (!util::generate_secure_random(config.static_secret)) { + std::println(stderr, "Unable to generate static secret"); exit(EXIT_FAILURE); } @@ -2826,7 +2831,7 @@ int main(int argc, char **argv) { for (;;) { Client c(EV_DEFAULT, client_chosen_version, config.version); - if (run(c, addr, port, tls_ctx) != 0) { + if (!run(c, addr, port, tls_ctx)) { exit(EXIT_FAILURE); } @@ -2844,13 +2849,13 @@ int main(int argc, char **argv) { offered_versions.data(), offered_versions.size()); if (client_chosen_version == 0) { - std::cerr << "Unable to select a version" << std::endl; + std::println(stderr, "Unable to select a version"); exit(EXIT_FAILURE); } if (!config.quiet) { - std::cerr << "Client selected version " << std::hex << "0x" - << client_chosen_version << std::dec << std::endl; + std::println(stderr, "Client selected version {:#x}", + client_chosen_version); } } diff --git a/deps/ngtcp2/ngtcp2/examples/h09client.h b/deps/ngtcp2/ngtcp2/examples/h09client.h index 4fa848e4126345..7e0afee3050083 100644 --- a/deps/ngtcp2/ngtcp2/examples/h09client.h +++ b/deps/ngtcp2/ngtcp2/examples/h09client.h @@ -57,7 +57,7 @@ struct Stream { Stream(const Request &req, int64_t stream_id); ~Stream(); - int open_file(const std::string_view &path); + std::expected open_file(std::string_view path); Request req; int64_t stream_id; @@ -87,63 +87,71 @@ class Client : public ClientBase { uint32_t original_version); ~Client(); - int init(int fd, const Address &local_addr, const Address &remote_addr, - const char *addr, const char *port, TLSClientContext &tls_ctx); + std::expected init(int fd, const Address &local_addr, + const Address &remote_addr, const char *addr, + const char *port, TLSClientContext &tls_ctx); void disconnect(); - int on_read(const Endpoint &ep); - int on_write(); - int write_streams(); - int feed_data(const Endpoint &ep, const sockaddr *sa, socklen_t salen, - const ngtcp2_pkt_info *pi, std::span data); - int handle_expiry(); + std::expected on_read(const Endpoint &ep); + std::expected on_write(); + std::expected write_streams(); + std::expected feed_data(const Endpoint &ep, const sockaddr *sa, + socklen_t salen, + const ngtcp2_pkt_info *pi, + std::span data); + std::expected handle_expiry(); void update_timer(); - int handshake_completed(); - int handshake_confirmed(); + std::expected handshake_completed(); + void handshake_confirmed(); void recv_version_negotiation(const uint32_t *sv, size_t nsv); - int send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, - unsigned int ecn, std::span data); - std::pair, int> + std::expected send_packet(const Endpoint &ep, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data); + std::span send_packet(const Endpoint &ep, const ngtcp2_addr &remote_addr, unsigned int ecn, std::span data, size_t gso_size); - int send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size); - int on_stream_close(int64_t stream_id, uint64_t app_error_code); - int on_extend_max_streams(); - int handle_error(); - int make_stream_early(); - int change_local_addr(); + std::expected + send_packet_or_blocked(const ngtcp2_path &path, unsigned int ecn, + std::span data, size_t gso_size); + void on_stream_close(int64_t stream_id, uint64_t app_error_code); + void on_extend_max_streams(); + std::expected handle_error(); + void make_stream_early(); + std::expected change_local_addr(); void start_change_local_addr_timer(); - int update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen); - int initiate_key_update(); + std::expected + update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, + size_t secretlen); + std::expected initiate_key_update(); void start_key_update_timer(); void start_delay_stream_timer(); - int select_preferred_address(Address &selected_addr, - const ngtcp2_preferred_addr *paddr); + std::expected + select_preferred_address(Address &selected_addr, + const ngtcp2_preferred_addr *paddr); - std::optional endpoint_for(const Address &remote_addr); + std::expected endpoint_for(const Address &remote_addr); void set_remote_addr(const ngtcp2_addr &remote_addr); - int submit_http_request(Stream *stream); - int recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data); - int acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen); - int extend_max_stream_data(int64_t stream_id, uint64_t max_data); + void submit_http_request(Stream *stream); + void recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + void acked_stream_data_offset(int64_t stream_id, uint64_t offset, + uint64_t datalen); + void extend_max_stream_data(int64_t stream_id, uint64_t max_data); void write_qlog(const void *data, size_t datalen); void on_send_blocked(const ngtcp2_path &path, unsigned int ecn, std::span data, size_t gso_size); void start_wev_endpoint(const Endpoint &ep); - int send_blocked_packet(); + void send_blocked_packet(); ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts); diff --git a/deps/ngtcp2/ngtcp2/examples/h09server.cc b/deps/ngtcp2/ngtcp2/examples/h09server.cc index 6f6102ac7d2011..3636d4e064dfc6 100644 --- a/deps/ngtcp2/ngtcp2/examples/h09server.cc +++ b/deps/ngtcp2/ngtcp2/examples/h09server.cc @@ -112,14 +112,14 @@ struct Request { }; namespace { -Request request_path(const std::string_view &uri) { +Request request_path(std::string_view uri) { urlparse_url u; Request req; if (auto rv = urlparse_parse_url(uri.data(), uri.size(), /* is_connect = */ 0, &u); rv != 0) { - return req; + return {}; } if (u.field_set & (1 << URLPARSE_PATH)) { @@ -127,15 +127,24 @@ Request request_path(const std::string_view &uri) { if (req.path.find('%') != std::string::npos) { req.path = util::percent_decode(req.path); } - if (!req.path.empty() && req.path.back() == '/') { + + assert(!req.path.empty()); + + if (req.path[0] != '/') { + return {}; + } + + if (req.path.back() == '/') { req.path += "index.html"; } - } else { - req.path = "/index.html"; - } - req.path = util::normalize_path(req.path); - if (req.path == "/") { + auto maybe_norm_path = util::normalize_path(req.path); + if (!maybe_norm_path) { + return {}; + } + + req.path = std::move(*maybe_norm_path); + } else { req.path = "/index.html"; } @@ -158,21 +167,21 @@ namespace { std::unordered_map file_cache; } // namespace -std::pair Stream::open_file(const std::string &path) { +std::expected Stream::open_file(const std::string &path) { auto it = file_cache.find(path); if (it != std::ranges::end(file_cache)) { - return {(*it).second, 0}; + return (*it).second; } auto fd = open(path.c_str(), O_RDONLY); if (fd == -1) { - return {{}, -1}; + return std::unexpected{Error::SYSCALL}; } struct stat st{}; if (fstat(fd, &st) != 0) { close(fd); - return {{}, -1}; + return std::unexpected{Error::SYSCALL}; } FileEntry fe; @@ -186,16 +195,16 @@ std::pair Stream::open_file(const std::string &path) { if (fe.len) { fe.map = mmap(nullptr, fe.len, PROT_READ, MAP_SHARED, fd, 0); if (fe.map == MAP_FAILED) { - std::cerr << "mmap: " << strerror(errno) << std::endl; + std::println(stderr, "mmap: {}", strerror(errno)); close(fd); - return {{}, -1}; + return std::unexpected{Error::SYSCALL}; } } } file_cache.emplace(path, fe); - return {std::move(fe), 0}; + return fe; } void Stream::map_file(const FileEntry &fe) { @@ -203,7 +212,7 @@ void Stream::map_file(const FileEntry &fe) { respbuf.end = respbuf.last = respbuf.begin + fe.len; } -int Stream::send_status_response(unsigned int status_code) { +void Stream::send_status_response(unsigned int status_code) { status_resp_body = make_status_body(status_code); respbuf.begin = respbuf.pos = @@ -212,30 +221,32 @@ int Stream::send_status_response(unsigned int status_code) { handler->add_sendq(this); handler->shutdown_read(stream_id, 0); - - return 0; } -int Stream::start_response() { +void Stream::start_response() { if (uri.empty()) { - return send_status_response(400); + send_status_response(400); + return; } auto req = request_path(uri); if (req.path.empty()) { - return send_status_response(400); + send_status_response(400); + return; } auto path = config.htdocs + req.path; - auto [fe, rv] = open_file(path); - if (rv != 0) { + auto maybe_fe = open_file(path); + if (!maybe_fe) { send_status_response(404); - return 0; + return; } + const auto &fe = *maybe_fe; + if (fe.flags & FILE_ENTRY_TYPE_DIR) { send_status_response(308); - return 0; + return; } map_file(fe); @@ -249,8 +260,6 @@ int Stream::start_response() { } handler->add_sendq(this); - - return 0; } namespace { @@ -258,11 +267,7 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) { auto h = static_cast(w->data); auto s = h->server(); - switch (h->on_write()) { - case 0: - case NETWORK_ERR_CLOSE_WAIT: - return; - default: + if (auto rv = h->on_write(); !rv && rv.error() != Error::CLOSE_WAIT) { s->remove(h); } } @@ -276,7 +281,7 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { if (ngtcp2_conn_in_closing_period(conn)) { if (!config.quiet) { - std::cerr << "Closing Period is over" << std::endl; + std::println(stderr, "Closing Period is over"); } s->remove(h); @@ -284,7 +289,7 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { } if (ngtcp2_conn_in_draining_period(conn)) { if (!config.quiet) { - std::cerr << "Draining Period is over" << std::endl; + std::println(stderr, "Draining Period is over"); } s->remove(h); @@ -297,33 +302,24 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { namespace { void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { - int rv; - auto h = static_cast(w->data); auto s = h->server(); if (!config.quiet) { - std::cerr << "Timer expired" << std::endl; + std::println(stderr, "Timer expired"); } - rv = h->handle_expiry(); - if (rv != 0) { - goto fail; - } - - h->signal_write(); - - return; + if (auto rv = h->handle_expiry(); !rv) { + if (rv.error() == Error::CLOSE_WAIT) { + ev_timer_stop(loop, w); + } else { + s->remove(h); + } -fail: - switch (rv) { - case NETWORK_ERR_CLOSE_WAIT: - ev_timer_stop(loop, w); - return; - default: - s->remove(h); return; } + + h->signal_write(); } } // namespace @@ -345,7 +341,7 @@ Handler::Handler(struct ev_loop *loop, Server *server) Handler::~Handler() { if (!config.quiet) { - std::cerr << scid_ << " Closing QUIC connection " << std::endl; + std::println(stderr, "{} Closing QUIC connection", scid_); } ev_timer_stop(loop_, &timer_); @@ -364,7 +360,7 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { debug::handshake_completed(conn, user_data); } - if (h->handshake_completed() != 0) { + if (!h->handshake_completed()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -372,19 +368,19 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { } } // namespace -int Handler::handshake_completed() { +std::expected Handler::handshake_completed() { if (!config.quiet) { - std::cerr << "Negotiated cipher suite is " << tls_session_.get_cipher_name() - << std::endl; + std::println(stderr, "Negotiated cipher suite is {}", + tls_session_.get_cipher_name()); if (auto group = tls_session_.get_negotiated_group(); !group.empty()) { - std::cerr << "Negotiated group is " << group << std::endl; + std::println(stderr, "Negotiated group is {}", group); } - std::cerr << "Negotiated ALPN is " << tls_session_.get_selected_alpn() - << std::endl; + std::println(stderr, "Negotiated ALPN is {}", + tls_session_.get_selected_alpn()); } - if (tls_session_.send_session_ticket() != 0) { - std::cerr << "Unable to send session ticket" << std::endl; + if (!tls_session_.send_session_ticket()) { + std::println(stderr, "Unable to send session ticket"); } std::array token; @@ -396,21 +392,21 @@ int Handler::handshake_completed() { token.data(), config.static_secret.data(), config.static_secret.size(), path->remote.addr, path->remote.addrlen, t); if (tokenlen < 0) { - std::cerr << "Unable to generate token" << std::endl; + std::println(stderr, "Unable to generate token"); - return 0; + return std::unexpected{Error::QUIC}; } if (auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(), as_unsigned(tokenlen)); rv != 0) { - std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_submit_new_token: {}", + ngtcp2_strerror(rv)); - return -1; + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } namespace { @@ -448,7 +444,7 @@ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->recv_stream_data(flags, stream_id, {data, datalen}) != 0) { + if (!h->recv_stream_data(flags, stream_id, {data, datalen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -461,15 +457,15 @@ int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id, uint64_t offset, uint64_t datalen, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->acked_stream_data_offset(stream_id, offset, datalen) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + + h->acked_stream_data_offset(stream_id, offset, datalen); + return 0; } } // namespace -int Handler::acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen) { +void Handler::acked_stream_data_offset(int64_t stream_id, uint64_t offset, + uint64_t datalen) { auto it = streams_.find(stream_id); assert(it != std::ranges::end(streams_)); auto &stream = (*it).second; @@ -477,8 +473,6 @@ int Handler::acked_stream_data_offset(int64_t stream_id, uint64_t offset, assert(static_cast(stream->respbuf.end - stream->respbuf.begin) >= offset + datalen); - - return 0; } namespace { @@ -504,17 +498,16 @@ int 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 h = static_cast(user_data); - if (h->on_stream_close(stream_id, app_error_code) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + + h->on_stream_close(stream_id, app_error_code); + return 0; } } // namespace namespace { void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { - auto rv = util::generate_secure_random({dest, destlen}); - if (rv != 0) { + if (!util::generate_secure_random({dest, destlen})) { assert(0); abort(); } @@ -522,16 +515,17 @@ void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { } // namespace namespace { -int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token, - size_t cidlen, void *user_data) { - if (util::generate_secure_random({cid->data, cidlen}) != 0) { +int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, + ngtcp2_stateless_reset_token *token, size_t cidlen, + void *user_data) { + if (!util::generate_secure_random({cid->data, cidlen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } cid->datalen = cidlen; if (ngtcp2_crypto_generate_stateless_reset_token( - token, config.static_secret.data(), config.static_secret.size(), cid) != - 0) { + token->data, config.static_secret.data(), config.static_secret.size(), + cid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -559,9 +553,8 @@ int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, const uint8_t *current_tx_secret, size_t secretlen, void *user_data) { auto h = static_cast(user_data); - if (h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, - tx_iv, current_rx_secret, current_tx_secret, - secretlen) != 0) { + if (!h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, + tx_iv, current_rx_secret, current_tx_secret, secretlen)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; @@ -588,7 +581,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) { - std::cerr << "Unable to generate token" << std::endl; + std::println(stderr, "Unable to generate token"); return 0; } @@ -596,8 +589,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) { - std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_submit_new_token: {}", + ngtcp2_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -611,14 +604,14 @@ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, uint64_t max_data, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->extend_max_stream_data(stream_id, max_data) != 0) { - return NGTCP2_ERR_CALLBACK_FAILURE; - } + + h->extend_max_stream_data(stream_id, max_data); + return 0; } } // namespace -int Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { +void Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { auto it = streams_.find(stream_id); assert(it != std::ranges::end(streams_)); auto &stream = (*it).second; @@ -626,8 +619,6 @@ int Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { if (nghttp3_buf_len(&stream->respbuf)) { sendq_.emplace(stream.get()); } - - return 0; } namespace { @@ -643,11 +634,12 @@ void Handler::write_qlog(const void *data, size_t datalen) { fwrite(data, 1, datalen, qlog_); } -int Handler::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 token, ngtcp2_token_type token_type, - uint32_t version, TLSServerContext &tls_ctx) { +std::expected +Handler::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 token, ngtcp2_token_type token_type, + uint32_t version, TLSServerContext &tls_ctx) { auto callbacks = ngtcp2_callbacks{ .recv_client_initial = ngtcp2_crypto_recv_client_initial_cb, .recv_crypto_data = ::recv_crypto_data, @@ -660,21 +652,22 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, .stream_open = stream_open, .stream_close = stream_close, .rand = rand, - .get_new_connection_id = get_new_connection_id, .remove_connection_id = remove_connection_id, .update_key = ::update_key, .path_validation = path_validation, .extend_max_stream_data = ::extend_max_stream_data, .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, + .get_new_connection_id2 = get_new_connection_id, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; scid_.datalen = NGTCP2_SV_SCIDLEN; - if (util::generate_secure_random({scid_.data, scid_.datalen}) != 0) { - std::cerr << "Could not generate connection ID" << std::endl; - return -1; + if (auto rv = util::generate_secure_random({scid_.data, scid_.datalen}); + !rv) { + std::println(stderr, "Could not generate connection ID"); + return rv; } ngtcp2_settings settings; @@ -702,9 +695,9 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, path += ".sqlog"; qlog_ = fopen(path.c_str(), "w"); if (qlog_ == nullptr) { - std::cerr << "Could not open qlog file " << std::quoted(path) << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "Could not open qlog file {}: {}", path, + strerror(errno)); + return std::unexpected{Error::IO}; } settings.qlog_write = ::write_qlog; } @@ -760,7 +753,7 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, if (ngtcp2_crypto_generate_stateless_reset_token( params.stateless_reset_token, config.static_secret.data(), config.static_secret.size(), &scid_) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } if (!config.preferred_ipv4_addr.empty() || @@ -779,20 +772,21 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, params.preferred_addr.ipv6_present = 1; } - if (util::generate_secure_random( - params.preferred_addr.stateless_reset_token) != 0) { - std::cerr << "Could not generate preferred address stateless reset token" - << std::endl; - return -1; + if (auto rv = util::generate_secure_random( + params.preferred_addr.stateless_reset_token); + !rv) { + std::println( + stderr, "Could not generate preferred address stateless reset token"); + return rv; } params.preferred_addr.cid.datalen = NGTCP2_SV_SCIDLEN; - if (util::generate_secure_random({params.preferred_addr.cid.data, - params.preferred_addr.cid.datalen}) != - 0) { - std::cerr << "Could not generate preferred address connection ID" - << std::endl; - return -1; + if (auto rv = util::generate_secure_random( + {params.preferred_addr.cid.data, params.preferred_addr.cid.datalen}); + !rv) { + std::println(stderr, + "Could not generate preferred address connection ID"); + return rv; } } @@ -805,12 +799,12 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, ngtcp2_conn_server_new(&conn_, dcid, &scid_, &path, version, &callbacks, &settings, ¶ms, nullptr, this); rv != 0) { - std::cerr << "ngtcp2_conn_server_new: " << ngtcp2_strerror(rv) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_server_new: {}", ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - if (tls_session_.init(tls_ctx, this) != 0) { - return -1; + if (auto rv = tls_session_.init(tls_ctx, this); !rv) { + return rv; } tls_session_.enable_keylog(); @@ -819,12 +813,14 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, ev_io_set(&wev_, ep.fd, EV_WRITE); - return 0; + return {}; } -int Handler::feed_data(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data) { +std::expected Handler::feed_data(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data) { auto path = ngtcp2_path{ .local = as_ngtcp2_addr(local_addr), .remote = as_ngtcp2_addr(remote_addr), @@ -834,15 +830,15 @@ int Handler::feed_data(const Endpoint &ep, const Address &local_addr, if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(), util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); switch (rv) { case NGTCP2_ERR_DRAINING: start_draining_period(); - return NETWORK_ERR_CLOSE_WAIT; + return std::unexpected{Error::CLOSE_WAIT}; case NGTCP2_ERR_RETRY: - return NETWORK_ERR_RETRY; + return std::unexpected{Error::RETRY_CONN}; case NGTCP2_ERR_DROP_CONN: - return NETWORK_ERR_DROP_CONN; + return std::unexpected{Error::DROP_CONN}; case NGTCP2_ERR_CRYPTO: if (!last_error_.error_code) { ngtcp2_ccerr_set_tls_alert( @@ -857,58 +853,57 @@ int Handler::feed_data(const Endpoint &ep, const Address &local_addr, return handle_error(); } - return 0; + return {}; } -int Handler::on_read(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data) { - if (auto rv = feed_data(ep, local_addr, remote_addr, pi, data); rv != 0) { +std::expected Handler::on_read(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data) { + if (auto rv = feed_data(ep, local_addr, remote_addr, pi, data); !rv) { return rv; } update_timer(); - return 0; + return {}; } -int Handler::handle_expiry() { +std::expected Handler::handle_expiry() { auto now = util::timestamp(); if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) { - std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_handle_expiry: {}", ngtcp2_strerror(rv)); ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); return handle_error(); } - return 0; + return {}; } -int Handler::on_write() { +std::expected Handler::on_write() { if (ngtcp2_conn_in_closing_period(conn_) || ngtcp2_conn_in_draining_period(conn_)) { - return 0; + return {}; } if (tx_.send_blocked) { - if (auto rv = send_blocked_packet(); rv != 0) { - return rv; - } + send_blocked_packet(); if (tx_.send_blocked) { - return 0; + return {}; } } ev_io_stop(loop_, &wev_); - if (auto rv = write_streams(); rv != 0) { + if (auto rv = write_streams(); !rv) { return rv; } update_timer(); - return 0; + return {}; } namespace { @@ -966,8 +961,8 @@ ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, assert(ndatalen == -1); - std::cerr << "ngtcp2_conn_writev_stream: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, 0); @@ -985,7 +980,7 @@ ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, } } -int Handler::write_streams() { +std::expected Handler::write_streams() { ngtcp2_path_storage ps; ngtcp2_pkt_info pi; size_t gso_size; @@ -1005,31 +1000,31 @@ int Handler::write_streams() { ngtcp2_conn_update_pkt_tx_time(conn_, ts); if (nwrite == 0) { - return 0; + return {}; } send_packet(ps.path, pi.ecn, txbuf.first(static_cast(nwrite)), gso_size); - return 0; + return {}; } -int Handler::send_packet(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size) { +std::expected Handler::send_packet(const ngtcp2_path &path, + unsigned int ecn, + std::span data, + size_t gso_size) { auto &ep = *static_cast(path.user_data); - auto [rest, rv] = server_->send_packet(ep, no_gso_, path.local, path.remote, - ecn, data, gso_size); - if (rv != 0) { - assert(NETWORK_ERR_SEND_BLOCKED == rv); - + auto rest = server_->send_packet(ep, no_gso_, path.local, path.remote, ecn, + data, gso_size); + if (!rest.empty()) { on_send_blocked(path, ecn, rest, gso_size); start_wev_endpoint(ep); - return rv; + return std::unexpected{Error::SEND_BLOCKED}; } - return 0; + return {}; } void Handler::on_send_blocked(const ngtcp2_path &path, unsigned int ecn, @@ -1064,27 +1059,23 @@ void Handler::start_wev_endpoint(const Endpoint &ep) { ev_io_start(loop_, &wev_); } -int Handler::send_blocked_packet() { +void Handler::send_blocked_packet() { assert(tx_.send_blocked); auto &p = tx_.blocked; - auto [rest, rv] = server_->send_packet( + auto rest = server_->send_packet( *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); - + if (!rest.empty()) { p.data = rest; start_wev_endpoint(*p.endpoint); - return 0; + return; } tx_.send_blocked = false; - - return 0; } void Handler::signal_write() { ev_io_start(loop_, &wev_); } @@ -1098,15 +1089,15 @@ void Handler::start_draining_period() { ev_timer_again(loop_, &timer_); if (!config.quiet) { - std::cerr << "Draining period has started (" << timer_.repeat << " seconds)" - << std::endl; + std::println(stderr, "Draining period has started ({:.9f} seconds)", + timer_.repeat); } } -int Handler::start_closing_period() { +std::expected Handler::start_closing_period() { if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || ngtcp2_conn_in_draining_period(conn_)) { - return 0; + return {}; } ev_io_stop(loop_, &wev_); @@ -1117,8 +1108,8 @@ int Handler::start_closing_period() { ev_timer_again(loop_, &timer_); if (!config.quiet) { - std::cerr << "Closing period has started (" << timer_.repeat << " seconds)" - << std::endl; + std::println(stderr, "Closing period has started ({:.9f} seconds)", + timer_.repeat); } conn_closebuf_ = std::make_unique(NGTCP2_MAX_UDP_PAYLOAD_SIZE); @@ -1132,43 +1123,43 @@ int Handler::start_closing_period() { conn_, &ps.path, &pi, conn_closebuf_->wpos(), conn_closebuf_->left(), &last_error_, util::timestamp()); if (n < 0) { - std::cerr << "ngtcp2_conn_write_connection_close: " - << ngtcp2_strerror(static_cast(n)) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_write_connection_close: {}", + ngtcp2_strerror(static_cast(n))); + return std::unexpected{Error::QUIC}; } if (n == 0) { - return 0; + return {}; } conn_closebuf_->push(as_unsigned(n)); - return 0; + return {}; } -int Handler::handle_error() { +std::expected Handler::handle_error() { if (last_error_.type == NGTCP2_CCERR_TYPE_IDLE_CLOSE) { - return -1; + return std::unexpected{Error::INTERNAL}; } - if (start_closing_period() != 0) { - return -1; + if (auto rv = start_closing_period(); !rv) { + return rv; } if (ngtcp2_conn_in_draining_period(conn_)) { - return NETWORK_ERR_CLOSE_WAIT; + return std::unexpected{Error::CLOSE_WAIT}; } - if (auto rv = send_conn_close(); rv != NETWORK_ERR_OK) { + if (auto rv = send_conn_close(); !rv) { return rv; } - return NETWORK_ERR_CLOSE_WAIT; + return std::unexpected{Error::CLOSE_WAIT}; } -int Handler::send_conn_close() { +std::expected Handler::send_conn_close() { if (!config.quiet) { - std::cerr << "Closing Period: TX CONNECTION_CLOSE" << std::endl; + std::println(stderr, "Closing Period: TX CONNECTION_CLOSE"); } assert(conn_closebuf_ && conn_closebuf_->size()); @@ -1182,10 +1173,10 @@ int Handler::send_conn_close() { /* ecn = */ 0, conn_closebuf_->data()); } -int Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, - const ngtcp2_pkt_info *pi, - std::span data) { +std::expected +Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, + const Address &remote_addr, const ngtcp2_pkt_info *pi, + std::span data) { assert(conn_closebuf_ && conn_closebuf_->size()); close_wait_.bytes_recv += data.size(); @@ -1194,20 +1185,20 @@ int Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, if (close_wait_.num_pkts_recv < close_wait_.next_pkts_recv || close_wait_.bytes_recv * 3 < close_wait_.bytes_sent + conn_closebuf_->size()) { - return 0; + return {}; } - auto rv = server_->send_packet(ep, as_ngtcp2_addr(local_addr), - as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, conn_closebuf_->data()); - if (rv != 0) { + if (auto rv = server_->send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, conn_closebuf_->data()); + !rv) { return rv; } close_wait_.bytes_sent += conn_closebuf_->size(); close_wait_.next_pkts_recv *= 2; - return 0; + return {}; } void Handler::update_timer() { @@ -1217,8 +1208,7 @@ void Handler::update_timer() { if (expiry <= now) { if (!config.quiet) { auto t = static_cast(now - expiry) / NGTCP2_SECONDS; - std::cerr << "Timer has already expired: " << std::fixed << t << "s" - << std::defaultfloat << std::endl; + std::println(stderr, "Timer has already expired: {:.9f}s", t); } ev_feed_event(loop_, &timer_, EV_TIMER); @@ -1228,8 +1218,7 @@ void Handler::update_timer() { auto t = static_cast(expiry - now) / NGTCP2_SECONDS; if (!config.quiet) { - std::cerr << "Set timer=" << std::fixed << t << "s" << std::defaultfloat - << std::endl; + std::println(stderr, "Set timer={:.9f}s", t); } timer_.repeat = t; ev_timer_again(loop_, &timer_); @@ -1257,9 +1246,7 @@ namespace { int on_msg_complete(http_parser *htp) { auto s = static_cast(htp->data); s->eos = true; - if (s->start_response() != 0) { - return -1; - } + s->start_response(); return 0; } } // namespace @@ -1270,8 +1257,9 @@ auto htp_settings = http_parser_settings{ .on_message_complete = on_msg_complete, }; -int Handler::recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data) { +std::expected +Handler::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { if (!config.quiet && !config.no_quic_dump) { debug::print_stream_data(stream_id, data); } @@ -1288,10 +1276,10 @@ int Handler::recv_stream_data(uint32_t flags, int64_t stream_id, if (auto rv = ngtcp2_conn_shutdown_stream(conn_, 0, stream_id, /* app error code */ 1); rv != 0) { - std::cerr << "ngtcp2_conn_shutdown_stream: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_shutdown_stream: {}", + ngtcp2_strerror(rv)); ngtcp2_ccerr_set_liberr(&last_error_, NGTCP2_ERR_INTERNAL, nullptr, 0); - return -1; + return std::unexpected{Error::QUIC}; } } } @@ -1299,14 +1287,15 @@ int Handler::recv_stream_data(uint32_t flags, int64_t stream_id, ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, data.size()); ngtcp2_conn_extend_max_offset(conn_, data.size()); - return 0; + return {}; } -int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen) { +std::expected +Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, + const uint8_t *current_tx_secret, size_t secretlen) { auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); auto aead = &crypto_ctx->aead; auto keylen = ngtcp2_crypto_aead_keylen(aead); @@ -1320,26 +1309,26 @@ int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), tx_iv, current_rx_secret, current_tx_secret, secretlen) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } if (!config.quiet && config.show_secret) { - std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic rx secret {}", nkey_update_); debug::print_secrets({rx_secret, secretlen}, {rx_key.data(), keylen}, {rx_iv, ivlen}); - std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic tx secret {}", nkey_update_); debug::print_secrets({tx_secret, secretlen}, {tx_key.data(), keylen}, {tx_iv, ivlen}); } - return 0; + return {}; } Server *Handler::server() const { return server_; } -int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) { +void Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) { if (!config.quiet) { - std::cerr << "QUIC stream " << stream_id << " closed" << std::endl; + std::println(stderr, "QUIC stream {:#x} closed", stream_id); } auto it = streams_.find(stream_id); @@ -1349,8 +1338,8 @@ int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) { sendq_.erase(stream.get()); if (!config.quiet) { - std::cerr << "HTTP stream " << stream_id << " closed with error code " - << app_error_code << std::endl; + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); } streams_.erase(it); @@ -1359,8 +1348,6 @@ int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) { assert(!ngtcp2_conn_is_local_stream(conn_, stream_id)); ngtcp2_conn_extend_max_streams_bidi(conn_, 1); } - - return 0; } void Handler::shutdown_read(int64_t stream_id, uint64_t app_error_code) { @@ -1432,8 +1419,8 @@ void Server::close() { } namespace { -int create_sock(Address &local_addr, const char *addr, const char *port, - int family) { +std::expected create_sock(Address &local_addr, const char *addr, + const char *port, int family) { addrinfo hints{ .ai_flags = AI_PASSIVE, .ai_family = family, @@ -1447,8 +1434,8 @@ int create_sock(Address &local_addr, const char *addr, const char *port, } if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } auto res_d = defer([res] { freeaddrinfo(res); }); @@ -1456,12 +1443,14 @@ int create_sock(Address &local_addr, const char *addr, const char *port, int fd = -1; for (rp = res; rp; rp = rp->ai_next) { - fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (fd == -1) { + auto maybe_fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (!maybe_fd) { continue; } + fd = *maybe_fd; + if (rp->ai_family == AF_INET6) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, static_cast(sizeof(val))) == -1) { @@ -1499,16 +1488,16 @@ int create_sock(Address &local_addr, const char *addr, const char *port, } if (!rp) { - std::cerr << "Could not bind" << std::endl; - return -1; + std::println(stderr, "Could not bind"); + return std::unexpected{Error::SYSCALL}; } sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::cerr << "getsockname: " << strerror(errno) << std::endl; + std::println(stderr, "getsockname: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } local_addr.set(reinterpret_cast(&ss)); @@ -1519,61 +1508,65 @@ int create_sock(Address &local_addr, const char *addr, const char *port, } // namespace namespace { -int add_endpoint(std::vector &endpoints, const char *addr, - const char *port, int af) { +std::expected add_endpoint(std::vector &endpoints, + const char *addr, const char *port, + int af) { Address dest; - auto fd = create_sock(dest, addr, port, af); - if (fd == -1) { - return -1; + auto maybe_fd = create_sock(dest, addr, port, af); + if (!maybe_fd) { + return std::unexpected{maybe_fd.error()}; } endpoints.emplace_back(); auto &ep = endpoints.back(); ep.addr = dest; - ep.fd = fd; + ep.fd = *maybe_fd; ev_io_init(&ep.rev, sreadcb, 0, EV_READ); ev_set_priority(&ep.rev, EV_MAXPRI); - return 0; + return {}; } } // namespace namespace { -int add_endpoint(std::vector &endpoints, const Address &addr) { +std::expected add_endpoint(std::vector &endpoints, + const Address &addr) { 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; + auto maybe_fd = util::create_nonblock_socket(family, SOCK_DGRAM, 0); + if (!maybe_fd) { + std::println(stderr, "socket: {}", strerror(errno)); + return std::unexpected{maybe_fd.error()}; } + auto fd = *maybe_fd; + int val = 1; if (family == AF_INET6) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, static_cast(sizeof(val))) == -1) { close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } fd_set_recv_ecn(fd, family); @@ -1582,9 +1575,9 @@ int add_endpoint(std::vector &endpoints, const Address &addr) { fd_set_udp_gro(fd); if (bind(fd, addr.as_sockaddr(), addr.size()) == -1) { - std::cerr << "bind: " << strerror(errno) << std::endl; + std::println(stderr, "bind: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } endpoints.emplace_back(Endpoint{}); @@ -1594,33 +1587,44 @@ int add_endpoint(std::vector &endpoints, const Address &addr) { ev_io_init(&ep.rev, sreadcb, 0, EV_READ); ev_set_priority(&ep.rev, EV_MAXPRI); - return 0; + return {}; } } // namespace -int Server::init(const char *addr, const char *port) { +std::expected Server::init(const char *addr, const char *port) { endpoints_.reserve(4); auto ready = false; - if (!util::numeric_host(addr, AF_INET6) && - add_endpoint(endpoints_, addr, port, AF_INET) == 0) { - ready = true; + auto error = Error::INTERNAL; + + if (!util::numeric_host(addr, AF_INET6)) { + if (auto rv = add_endpoint(endpoints_, addr, port, AF_INET); !rv) { + error = rv.error(); + } else { + ready = true; + } } - if (!util::numeric_host(addr, AF_INET) && - add_endpoint(endpoints_, addr, port, AF_INET6) == 0) { - ready = true; + if (!util::numeric_host(addr, AF_INET)) { + if (auto rv = add_endpoint(endpoints_, addr, port, AF_INET6); !rv) { + error = rv.error(); + } else { + ready = true; + } } if (!ready) { - return -1; + return std::unexpected{error}; } - if (!config.preferred_ipv4_addr.empty() && - add_endpoint(endpoints_, config.preferred_ipv4_addr) != 0) { - return -1; + if (!config.preferred_ipv4_addr.empty()) { + if (auto rv = add_endpoint(endpoints_, config.preferred_ipv4_addr); !rv) { + return rv; + } } - if (!config.preferred_ipv6_addr.empty() && - add_endpoint(endpoints_, config.preferred_ipv6_addr) != 0) { - return -1; + + if (!config.preferred_ipv6_addr.empty()) { + if (auto rv = add_endpoint(endpoints_, config.preferred_ipv6_addr); !rv) { + return rv; + } } for (auto &ep : endpoints_) { @@ -1634,10 +1638,10 @@ int Server::init(const char *addr, const char *port) { ev_signal_start(loop_, &sigintev_); - return 0; + return {}; } -int Server::on_read(const Endpoint &ep) { +void Server::on_read(const Endpoint &ep) { sockaddr_storage ss; std::array buf; size_t pktcnt = 0; @@ -1663,7 +1667,7 @@ int Server::on_read(const Endpoint &ep) { for (; pktcnt < MAX_RECV_PKTS;) { if (util::recv_pkt_time_threshold_exceeded( config.cc_algo == NGTCP2_CC_ALGO_BBR, start, pktcnt)) { - return 0; + return; } msg.msg_namelen = sizeof(ss); @@ -1672,9 +1676,9 @@ int Server::on_read(const Endpoint &ep) { auto nread = recvmsg(ep.fd, &msg, 0); if (nread == -1) { if (!(errno == EAGAIN || errno == ENOTCONN)) { - std::cerr << "recvmsg: " << strerror(errno) << std::endl; + std::println(stderr, "recvmsg: {}", strerror(errno)); } - return 0; + return; } // Packets less than 21 bytes never be a valid QUIC packet. @@ -1697,7 +1701,7 @@ int Server::on_read(const Endpoint &ep) { auto local_addr = msghdr_get_local_addr(&msg, ss.ss_family); if (!local_addr) { ++pktcnt; - std::cerr << "Unable to obtain local address" << std::endl; + std::println(stderr, "Unable to obtain local address"); continue; } @@ -1717,11 +1721,11 @@ int Server::on_read(const Endpoint &ep) { if (!config.quiet) { std::array ifname; - 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(pi.ecn) - << std::dec << " " << datalen << " bytes" << std::endl; + std::println( + stderr, + "Received packet: local={} remote={} if={} ecn={:#x} {} bytes", + util::straddr(*local_addr), util::straddr(remote_addr), + if_indextoname(local_addr->ifindex, ifname.data()), pi.ecn, datalen); } // Packets less than 21 bytes never be a valid QUIC packet. @@ -1731,7 +1735,7 @@ int Server::on_read(const Endpoint &ep) { if (debug::packet_lost(config.rx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated incoming packet loss **" << std::endl; + std::println(stderr, "** Simulated incoming packet loss **"); } } else { read_pkt(ep, *local_addr, remote_addr, &pi, {data.data(), datalen}); @@ -1740,8 +1744,6 @@ int Server::on_read(const Endpoint &ep) { data = data.subspan(datalen); } } - - return 0; } void Server::read_pkt(const Endpoint &ep, const Address &local_addr, @@ -1760,8 +1762,9 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, remote_addr); return; default: - std::cerr << "Could not decode version and CID from QUIC packet header: " - << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, + "Could not decode version and CID from QUIC packet header: {}", + ngtcp2_strerror(rv)); return; } @@ -1773,8 +1776,8 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, if (auto rv = ngtcp2_accept(&hd, data.data(), data.size()); rv != 0) { if (!config.quiet) { - std::cerr << "Unexpected packet received: length=" << data.size() - << std::endl; + std::println(stderr, "Unexpected packet received: length={}", + data.size()); } if (!(data[0] & 0x80) && data.size() >= NGTCP2_SV_SCIDLEN + 21) { @@ -1792,7 +1795,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, assert(hd.type == NGTCP2_PKT_INITIAL); if (config.validate_addr || hd.tokenlen) { - std::cerr << "Perform stateless address validation" << std::endl; + std::println(stderr, "Perform stateless address validation"); if (hd.tokenlen == 0) { send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); return; @@ -1806,23 +1809,23 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, switch (hd.token[0]) { case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2: - 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, remote_addr); - return; - case 1: + if (auto rv = verify_retry_token(&ocid, &hd, remote_addr); !rv) { + if (rv.error() != Error::UNREADABLE_TOKEN) { + send_stateless_connection_close(&hd, ep, local_addr, remote_addr); + + return; + } + hd.token = nullptr; hd.tokenlen = 0; - break; + } else { + pocid = &ocid; + token_type = NGTCP2_TOKEN_TYPE_RETRY; } break; case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR: - if (verify_token(&hd, remote_addr) != 0) { + if (!verify_token(&hd, remote_addr)) { if (config.validate_addr) { send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); return; @@ -1836,7 +1839,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, break; default: if (!config.quiet) { - std::cerr << "Ignore unrecognized token" << std::endl; + std::println(stderr, "Ignore unrecognized token"); } if (config.validate_addr) { send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); @@ -1850,23 +1853,20 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, } auto h = std::make_unique(loop_, this); - if (h->init(ep, local_addr, remote_addr, &hd.scid, &hd.dcid, pocid, - {hd.token, hd.tokenlen}, token_type, hd.version, - tls_ctx_) != 0) { + if (!h->init(ep, local_addr, remote_addr, &hd.scid, &hd.dcid, pocid, + {hd.token, hd.tokenlen}, token_type, hd.version, tls_ctx_)) { return; } - switch (h->on_read(ep, local_addr, remote_addr, pi, data)) { - case 0: - break; - case NETWORK_ERR_RETRY: - send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); - return; - default: + if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); !rv) { + if (rv.error() == Error::RETRY_CONN) { + send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); + } + return; } - if (h->on_write() != 0) { + if (!h->on_write()) { return; } @@ -1891,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, remote_addr, pi, data) != 0) { + if (!h->send_conn_close(ep, local_addr, remote_addr, pi, data)) { remove(h); } return; @@ -1900,8 +1900,8 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, return; } - if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); rv != 0) { - if (rv != NETWORK_ERR_CLOSE_WAIT) { + if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); !rv) { + if (rv.error() != Error::CLOSE_WAIT) { remove(h); } return; @@ -1912,32 +1912,30 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, namespace { uint32_t generate_reserved_version(const Address &addr, uint32_t version) { - uint32_t h = 0x811C9DC5u; + uint32_t h = 0x811C9DC5U; const uint8_t *p = reinterpret_cast(addr.as_sockaddr()); const uint8_t *ep = p + addr.size(); for (; p != ep; ++p) { h ^= *p; - h *= 0x01000193u; + h *= 0x01000193U; } version = htonl(version); p = (const uint8_t *)&version; ep = p + sizeof(version); for (; p != ep; ++p) { h ^= *p; - h *= 0x01000193u; + h *= 0x01000193U; } - h &= 0xf0f0f0f0u; - h |= 0x0a0a0a0au; + h &= 0xF0F0F0F0U; + h |= 0x0A0A0A0AU; return h; } } // namespace -int Server::send_version_negotiation(uint32_t version, - std::span dcid, - std::span scid, - const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr) { +std::expected Server::send_version_negotiation( + uint32_t version, std::span dcid, + std::span scid, const Endpoint &ep, const Address &local_addr, + const Address &remote_addr) { Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; std::array sv; @@ -1958,24 +1956,23 @@ int Server::send_version_negotiation(uint32_t version, dcid.data(), dcid.size(), scid.data(), scid.size(), sv.data(), as_unsigned(p - std::ranges::begin(sv))); if (nwrite < 0) { - std::cerr << "ngtcp2_pkt_write_version_negotiation: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; - return -1; + std::println(stderr, "ngtcp2_pkt_write_version_negotiation: {}", + ngtcp2_strerror(static_cast(nwrite))); + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep, - const Address &local_addr, const Address &remote_addr, - size_t max_pktlen) { +std::expected Server::send_retry(const ngtcp2_pkt_hd *chd, + const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + size_t max_pktlen) { std::array host; std::array port; @@ -1983,89 +1980,85 @@ int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep, host.data(), host.size(), port.data(), port.size(), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } if (!config.quiet) { - std::cerr << "Sending Retry packet to [" << host.data() - << "]:" << port.data() << std::endl; + std::println(stderr, "Sending Retry packet to [{}]:{}", host.data(), + port.data()); } ngtcp2_cid scid; scid.datalen = NGTCP2_SV_SCIDLEN; - if (util::generate_secure_random({scid.data, scid.datalen}) != 0) { - return -1; + if (auto rv = util::generate_secure_random({scid.data, scid.datalen}); !rv) { + return rv; } - std::array token; + std::array tokenbuf; auto t = util::system_clock_now(); auto tokenlen = ngtcp2_crypto_generate_retry_token2( - token.data(), config.static_secret.data(), config.static_secret.size(), + tokenbuf.data(), config.static_secret.data(), config.static_secret.size(), chd->version, remote_addr.as_sockaddr(), remote_addr.size(), &scid, &chd->dcid, t); if (tokenlen < 0) { - return -1; + return std::unexpected{Error::QUIC}; } + auto token = std::span{tokenbuf}.first(as_unsigned(tokenlen)); + if (!config.quiet) { - std::cerr << "Generated address validation token:" << std::endl; - util::hexdump(stderr, token.data(), as_unsigned(tokenlen)); + std::println(stderr, "Generated address validation token:"); + util::hexdump(stderr, token); } Buffer buf{ std::min(static_cast(NGTCP2_MAX_UDP_PAYLOAD_SIZE), max_pktlen)}; - auto nwrite = ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version, - &chd->scid, &scid, &chd->dcid, - token.data(), as_unsigned(tokenlen)); + auto nwrite = + ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version, &chd->scid, + &scid, &chd->dcid, token.data(), token.size()); if (nwrite < 0) { - std::cerr << "ngtcp2_crypto_write_retry failed" << std::endl; - return -1; + std::println(stderr, "ngtcp2_crypto_write_retry failed"); + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd, - const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr) { +std::expected Server::send_stateless_connection_close( + const ngtcp2_pkt_hd *chd, const Endpoint &ep, const Address &local_addr, + const Address &remote_addr) { Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; auto nwrite = ngtcp2_crypto_write_connection_close( buf.wpos(), buf.left(), chd->version, &chd->scid, &chd->dcid, NGTCP2_INVALID_TOKEN, nullptr, 0); if (nwrite < 0) { - std::cerr << "ngtcp2_crypto_write_connection_close failed" << std::endl; - return -1; + std::println(stderr, "ngtcp2_crypto_write_connection_close failed"); + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::send_stateless_reset(size_t pktlen, std::span dcid, - const Endpoint &ep, const Address &local_addr, - const Address &remote_addr) { +std::expected +Server::send_stateless_reset(size_t pktlen, std::span dcid, + const Endpoint &ep, const Address &local_addr, + const Address &remote_addr) { if (stateless_reset_bucket_ == 0) { - return 0; + return {}; } --stateless_reset_bucket_; @@ -2078,12 +2071,12 @@ int Server::send_stateless_reset(size_t pktlen, std::span dcid, ngtcp2_cid_init(&cid, dcid.data(), dcid.size()); - std::array token; + ngtcp2_stateless_reset_token token; if (ngtcp2_crypto_generate_stateless_reset_token( - token.data(), config.static_secret.data(), config.static_secret.size(), + token.data, config.static_secret.data(), config.static_secret.size(), &cid) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } // SCID + minimum expansion - NGTCP2_STATELESS_RESET_TOKENLEN @@ -2102,33 +2095,33 @@ int Server::send_stateless_reset(size_t pktlen, std::span dcid, std::array rand_bytes; - if (util::generate_secure_random({rand_bytes.data(), rand_byteslen}) != 0) { - return -1; + if (auto rv = + util::generate_secure_random({rand_bytes.data(), rand_byteslen}); + !rv) { + return rv; } Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; - auto nwrite = ngtcp2_pkt_write_stateless_reset( - buf.wpos(), buf.left(), token.data(), rand_bytes.data(), rand_byteslen); + auto nwrite = ngtcp2_pkt_write_stateless_reset2( + buf.wpos(), buf.left(), &token, rand_bytes.data(), rand_byteslen); if (nwrite < 0) { - std::cerr << "ngtcp2_pkt_write_stateless_reset: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_pkt_write_stateless_reset2: {}", + ngtcp2_strerror(static_cast(nwrite))); - return -1; + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, - const Address &remote_addr) { +std::expected +Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, + const Address &remote_addr) { int rv; if (!config.quiet) { @@ -2139,13 +2132,13 @@ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, host.data(), host.size(), port.data(), port.size(), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } - std::cerr << "Verifying Retry token from [" << host.data() - << "]:" << port.data() << std::endl; - util::hexdump(stderr, hd->token, hd->tokenlen); + std::println(stderr, "Verifying Retry token from [{}]:{}", host.data(), + port.data()); + util::hexdump(stderr, {hd->token, hd->tokenlen}); } auto t = util::system_clock_now(); @@ -2158,24 +2151,25 @@ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, case 0: break; case NGTCP2_CRYPTO_ERR_VERIFY_TOKEN: - std::cerr << "Could not verify Retry token" << std::endl; + std::println(stderr, "Could not verify Retry token"); - return -1; + return std::unexpected{Error::QUIC}; default: - std::cerr << "Could not read Retry token. Continue without the token" - << std::endl; + std::println(stderr, + "Could not read Retry token. Continue without the token"); - return 1; + return std::unexpected{Error::UNREADABLE_TOKEN}; } if (!config.quiet) { - std::cerr << "Token was successfully validated" << std::endl; + std::println(stderr, "Token was successfully validated"); } - return 0; + return {}; } -int Server::verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr) { +std::expected Server::verify_token(const ngtcp2_pkt_hd *hd, + const Address &remote_addr) { std::array host; std::array port; @@ -2183,14 +2177,14 @@ int Server::verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr) { host.data(), host.size(), port.data(), port.size(), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } if (!config.quiet) { - std::cerr << "Verifying token from [" << host.data() << "]:" << port.data() - << std::endl; - util::hexdump(stderr, hd->token, hd->tokenlen); + std::println(stderr, "Verifying token from [{}]:{}", host.data(), + port.data()); + util::hexdump(stderr, {hd->token, hd->tokenlen}); } auto t = util::system_clock_now(); @@ -2199,56 +2193,64 @@ int Server::verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr) { 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; + std::println(stderr, "Could not verify token"); - return -1; + return std::unexpected{Error::QUIC}; } if (!config.quiet) { - std::cerr << "Token was successfully validated" << std::endl; + std::println(stderr, "Token was successfully validated"); } - return 0; + return {}; } -int Server::send_packet(const Endpoint &ep, const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, unsigned int ecn, - std::span data) { +std::expected Server::send_packet(const Endpoint &ep, + const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data) { auto no_gso = false; - auto [_, rv] = + auto rest = send_packet(ep, no_gso, local_addr, remote_addr, ecn, data, data.size()); + if (!rest.empty()) { + return std::unexpected{Error::SEND_BLOCKED}; + } - return rv; + return {}; } -std::pair, int> -Server::send_packet(const Endpoint &ep, bool &no_gso, - const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, unsigned int ecn, - std::span data, size_t gso_size) { +std::span Server::send_packet(const Endpoint &ep, bool &no_gso, + const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data, + size_t gso_size) { assert(gso_size); if (debug::packet_lost(config.tx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated outgoing packet loss **" << std::endl; + std::println(stderr, "** Simulated outgoing packet loss **"); } - return {{}, NETWORK_ERR_OK}; + return {}; } if (no_gso && data.size() > gso_size) { for (; !data.empty();) { auto len = std::min(gso_size, data.size()); - auto [_, rv] = send_packet(ep, no_gso, local_addr, remote_addr, ecn, - data.first(len), len); - if (rv != 0) { - return {data, rv}; + auto rest = send_packet(ep, no_gso, local_addr, remote_addr, ecn, + data.first(len), len); + if (!rest.empty()) { + assert(rest.size() == len); + + return data; } data = data.subspan(len); } - return {{}, 0}; + return {}; } iovec msg_iov{ @@ -2355,13 +2357,13 @@ Server::send_packet(const Endpoint &ep, bool &no_gso, #if EAGAIN != EWOULDBLOCK case EWOULDBLOCK: #endif // EAGAIN != EWOULDBLOCK - return {data, NETWORK_ERR_SEND_BLOCKED}; + return data; #ifdef UDP_SEGMENT case EIO: if (data.size() > gso_size) { // GSO failure; send each packet in a separate sendmsg call. - std::cerr << "sendmsg: disabling GSO due to " << strerror(errno) - << std::endl; + std::println(stderr, "sendmsg: disabling GSO due to {}", + strerror(errno)); no_gso = true; @@ -2372,22 +2374,20 @@ Server::send_packet(const Endpoint &ep, bool &no_gso, #endif // defined(UDP_SEGMENT) } - std::cerr << "sendmsg: " << strerror(errno) << std::endl; + std::println(stderr, "sendmsg: {}", strerror(errno)); // TODO We have packet which is expected to fail to send (e.g., // path validation to old path). - return {{}, NETWORK_ERR_OK}; + return {}; } if (!config.quiet) { - std::cerr << "Sent packet: local=" - << util::straddr(local_addr.addr, local_addr.addrlen) - << " remote=" - << util::straddr(remote_addr.addr, remote_addr.addrlen) - << " ecn=0x" << std::hex << ecn << std::dec << " " << nwrite - << " bytes" << std::endl; + std::println(stderr, "Sent packet: local={} remote={} ecn={:#x} {} bytes", + util::straddr(local_addr.addr, local_addr.addrlen), + util::straddr(remote_addr.addr, remote_addr.addrlen), ecn, + nwrite); } - return {{}, NETWORK_ERR_OK}; + return {}; } void Server::associate_cid(const ngtcp2_cid *cid, Handler *h) { @@ -2420,9 +2420,10 @@ void Server::on_stateless_reset_regen() { } namespace { -int parse_host_port(Address &dest, int af, const std::string_view &host_port) { +std::expected parse_host_port(int af, + std::string_view host_port) { if (host_port.empty()) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } auto first = std::ranges::begin(host_port); @@ -2435,19 +2436,19 @@ int parse_host_port(Address &dest, int af, const std::string_view &host_port) { auto it = std::ranges::find(first, last, ']'); if (it == last) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } hostv = std::string_view{first, it}; first = it + 1; if (first == last || *first != ':') { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } } else { auto it = std::ranges::find(first, last, ':'); if (it == last) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } hostv = std::string_view{first, it}; @@ -2455,7 +2456,7 @@ int parse_host_port(Address &dest, int af, const std::string_view &host_port) { } if (++first == last) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } std::array host; @@ -2469,16 +2470,17 @@ int parse_host_port(Address &dest, int af, const std::string_view &host_port) { auto svc = first; if (auto rv = getaddrinfo(host.data(), svc, &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: [" << host.data() << "]:" << svc << ": " - << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: [{}]:{}: {}", host.data(), svc, + gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } + Address dest; dest.set(res->ai_addr); freeaddrinfo(res); - return 0; + return dest; } } // namespace @@ -2487,17 +2489,17 @@ const char *prog = "h09server"; } // namespace namespace { -void print_usage() { - std::cerr << "Usage: " << prog - << " [OPTIONS] " - "" - << std::endl; +void print_usage(FILE *out) { + std::println( + out, + "Usage: {} [OPTIONS] ", + prog); } } // namespace namespace { void print_help() { - print_usage(); + print_usage(stdout); Config config; @@ -2759,7 +2761,7 @@ int main(int argc, char **argv) { // --htdocs auto path = realpath(optarg, nullptr); if (path == nullptr) { - std::cerr << "path: invalid path " << std::quoted(optarg) << std::endl; + std::println(stderr, "path: invalid path {}", optarg); exit(EXIT_FAILURE); } config.htdocs = path; @@ -2791,14 +2793,14 @@ int main(int argc, char **argv) { config.validate_addr = true; break; case '?': - print_usage(); + print_usage(stderr); exit(EXIT_FAILURE); case 0: switch (flag) { case 1: // --ciphers if (util::crypto_default_ciphers()[0] == '\0') { - std::cerr << "ciphers: not supported" << std::endl; + std::println(stderr, "ciphers: not supported"); exit(EXIT_FAILURE); } config.ciphers = optarg; @@ -2810,29 +2812,36 @@ int main(int argc, char **argv) { case 3: // --timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "timeout: invalid argument" << std::endl; + std::println(stderr, "timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.timeout = *t; } break; - case 4: + case 4: { // --preferred-ipv4-addr - if (parse_host_port(config.preferred_ipv4_addr, AF_INET, optarg) != 0) { - std::cerr << "preferred-ipv4-addr: could not use " - << std::quoted(optarg) << std::endl; + auto maybe_addr = parse_host_port(AF_INET, optarg); + if (!maybe_addr) { + std::println(stderr, "preferred-ipv4-addr: could not use {}", optarg); exit(EXIT_FAILURE); } + + config.preferred_ipv4_addr = *maybe_addr; + break; - case 5: + } + case 5: { // --preferred-ipv6-addr - if (parse_host_port(config.preferred_ipv6_addr, AF_INET6, optarg) != - 0) { - std::cerr << "preferred-ipv6-addr: could not use " - << std::quoted(optarg) << std::endl; + auto maybe_addr = parse_host_port(AF_INET6, optarg); + if (!maybe_addr) { + std::println(stderr, "preferred-ipv6-addr: could not use {}", optarg); exit(EXIT_FAILURE); } + + config.preferred_ipv6_addr = *maybe_addr; + break; + } case 6: // --mime-types-file config.mime_types_file = optarg; @@ -2860,7 +2869,7 @@ int main(int argc, char **argv) { case 12: // --max-data if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-data: invalid argument" << std::endl; + std::println(stderr, "max-data: invalid argument"); exit(EXIT_FAILURE); } else { config.max_data = *n; @@ -2869,8 +2878,7 @@ int main(int argc, char **argv) { case 13: // --max-stream-data-bidi-local if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-local: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-local: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_local = *n; @@ -2879,8 +2887,7 @@ int main(int argc, char **argv) { case 14: // --max-stream-data-bidi-remote if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-remote: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-remote: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_remote = *n; @@ -2889,7 +2896,7 @@ int main(int argc, char **argv) { case 15: // --max-stream-data-uni if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-uni: invalid argument" << std::endl; + std::println(stderr, "max-stream-data-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_uni = *n; @@ -2898,7 +2905,7 @@ int main(int argc, char **argv) { case 16: // --max-streams-bidi if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-bidi: invalid argument" << std::endl; + std::println(stderr, "max-streams-bidi: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_bidi = *n; @@ -2907,7 +2914,7 @@ int main(int argc, char **argv) { case 17: // --max-streams-uni if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-uni: invalid argument" << std::endl; + std::println(stderr, "max-streams-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_uni = *n; @@ -2916,7 +2923,7 @@ int main(int argc, char **argv) { case 18: // --max-dyn-length if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-dyn-length: invalid argument" << std::endl; + std::println(stderr, "max-dyn-length: invalid argument"); exit(EXIT_FAILURE); } else { config.max_dyn_length = *n; @@ -2936,12 +2943,12 @@ int main(int argc, char **argv) { config.cc_algo = NGTCP2_CC_ALGO_BBR; break; } - std::cerr << "cc: specify cubic, reno, or bbr" << std::endl; + std::println(stderr, "cc: specify cubic, reno, or bbr"); exit(EXIT_FAILURE); case 20: // --initial-rtt if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "initial-rtt: invalid argument" << std::endl; + std::println(stderr, "initial-rtt: invalid argument"); exit(EXIT_FAILURE); } else { config.initial_rtt = *t; @@ -2950,11 +2957,11 @@ int main(int argc, char **argv) { case 21: // --max-udp-payload-size if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-udp-payload-size: invalid argument" << std::endl; + std::println(stderr, "max-udp-payload-size: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println(stderr, "max-udp-payload-size: must not exceed {}", + NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else { config.max_udp_payload_size = *n; @@ -2967,7 +2974,7 @@ int main(int argc, char **argv) { case 23: // --max-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-window: invalid argument" << std::endl; + std::println(stderr, "max-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_window = *n; @@ -2976,7 +2983,7 @@ int main(int argc, char **argv) { case 24: // --max-stream-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-window: invalid argument" << std::endl; + std::println(stderr, "max-stream-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_window = *n; @@ -2985,7 +2992,7 @@ int main(int argc, char **argv) { case 26: // --handshake-timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "handshake-timeout: invalid argument" << std::endl; + std::println(stderr, "handshake-timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.handshake_timeout = *t; @@ -2995,8 +3002,9 @@ int main(int argc, char **argv) { // --preferred-versions auto l = util::split_str(optarg); if (l.size() > max_preferred_versionslen) { - std::cerr << "preferred-versions: too many versions > " - << max_preferred_versionslen << std::endl; + std::println(stderr, "preferred-versions: too many versions > {}", + max_preferred_versionslen); + exit(EXIT_FAILURE); } config.preferred_versions.resize(l.size()); auto it = std::ranges::begin(config.preferred_versions); @@ -3011,13 +3019,12 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "preferred-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: invalid version {}", k); exit(EXIT_FAILURE); } if (!ngtcp2_is_supported_version(*rv)) { - std::cerr << "preferred-versions: unsupported version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: unsupported version {}", + k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -3040,8 +3047,7 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "available-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "available-versions: invalid version {}", k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -3055,10 +3061,10 @@ int main(int argc, char **argv) { case 30: // --ack-thresh if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "ack-thresh: invalid argument" << std::endl; + std::println(stderr, "ack-thresh: invalid argument"); exit(EXIT_FAILURE); } else if (*n > 100) { - std::cerr << "ack-thresh: must not exceed 100" << std::endl; + std::println(stderr, "ack-thresh: must not exceed 100"); exit(EXIT_FAILURE); } else { config.ack_thresh = *n; @@ -3067,11 +3073,11 @@ int main(int argc, char **argv) { case 31: // --initial-pkt-num if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "initial-pkt-num: invalid argument" << std::endl; + std::println(stderr, "initial-pkt-num: invalid argument"); exit(EXIT_FAILURE); } else if (*n > INT32_MAX) { - std::cerr << "initial-pkt-num: must not exceed (1 << 31) - 1" - << std::endl; + std::println(stderr, + "initial-pkt-num: must not exceed (1 << 31) - 1"); exit(EXIT_FAILURE); } else { config.initial_pkt_num = static_cast(*n); @@ -3082,14 +3088,13 @@ int main(int argc, char **argv) { auto l = util::split_str(optarg); for (auto &s : l) { if (auto n = util::parse_uint_iec(s); !n) { - std::cerr << "pmtud-probes: invalid argument" << std::endl; + std::println(stderr, "pmtud-probes: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println( + stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", + NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else { config.pmtud_probes.push_back(static_cast(*n)); @@ -3113,13 +3118,13 @@ int main(int argc, char **argv) { // --gso-burst auto n = util::parse_uint(optarg); if (!n) { - std::cerr << "gso-burst: invalid argument" << std::endl; + std::println(stderr, "gso-burst: invalid argument"); exit(EXIT_FAILURE); } if (*n > 64) { - std::cerr << "gso-burst: must be in range [0, 64], inclusive." - << std::endl; + std::println(stderr, + "gso-burst: must be in range [0, 64], inclusive."); exit(EXIT_FAILURE); } @@ -3135,8 +3140,8 @@ int main(int argc, char **argv) { } if (argc - optind < 4) { - std::cerr << "Too few arguments" << std::endl; - print_usage(); + std::println(stderr, "Too few arguments"); + print_usage(stderr); exit(EXIT_FAILURE); } @@ -3146,18 +3151,19 @@ int main(int argc, char **argv) { auto cert_file = argv[optind++]; if (auto n = util::parse_uint(port); !n) { - std::cerr << "port: invalid port number" << std::endl; + std::println(stderr, "port: invalid port number"); exit(EXIT_FAILURE); } else if (*n > 65535) { - std::cerr << "port: must not exceed 65535" << std::endl; + std::println(stderr, "port: must not exceed 65535"); exit(EXIT_FAILURE); } else { config.port = static_cast(*n); } if (auto mt = util::read_mime_types(config.mime_types_file); !mt) { - std::cerr << "mime-types-file: Could not read MIME media types file " - << std::quoted(config.mime_types_file) << std::endl; + std::println(stderr, + "mime-types-file: Could not read MIME media types file {}", + config.mime_types_file); } else { config.mime_types = std::move(*mt); } @@ -3165,8 +3171,8 @@ int main(int argc, char **argv) { if (!ech_config_file.empty()) { auto ech_config = util::read_ech_server_config(ech_config_file); if (!ech_config) { - std::cerr << "ech-config-file: Could not read private key and ECHConfig" - << std::endl; + std::println(stderr, + "ech-config-file: Could not read private key and ECHConfig"); exit(EXIT_FAILURE); } @@ -3175,7 +3181,7 @@ int main(int argc, char **argv) { TLSServerContext tls_ctx; - if (tls_ctx.init(private_key_file, cert_file, AppProtocol::HQ) != 0) { + if (!tls_ctx.init(private_key_file, cert_file, AppProtocol::HQ)) { exit(EXIT_FAILURE); } @@ -3183,7 +3189,7 @@ int main(int argc, char **argv) { config.htdocs += '/'; } - std::cerr << "Using document root " << config.htdocs << std::endl; + std::println(stderr, "Using document root {}", config.htdocs); auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); }); @@ -3195,13 +3201,13 @@ int main(int argc, char **argv) { } } - if (util::generate_secret(config.static_secret) != 0) { - std::cerr << "Unable to generate static secret" << std::endl; + if (!util::generate_secure_random(config.static_secret)) { + std::println(stderr, "Unable to generate static secret"); exit(EXIT_FAILURE); } Server s(EV_DEFAULT, tls_ctx); - if (s.init(addr, port) != 0) { + if (!s.init(addr, port)) { exit(EXIT_FAILURE); } diff --git a/deps/ngtcp2/ngtcp2/examples/h09server.h b/deps/ngtcp2/ngtcp2/examples/h09server.h index 50bfae347f10fb..b02557fcd5ddf3 100644 --- a/deps/ngtcp2/ngtcp2/examples/h09server.h +++ b/deps/ngtcp2/ngtcp2/examples/h09server.h @@ -58,10 +58,10 @@ struct FileEntry; struct Stream { Stream(int64_t stream_id, Handler *handler); - int start_response(); - std::pair open_file(const std::string &path); + void start_response(); + std::expected open_file(const std::string &path); void map_file(const FileEntry &fe); - int send_status_response(unsigned int status_code); + void send_status_response(unsigned int status_code); int64_t stream_id; Handler *handler; @@ -95,49 +95,57 @@ class Handler : public HandlerBase { Handler(struct ev_loop *loop, Server *server); ~Handler(); - 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 token, ngtcp2_token_type token_type, - uint32_t version, TLSServerContext &tls_ctx); - - int on_read(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data); - int on_write(); - int write_streams(); - int feed_data(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data); + std::expected + 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 token, ngtcp2_token_type token_type, + uint32_t version, TLSServerContext &tls_ctx); + + std::expected on_read(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data); + std::expected on_write(); + std::expected write_streams(); + std::expected feed_data(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data); void update_timer(); - int handle_expiry(); + std::expected handle_expiry(); void signal_write(); - int handshake_completed(); + std::expected handshake_completed(); Server *server() const; - int recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data); - int acked_stream_data_offset(int64_t stream_id, uint64_t offset, - uint64_t datalen); + std::expected recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + void acked_stream_data_offset(int64_t stream_id, uint64_t offset, + uint64_t datalen); uint32_t version() const; void on_stream_open(int64_t stream_id); - int on_stream_close(int64_t stream_id, uint64_t app_error_code); + void on_stream_close(int64_t stream_id, uint64_t app_error_code); void start_draining_period(); - int start_closing_period(); - int handle_error(); - int send_conn_close(); - int send_conn_close(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data); - - int update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen); + std::expected start_closing_period(); + std::expected handle_error(); + std::expected send_conn_close(); + std::expected send_conn_close(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data); + + std::expected + update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, + size_t secretlen); Stream *find_stream(int64_t stream_id); - int extend_max_stream_data(int64_t stream_id, uint64_t max_data); + void extend_max_stream_data(int64_t stream_id, uint64_t max_data); void shutdown_read(int64_t stream_id, uint64_t app_error_code); void write_qlog(const void *data, size_t datalen); @@ -146,9 +154,11 @@ class Handler : public HandlerBase { void on_send_blocked(const ngtcp2_path &path, unsigned int ecn, std::span data, size_t gso_size); void start_wev_endpoint(const Endpoint &ep); - int send_packet(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size); - int send_blocked_packet(); + std::expected send_packet(const ngtcp2_path &path, + unsigned int ecn, + std::span data, + size_t gso_size); + void send_blocked_packet(); ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts); @@ -196,35 +206,44 @@ class Server { Server(struct ev_loop *loop, TLSServerContext &tls_ctx); ~Server(); - int init(const char *addr, const char *port); + std::expected init(const char *addr, const char *port); void disconnect(); void close(); - int on_read(const Endpoint &ep); + void on_read(const Endpoint &ep); void read_pkt(const Endpoint &ep, const Address &local_addr, const Address &remote_addr, const ngtcp2_pkt_info *pi, std::span data); - int send_version_negotiation(uint32_t version, std::span dcid, - std::span scid, - const Endpoint &ep, const Address &local_addr, - const Address &remote_addr); - int send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep, - 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 Address &remote_addr); - int send_stateless_reset(size_t pktlen, std::span dcid, - const Endpoint &ep, const Address &local_addr, + std::expected + send_version_negotiation(uint32_t version, std::span dcid, + std::span scid, const Endpoint &ep, + const Address &local_addr, const Address &remote_addr); - int verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, - 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 data); - std::pair, int> + std::expected send_retry(const ngtcp2_pkt_hd *chd, + const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + size_t max_pktlen); + std::expected + send_stateless_connection_close(const ngtcp2_pkt_hd *chd, const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr); + std::expected send_stateless_reset(size_t pktlen, + std::span dcid, + const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr); + std::expected verify_retry_token(ngtcp2_cid *ocid, + const ngtcp2_pkt_hd *hd, + const Address &remote_addr); + std::expected verify_token(const ngtcp2_pkt_hd *hd, + const Address &remote_addr); + std::expected send_packet(const Endpoint &ep, + const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data); + std::span send_packet(const Endpoint &ep, bool &no_gso, const ngtcp2_addr &local_addr, const ngtcp2_addr &remote_addr, unsigned int ecn, std::span data, size_t gso_size); diff --git a/deps/ngtcp2/ngtcp2/examples/server.cc b/deps/ngtcp2/ngtcp2/examples/server.cc index f9463eacd9cc7d..35b387c36fd1e5 100644 --- a/deps/ngtcp2/ngtcp2/examples/server.cc +++ b/deps/ngtcp2/ngtcp2/examples/server.cc @@ -111,7 +111,8 @@ struct Request { }; namespace { -Request request_path(const std::string_view &uri, bool is_connect) { +std::expected request_path(std::string_view uri, + bool is_connect) { urlparse_url u; Request req{ .pri{ @@ -122,7 +123,7 @@ Request request_path(const std::string_view &uri, bool is_connect) { if (auto rv = urlparse_parse_url(uri.data(), uri.size(), is_connect, &u); rv != 0) { - return req; + return std::unexpected{Error::INVALID_ARGUMENT}; } if (u.field_set & (1 << URLPARSE_PATH)) { @@ -130,15 +131,24 @@ Request request_path(const std::string_view &uri, bool is_connect) { if (req.path.find('%') != std::string::npos) { req.path = util::percent_decode(req.path); } - if (!req.path.empty() && req.path.back() == '/') { + + assert(!req.path.empty()); + + if (req.path[0] != '/') { + return std::unexpected{Error::INVALID_ARGUMENT}; + } + + if (req.path.back() == '/') { req.path += "index.html"; } - } else { - req.path = "/index.html"; - } - req.path = util::normalize_path(req.path); - if (req.path == "/") { + auto maybe_norm_path = util::normalize_path(req.path); + if (!maybe_norm_path) { + return std::unexpected{maybe_norm_path.error()}; + } + + req.path = std::move(*maybe_norm_path); + } else { req.path = "/index.html"; } @@ -203,21 +213,21 @@ namespace { std::unordered_map file_cache; } // namespace -std::pair Stream::open_file(const std::string &path) { +std::expected Stream::open_file(const std::string &path) { auto it = file_cache.find(path); if (it != std::ranges::end(file_cache)) { - return {(*it).second, 0}; + return (*it).second; } auto fd = open(path.c_str(), O_RDONLY); if (fd == -1) { - return {{}, -1}; + return std::unexpected{Error::SYSCALL}; } struct stat st{}; if (fstat(fd, &st) != 0) { close(fd); - return {{}, -1}; + return std::unexpected{Error::SYSCALL}; } FileEntry fe; @@ -231,16 +241,16 @@ std::pair Stream::open_file(const std::string &path) { if (fe.len) { fe.map = mmap(nullptr, fe.len, PROT_READ, MAP_SHARED, fd, 0); if (fe.map == MAP_FAILED) { - std::cerr << "mmap: " << strerror(errno) << std::endl; + std::println(stderr, "mmap: {}", strerror(errno)); close(fd); - return {{}, -1}; + return std::unexpected{Error::SYSCALL}; } } } file_cache.emplace(path, fe); - return {std::move(fe), 0}; + return fe; } void Stream::map_file(const FileEntry &fe) { @@ -248,11 +258,11 @@ void Stream::map_file(const FileEntry &fe) { datalen = fe.len; } -int64_t Stream::find_dyn_length(const std::string_view &path) { +std::expected Stream::find_dyn_length(std::string_view path) { assert(path[0] == '/'); if (path.size() == 1) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } uint64_t n = 0; @@ -260,19 +270,19 @@ int64_t Stream::find_dyn_length(const std::string_view &path) { for (auto it = std::ranges::begin(path) + 1; it != std::ranges::end(path); ++it) { if (*it < '0' || '9' < *it) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } auto d = static_cast(*it - '0'); - if (n > (((1ull << 62) - 1) - d) / 10) { - return -1; + if (n > (((1ULL << 62) - 1) - d) / 10) { + return std::unexpected{Error::INVALID_ARGUMENT}; } n = n * 10 + d; if (n > config.max_dyn_length) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } } - return static_cast(n); + return n; } namespace { @@ -321,8 +331,8 @@ nghttp3_ssize dyn_read_data(nghttp3_conn *conn, int64_t stream_id, if (auto rv = nghttp3_conn_submit_trailers( conn, stream_id, trailers.data(), trailers.size()); rv != 0) { - std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv) - << std::endl; + std::println(stderr, "nghttp3_conn_submit_trailers: {}", + nghttp3_strerror(rv)); return NGHTTP3_ERR_CALLBACK_FAILURE; } } @@ -342,9 +352,9 @@ void Stream::http_acked_stream_data(uint64_t datalen) { dynbuflen -= datalen; } -int Stream::send_status_response(nghttp3_conn *httpconn, - unsigned int status_code, - const std::vector &extra_headers) { +std::expected +Stream::send_status_response(nghttp3_conn *httpconn, unsigned int status_code, + const std::vector &extra_headers) { status_resp_body = make_status_body(status_code); auto status_code_str = util::format_uint(status_code); @@ -372,9 +382,9 @@ int Stream::send_status_response(nghttp3_conn *httpconn, if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(), nva.size(), &dr); rv != 0) { - std::cerr << "nghttp3_conn_submit_response: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_submit_response: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } if (config.send_trailers) { @@ -386,55 +396,56 @@ int Stream::send_status_response(nghttp3_conn *httpconn, if (auto rv = nghttp3_conn_submit_trailers( httpconn, stream_id, trailers.data(), trailers.size()); rv != 0) { - std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_submit_trailers: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } } handler->shutdown_read(stream_id, NGHTTP3_H3_NO_ERROR); - return 0; + return {}; } -int Stream::send_redirect_response(nghttp3_conn *httpconn, - unsigned int status_code, - const std::string_view &path) { +std::expected +Stream::send_redirect_response(nghttp3_conn *httpconn, unsigned int status_code, + std::string_view path) { return send_status_response(httpconn, status_code, {{"location", path}}); } -int Stream::start_response(nghttp3_conn *httpconn) { +std::expected Stream::start_response(nghttp3_conn *httpconn) { // TODO This should be handled by nghttp3 if (uri.empty() || method.empty()) { return send_status_response(httpconn, 400); } - auto req = request_path(uri, method == "CONNECT"); - if (req.path.empty()) { + auto maybe_req = request_path(uri, method == "CONNECT"); + if (!maybe_req) { return send_status_response(httpconn, 400); } - auto dyn_len = find_dyn_length(req.path); + const auto &req = *maybe_req; - int64_t content_length = -1; + uint64_t content_length; nghttp3_data_reader dr{}; auto content_type = "text/plain"sv; - if (dyn_len == -1) { + auto maybe_dyn_len = find_dyn_length(req.path); + if (!maybe_dyn_len) { auto path = config.htdocs + req.path; - auto [fe, rv] = open_file(path); - if (rv != 0) { - send_status_response(httpconn, 404); - return 0; + auto maybe_fe = open_file(path); + if (!maybe_fe) { + return send_status_response(httpconn, 404); } + const auto &fe = *maybe_fe; + if (fe.flags & FILE_ENTRY_TYPE_DIR) { - send_redirect_response(httpconn, 308, - path.substr(config.htdocs.size() - 1) + '/'); - return 0; + return send_redirect_response( + httpconn, 308, path.substr(config.htdocs.size() - 1) + '/'); } - content_length = static_cast(fe.len); + content_length = fe.len; if (method != "HEAD") { map_file(fe); @@ -455,19 +466,19 @@ int Stream::start_response(nghttp3_conn *httpconn) { } } } else { - content_length = dyn_len; + content_length = *maybe_dyn_len; dynresp = true; dr.read_data = dyn_read_data; if (method != "HEAD") { - datalen = as_unsigned(dyn_len); - dyndataleft = as_unsigned(dyn_len); + datalen = content_length; + dyndataleft = content_length; } content_type = "application/octet-stream"sv; } - auto content_length_str = util::format_uint(as_unsigned(content_length)); + auto content_length_str = util::format_uint(content_length); std::array nva{ util::make_nv_nn(":status"sv, "200"sv), @@ -485,9 +496,9 @@ int Stream::start_response(nghttp3_conn *httpconn) { if (auto rv = nghttp3_conn_get_stream_priority(httpconn, &pri, stream_id); rv != 0) { - std::cerr << "nghttp3_conn_get_stream_priority: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_get_stream_priority: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } if (req.pri.urgency != -1) { @@ -500,9 +511,9 @@ int Stream::start_response(nghttp3_conn *httpconn) { if (auto rv = nghttp3_conn_set_server_stream_priority(httpconn, stream_id, &pri); rv != 0) { - std::cerr << "nghttp3_conn_set_stream_priority: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_set_server_stream_priority: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } prival = "u="; @@ -522,12 +533,12 @@ int Stream::start_response(nghttp3_conn *httpconn) { if (auto rv = nghttp3_conn_submit_response(httpconn, stream_id, nva.data(), nvlen, &dr); rv != 0) { - std::cerr << "nghttp3_conn_submit_response: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_submit_response: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - if (config.send_trailers && dyn_len == -1) { + if (config.send_trailers && !maybe_dyn_len) { auto stream_id_str = util::format_uint(as_unsigned(stream_id)); auto trailers = std::to_array({ util::make_nv_nc("x-ngtcp2-stream-id"sv, stream_id_str), @@ -536,13 +547,13 @@ int Stream::start_response(nghttp3_conn *httpconn) { if (auto rv = nghttp3_conn_submit_trailers( httpconn, stream_id, trailers.data(), trailers.size()); rv != 0) { - std::cerr << "nghttp3_conn_submit_trailers: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_submit_trailers: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } } - return 0; + return {}; } namespace { @@ -550,11 +561,7 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) { auto h = static_cast(w->data); auto s = h->server(); - switch (h->on_write()) { - case 0: - case NETWORK_ERR_CLOSE_WAIT: - return; - default: + if (auto rv = h->on_write(); !rv && rv.error() != Error::CLOSE_WAIT) { s->remove(h); } } @@ -568,7 +575,7 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { if (ngtcp2_conn_in_closing_period(conn)) { if (!config.quiet) { - std::cerr << "Closing Period is over" << std::endl; + std::println(stderr, "Closing Period is over"); } s->remove(h); @@ -576,7 +583,7 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { } if (ngtcp2_conn_in_draining_period(conn)) { if (!config.quiet) { - std::cerr << "Draining Period is over" << std::endl; + std::println(stderr, "Draining Period is over"); } s->remove(h); @@ -589,33 +596,24 @@ void close_waitcb(struct ev_loop *loop, ev_timer *w, int revents) { namespace { void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { - int rv; - auto h = static_cast(w->data); auto s = h->server(); if (!config.quiet) { - std::cerr << "Timer expired" << std::endl; - } - - rv = h->handle_expiry(); - if (rv != 0) { - goto fail; + std::println(stderr, "Timer expired"); } - h->signal_write(); - - return; + if (auto rv = h->handle_expiry(); !rv) { + if (rv.error() == Error::CLOSE_WAIT) { + ev_timer_stop(loop, w); + } else { + s->remove(h); + } -fail: - switch (rv) { - case NETWORK_ERR_CLOSE_WAIT: - ev_timer_stop(loop, w); - return; - default: - s->remove(h); return; } + + h->signal_write(); } } // namespace @@ -637,7 +635,7 @@ Handler::Handler(struct ev_loop *loop, Server *server) Handler::~Handler() { if (!config.quiet) { - std::cerr << scid_ << " Closing QUIC connection " << std::endl; + std::println(stderr, "{} Closing QUIC connection", scid_); } ev_timer_stop(loop_, &timer_); @@ -660,7 +658,7 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { debug::handshake_completed(conn, user_data); } - if (h->handshake_completed() != 0) { + if (!h->handshake_completed()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -668,19 +666,19 @@ int handshake_completed(ngtcp2_conn *conn, void *user_data) { } } // namespace -int Handler::handshake_completed() { +std::expected Handler::handshake_completed() { if (!config.quiet) { - std::cerr << "Negotiated cipher suite is " << tls_session_.get_cipher_name() - << std::endl; + std::println(stderr, "Negotiated cipher suite is {}", + tls_session_.get_cipher_name()); if (auto group = tls_session_.get_negotiated_group(); !group.empty()) { - std::cerr << "Negotiated group is " << group << std::endl; + std::println(stderr, "Negotiated group is {}", group); } - std::cerr << "Negotiated ALPN is " << tls_session_.get_selected_alpn() - << std::endl; + std::println(stderr, "Negotiated ALPN is {}", + tls_session_.get_selected_alpn()); } - if (tls_session_.send_session_ticket() != 0) { - std::cerr << "Unable to send session ticket" << std::endl; + if (!tls_session_.send_session_ticket()) { + std::println(stderr, "Unable to send session ticket"); } std::array token; @@ -692,21 +690,21 @@ int Handler::handshake_completed() { token.data(), config.static_secret.data(), config.static_secret.size(), path->remote.addr, path->remote.addrlen, t); if (tokenlen < 0) { - std::cerr << "Unable to generate token" << std::endl; + std::println(stderr, "Unable to generate token"); - return 0; + return std::unexpected{Error::QUIC}; } if (auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(), as_unsigned(tokenlen)); rv != 0) { - std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_submit_new_token: {}", + ngtcp2_strerror(rv)); - return -1; + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } namespace { @@ -744,7 +742,7 @@ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->recv_stream_data(flags, stream_id, {data, datalen}) != 0) { + if (!h->recv_stream_data(flags, stream_id, {data, datalen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -757,26 +755,27 @@ int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id, uint64_t offset, uint64_t datalen, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->acked_stream_data_offset(stream_id, datalen) != 0) { + if (!h->acked_stream_data_offset(stream_id, datalen)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::acked_stream_data_offset(int64_t stream_id, uint64_t datalen) { +std::expected Handler::acked_stream_data_offset(int64_t stream_id, + uint64_t datalen) { if (!httpconn_) { - return 0; + return {}; } if (auto rv = nghttp3_conn_add_ack_offset(httpconn_, stream_id, datalen); rv != 0) { - std::cerr << "nghttp3_conn_add_ack_offset: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_add_ack_offset: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - return 0; + return {}; } namespace { @@ -807,7 +806,7 @@ int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id, app_error_code = NGHTTP3_H3_NO_ERROR; } - if (h->on_stream_close(stream_id, app_error_code) != 0) { + if (!h->on_stream_close(stream_id, app_error_code)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; @@ -819,23 +818,23 @@ int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size, uint64_t app_error_code, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->on_stream_reset(stream_id) != 0) { + if (!h->on_stream_reset(stream_id)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::on_stream_reset(int64_t stream_id) { +std::expected Handler::on_stream_reset(int64_t stream_id) { if (httpconn_) { if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); rv != 0) { - std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } } - return 0; + return {}; } namespace { @@ -843,32 +842,31 @@ int stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->on_stream_stop_sending(stream_id) != 0) { + if (!h->on_stream_stop_sending(stream_id)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::on_stream_stop_sending(int64_t stream_id) { +std::expected Handler::on_stream_stop_sending(int64_t stream_id) { if (!httpconn_) { - return 0; + return {}; } if (auto rv = nghttp3_conn_shutdown_stream_read(httpconn_, stream_id); rv != 0) { - std::cerr << "nghttp3_conn_shutdown_stream_read: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_shutdown_stream_read: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - return 0; + return {}; } namespace { void rand_bytes(uint8_t *dest, size_t destlen) { - auto rv = util::generate_secure_random({dest, destlen}); - if (rv != 0) { + if (!util::generate_secure_random({dest, destlen})) { assert(0); abort(); } @@ -882,16 +880,17 @@ void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) { } // namespace namespace { -int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token, - size_t cidlen, void *user_data) { - if (util::generate_secure_random({cid->data, cidlen}) != 0) { +int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, + ngtcp2_stateless_reset_token *token, size_t cidlen, + void *user_data) { + if (!util::generate_secure_random({cid->data, cidlen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } cid->datalen = cidlen; if (ngtcp2_crypto_generate_stateless_reset_token( - token, config.static_secret.data(), config.static_secret.size(), cid) != - 0) { + token->data, config.static_secret.data(), config.static_secret.size(), + cid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -919,9 +918,8 @@ int update_key(ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret, const uint8_t *current_tx_secret, size_t secretlen, void *user_data) { auto h = static_cast(user_data); - if (h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, - tx_iv, current_rx_secret, current_tx_secret, - secretlen) != 0) { + if (!h->update_key(rx_secret, tx_secret, rx_aead_ctx, rx_iv, tx_aead_ctx, + tx_iv, current_rx_secret, current_tx_secret, secretlen)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; @@ -948,7 +946,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) { - std::cerr << "Unable to generate token" << std::endl; + std::println(stderr, "Unable to generate token"); return 0; } @@ -956,8 +954,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) { - std::cerr << "ngtcp2_conn_submit_new_token: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_submit_new_token: {}", + ngtcp2_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1074,22 +1072,22 @@ int http_end_request_headers(nghttp3_conn *conn, int64_t stream_id, int fin, auto h = static_cast(user_data); auto stream = static_cast(stream_user_data); - if (h->http_end_request_headers(stream) != 0) { + if (!h->http_end_request_headers(stream)) { return NGHTTP3_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::http_end_request_headers(Stream *stream) { +std::expected Handler::http_end_request_headers(Stream *stream) { if (config.early_response) { - if (start_response(stream) != 0) { - return -1; + if (auto rv = start_response(stream); !rv) { + return rv; } shutdown_read(stream->stream_id, NGHTTP3_H3_NO_ERROR); } - return 0; + return {}; } namespace { @@ -1097,21 +1095,21 @@ int http_end_stream(nghttp3_conn *conn, int64_t stream_id, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); auto stream = static_cast(stream_user_data); - if (h->http_end_stream(stream) != 0) { + if (!h->http_end_stream(stream)) { return NGHTTP3_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::http_end_stream(Stream *stream) { +std::expected Handler::http_end_stream(Stream *stream) { if (!config.early_response) { return start_response(stream); } - return 0; + return {}; } -int Handler::start_response(Stream *stream) { +std::expected Handler::start_response(Stream *stream) { return stream->start_response(httpconn_); } @@ -1144,8 +1142,8 @@ void Handler::http_stream_close(int64_t stream_id, uint64_t app_error_code) { } if (!config.quiet) { - std::cerr << "HTTP stream " << stream_id << " closed with error code " - << app_error_code << std::endl; + std::println(stderr, "HTTP stream {:#x} closed with error code {:#x}", + stream_id, app_error_code); } streams_.erase(it); @@ -1156,22 +1154,23 @@ int http_stop_sending(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->http_stop_sending(stream_id, app_error_code) != 0) { + if (!h->http_stop_sending(stream_id, app_error_code)) { return NGHTTP3_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::http_stop_sending(int64_t stream_id, uint64_t app_error_code) { +std::expected Handler::http_stop_sending(int64_t stream_id, + uint64_t app_error_code) { if (auto rv = ngtcp2_conn_shutdown_stream_read(conn_, 0, stream_id, app_error_code); rv != 0) { - std::cerr << "ngtcp2_conn_shutdown_stream_read: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_shutdown_stream_read: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } namespace { @@ -1179,22 +1178,23 @@ int http_reset_stream(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->http_reset_stream(stream_id, app_error_code) != 0) { + if (!h->http_reset_stream(stream_id, app_error_code)) { return NGHTTP3_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::http_reset_stream(int64_t stream_id, uint64_t app_error_code) { +std::expected Handler::http_reset_stream(int64_t stream_id, + uint64_t app_error_code) { if (auto rv = ngtcp2_conn_shutdown_stream_write(conn_, 0, stream_id, app_error_code); rv != 0) { - std::cerr << "ngtcp2_conn_shutdown_stream_write: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_shutdown_stream_write: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - return 0; + return {}; } namespace { @@ -1209,15 +1209,15 @@ int http_recv_settings(nghttp3_conn *conn, } } // namespace -int Handler::setup_httpconn() { +std::expected Handler::setup_httpconn() { if (httpconn_) { - return 0; + return {}; } if (ngtcp2_conn_get_streams_uni_left(conn_) < 3) { - std::cerr << "peer does not allow at least 3 unidirectional streams." - << std::endl; - return -1; + std::println(stderr, + "peer does not allow at least 3 unidirectional streams."); + return std::unexpected{Error::QUIC}; } nghttp3_callbacks callbacks{ @@ -1252,9 +1252,8 @@ int Handler::setup_httpconn() { if (auto rv = nghttp3_conn_server_new(&httpconn_, &callbacks, &settings, mem, this); rv != 0) { - std::cerr << "nghttp3_conn_server_new: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_server_new: {}", nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } auto params = ngtcp2_conn_get_local_transport_params(conn_); @@ -1266,20 +1265,20 @@ int Handler::setup_httpconn() { if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &ctrl_stream_id, nullptr); rv != 0) { - std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } if (auto rv = nghttp3_conn_bind_control_stream(httpconn_, ctrl_stream_id); rv != 0) { - std::cerr << "nghttp3_conn_bind_control_stream: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_bind_control_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } if (!config.quiet) { - fprintf(stderr, "http: control stream=%" PRIx64 "\n", ctrl_stream_id); + std::println(stderr, "http: control stream={:#x}", ctrl_stream_id); } int64_t qpack_enc_stream_id, qpack_dec_stream_id; @@ -1287,34 +1286,33 @@ int Handler::setup_httpconn() { if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &qpack_enc_stream_id, nullptr); rv != 0) { - std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } if (auto rv = ngtcp2_conn_open_uni_stream(conn_, &qpack_dec_stream_id, nullptr); rv != 0) { - std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_open_uni_stream: {}", + ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } if (auto rv = nghttp3_conn_bind_qpack_streams(httpconn_, qpack_enc_stream_id, qpack_dec_stream_id); rv != 0) { - std::cerr << "nghttp3_conn_bind_qpack_streams: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_bind_qpack_streams: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } if (!config.quiet) { - fprintf(stderr, - "http: QPACK streams encoder=%" PRIx64 " decoder=%" PRIx64 "\n", - qpack_enc_stream_id, qpack_dec_stream_id); + std::println(stderr, "http: QPACK streams encoder={:#x} decoder={:#x}", + qpack_enc_stream_id, qpack_dec_stream_id); } - return 0; + return {}; } namespace { @@ -1322,20 +1320,21 @@ int extend_max_stream_data(ngtcp2_conn *conn, int64_t stream_id, uint64_t max_data, void *user_data, void *stream_user_data) { auto h = static_cast(user_data); - if (h->extend_max_stream_data(stream_id, max_data) != 0) { + if (!h->extend_max_stream_data(stream_id, max_data)) { return NGTCP2_ERR_CALLBACK_FAILURE; } return 0; } } // namespace -int Handler::extend_max_stream_data(int64_t stream_id, uint64_t max_data) { +std::expected Handler::extend_max_stream_data(int64_t stream_id, + uint64_t max_data) { if (auto rv = nghttp3_conn_unblock_stream(httpconn_, stream_id); rv != 0) { - std::cerr << "nghttp3_conn_unblock_stream: " << nghttp3_strerror(rv) - << std::endl; - return -1; + std::println(stderr, "nghttp3_conn_unblock_stream: {}", + nghttp3_strerror(rv)); + return std::unexpected{Error::HTTP3}; } - return 0; + return {}; } namespace { @@ -1346,7 +1345,7 @@ int recv_tx_key(ngtcp2_conn *conn, ngtcp2_encryption_level level, } auto h = static_cast(user_data); - if (h->setup_httpconn() != 0) { + if (!h->setup_httpconn()) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -1367,11 +1366,12 @@ void Handler::write_qlog(const void *data, size_t datalen) { fwrite(data, 1, datalen, qlog_); } -int Handler::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 token, ngtcp2_token_type token_type, - uint32_t version, TLSServerContext &tls_ctx) { +std::expected +Handler::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 token, ngtcp2_token_type token_type, + uint32_t version, TLSServerContext &tls_ctx) { auto callbacks = ngtcp2_callbacks{ .recv_client_initial = ngtcp2_crypto_recv_client_initial_cb, .recv_crypto_data = ::recv_crypto_data, @@ -1384,7 +1384,6 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, .stream_open = stream_open, .stream_close = stream_close, .rand = rand, - .get_new_connection_id = get_new_connection_id, .remove_connection_id = remove_connection_id, .update_key = ::update_key, .path_validation = path_validation, @@ -1393,16 +1392,18 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, .extend_max_stream_data = ::extend_max_stream_data, .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, .stream_stop_sending = stream_stop_sending, .version_negotiation = ngtcp2_crypto_version_negotiation_cb, .recv_tx_key = ::recv_tx_key, + .get_new_connection_id2 = get_new_connection_id, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; scid_.datalen = NGTCP2_SV_SCIDLEN; - if (util::generate_secure_random({scid_.data, scid_.datalen}) != 0) { - std::cerr << "Could not generate connection ID" << std::endl; - return -1; + if (auto rv = util::generate_secure_random({scid_.data, scid_.datalen}); + !rv) { + std::println(stderr, "Could not generate connection ID"); + return rv; } ngtcp2_settings settings; @@ -1430,9 +1431,9 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, path += ".sqlog"; qlog_ = fopen(path.c_str(), "w"); if (qlog_ == nullptr) { - std::cerr << "Could not open qlog file " << std::quoted(path) << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "Could not open qlog file {}: {}", path, + strerror(errno)); + return std::unexpected{Error::IO}; } settings.qlog_write = ::write_qlog; } @@ -1488,7 +1489,7 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, if (ngtcp2_crypto_generate_stateless_reset_token( params.stateless_reset_token, config.static_secret.data(), config.static_secret.size(), &scid_) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } if (!config.preferred_ipv4_addr.empty() || @@ -1507,20 +1508,21 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, params.preferred_addr.ipv6_present = 1; } - if (util::generate_secure_random( - params.preferred_addr.stateless_reset_token) != 0) { - std::cerr << "Could not generate preferred address stateless reset token" - << std::endl; - return -1; + if (auto rv = util::generate_secure_random( + params.preferred_addr.stateless_reset_token); + !rv) { + std::println( + stderr, "Could not generate preferred address stateless reset token"); + return rv; } params.preferred_addr.cid.datalen = NGTCP2_SV_SCIDLEN; - if (util::generate_secure_random({params.preferred_addr.cid.data, - params.preferred_addr.cid.datalen}) != - 0) { - std::cerr << "Could not generate preferred address connection ID" - << std::endl; - return -1; + if (auto rv = util::generate_secure_random( + {params.preferred_addr.cid.data, params.preferred_addr.cid.datalen}); + !rv) { + std::println(stderr, + "Could not generate preferred address connection ID"); + return rv; } } @@ -1533,12 +1535,12 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, ngtcp2_conn_server_new(&conn_, dcid, &scid_, &path, version, &callbacks, &settings, ¶ms, nullptr, this); rv != 0) { - std::cerr << "ngtcp2_conn_server_new: " << ngtcp2_strerror(rv) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_server_new: {}", ngtcp2_strerror(rv)); + return std::unexpected{Error::QUIC}; } - if (tls_session_.init(tls_ctx, this) != 0) { - return -1; + if (auto rv = tls_session_.init(tls_ctx, this); !rv) { + return rv; } tls_session_.enable_keylog(); @@ -1547,12 +1549,14 @@ int Handler::init(const Endpoint &ep, const Address &local_addr, ev_io_set(&wev_, ep.fd, EV_WRITE); - return 0; + return {}; } -int Handler::feed_data(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data) { +std::expected Handler::feed_data(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data) { auto path = ngtcp2_path{ .local = as_ngtcp2_addr(local_addr), .remote = as_ngtcp2_addr(remote_addr), @@ -1562,15 +1566,15 @@ int Handler::feed_data(const Endpoint &ep, const Address &local_addr, if (auto rv = ngtcp2_conn_read_pkt(conn_, &path, pi, data.data(), data.size(), util::timestamp()); rv != 0) { - std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, "ngtcp2_conn_read_pkt: {}", ngtcp2_strerror(rv)); switch (rv) { case NGTCP2_ERR_DRAINING: start_draining_period(); - return NETWORK_ERR_CLOSE_WAIT; + return std::unexpected{Error::CLOSE_WAIT}; case NGTCP2_ERR_RETRY: - return NETWORK_ERR_RETRY; + return std::unexpected{Error::RETRY_CONN}; case NGTCP2_ERR_DROP_CONN: - return NETWORK_ERR_DROP_CONN; + return std::unexpected{Error::DROP_CONN}; case NGTCP2_ERR_CRYPTO: if (!last_error_.error_code) { ngtcp2_ccerr_set_tls_alert( @@ -1585,58 +1589,57 @@ int Handler::feed_data(const Endpoint &ep, const Address &local_addr, return handle_error(); } - return 0; + return {}; } -int Handler::on_read(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data) { - if (auto rv = feed_data(ep, local_addr, remote_addr, pi, data); rv != 0) { +std::expected Handler::on_read(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data) { + if (auto rv = feed_data(ep, local_addr, remote_addr, pi, data); !rv) { return rv; } update_timer(); - return 0; + return {}; } -int Handler::handle_expiry() { +std::expected Handler::handle_expiry() { auto now = util::timestamp(); if (auto rv = ngtcp2_conn_handle_expiry(conn_, now); rv != 0) { - std::cerr << "ngtcp2_conn_handle_expiry: " << ngtcp2_strerror(rv) - << std::endl; + std::println(stderr, "ngtcp2_conn_handle_expiry: {}", ngtcp2_strerror(rv)); ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0); return handle_error(); } - return 0; + return {}; } -int Handler::on_write() { +std::expected Handler::on_write() { if (ngtcp2_conn_in_closing_period(conn_) || ngtcp2_conn_in_draining_period(conn_)) { - return 0; + return {}; } if (tx_.send_blocked) { - if (auto rv = send_blocked_packet(); rv != 0) { - return rv; - } + send_blocked_packet(); if (tx_.send_blocked) { - return 0; + return {}; } } ev_io_stop(loop_, &wev_); - if (auto rv = write_streams(); rv != 0) { + if (auto rv = write_streams(); !rv) { return rv; } update_timer(); - return 0; + return {}; } namespace { @@ -1663,8 +1666,8 @@ ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, sveccnt = nghttp3_conn_writev_stream(httpconn_, &stream_id, &fin, vec.data(), vec.size()); if (sveccnt < 0) { - std::cerr << "nghttp3_conn_writev_stream: " - << nghttp3_strerror(static_cast(sveccnt)) << std::endl; + std::println(stderr, "nghttp3_conn_writev_stream: {}", + nghttp3_strerror(static_cast(sveccnt))); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(static_cast(sveccnt)), @@ -1701,8 +1704,8 @@ ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, as_unsigned(ndatalen)); rv != 0) { - std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv) - << std::endl; + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); @@ -1713,8 +1716,8 @@ ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, assert(ndatalen == -1); - std::cerr << "ngtcp2_conn_writev_stream: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_conn_writev_stream: {}", + ngtcp2_strerror(static_cast(nwrite))); ngtcp2_ccerr_set_liberr(&last_error_, static_cast(nwrite), nullptr, 0); return NGTCP2_ERR_CALLBACK_FAILURE; @@ -1724,8 +1727,8 @@ ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, if (auto rv = nghttp3_conn_add_write_offset(httpconn_, stream_id, as_unsigned(ndatalen)); rv != 0) { - std::cerr << "nghttp3_conn_add_write_offset: " << nghttp3_strerror(rv) - << std::endl; + std::println(stderr, "nghttp3_conn_add_write_offset: {}", + nghttp3_strerror(rv)); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); return NGTCP2_ERR_CALLBACK_FAILURE; @@ -1736,7 +1739,7 @@ ngtcp2_ssize Handler::write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, } } -int Handler::write_streams() { +std::expected Handler::write_streams() { ngtcp2_path_storage ps; ngtcp2_pkt_info pi; size_t gso_size; @@ -1756,31 +1759,31 @@ int Handler::write_streams() { ngtcp2_conn_update_pkt_tx_time(conn_, ts); if (nwrite == 0) { - return 0; + return {}; } send_packet(ps.path, pi.ecn, txbuf.first(static_cast(nwrite)), gso_size); - return 0; + return {}; } -int Handler::send_packet(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size) { +std::expected Handler::send_packet(const ngtcp2_path &path, + unsigned int ecn, + std::span data, + size_t gso_size) { auto &ep = *static_cast(path.user_data); - auto [rest, rv] = server_->send_packet(ep, no_gso_, path.local, path.remote, - ecn, data, gso_size); - if (rv != 0) { - assert(NETWORK_ERR_SEND_BLOCKED == rv); - + auto rest = server_->send_packet(ep, no_gso_, path.local, path.remote, ecn, + data, gso_size); + if (!rest.empty()) { on_send_blocked(path, ecn, rest, gso_size); start_wev_endpoint(ep); - return rv; + return std::unexpected{Error::SEND_BLOCKED}; } - return 0; + return {}; } void Handler::on_send_blocked(const ngtcp2_path &path, unsigned int ecn, @@ -1815,27 +1818,23 @@ void Handler::start_wev_endpoint(const Endpoint &ep) { ev_io_start(loop_, &wev_); } -int Handler::send_blocked_packet() { +void Handler::send_blocked_packet() { assert(tx_.send_blocked); auto &p = tx_.blocked; - auto [rest, rv] = server_->send_packet( + auto rest = server_->send_packet( *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); - + if (!rest.empty()) { p.data = rest; start_wev_endpoint(*p.endpoint); - return 0; + return; } tx_.send_blocked = false; - - return 0; } void Handler::signal_write() { ev_io_start(loop_, &wev_); } @@ -1849,15 +1848,15 @@ void Handler::start_draining_period() { ev_timer_again(loop_, &timer_); if (!config.quiet) { - std::cerr << "Draining period has started (" << timer_.repeat << " seconds)" - << std::endl; + std::println(stderr, "Draining period has started ({:.9f} seconds)", + timer_.repeat); } } -int Handler::start_closing_period() { +std::expected Handler::start_closing_period() { if (!conn_ || ngtcp2_conn_in_closing_period(conn_) || ngtcp2_conn_in_draining_period(conn_)) { - return 0; + return {}; } ev_io_stop(loop_, &wev_); @@ -1868,8 +1867,8 @@ int Handler::start_closing_period() { ev_timer_again(loop_, &timer_); if (!config.quiet) { - std::cerr << "Closing period has started (" << timer_.repeat << " seconds)" - << std::endl; + std::println(stderr, "Closing period has started ({:.9f} seconds)", + timer_.repeat); } conn_closebuf_ = std::make_unique(NGTCP2_MAX_UDP_PAYLOAD_SIZE); @@ -1883,43 +1882,43 @@ int Handler::start_closing_period() { conn_, &ps.path, &pi, conn_closebuf_->wpos(), conn_closebuf_->left(), &last_error_, util::timestamp()); if (n < 0) { - std::cerr << "ngtcp2_conn_write_connection_close: " - << ngtcp2_strerror(static_cast(n)) << std::endl; - return -1; + std::println(stderr, "ngtcp2_conn_write_connection_close: {}", + ngtcp2_strerror(static_cast(n))); + return std::unexpected{Error::QUIC}; } if (n == 0) { - return 0; + return {}; } conn_closebuf_->push(as_unsigned(n)); - return 0; + return {}; } -int Handler::handle_error() { +std::expected Handler::handle_error() { if (last_error_.type == NGTCP2_CCERR_TYPE_IDLE_CLOSE) { - return -1; + return std::unexpected{Error::INTERNAL}; } - if (start_closing_period() != 0) { - return -1; + if (auto rv = start_closing_period(); !rv) { + return rv; } if (ngtcp2_conn_in_draining_period(conn_)) { - return NETWORK_ERR_CLOSE_WAIT; + return std::unexpected{Error::CLOSE_WAIT}; } - if (auto rv = send_conn_close(); rv != NETWORK_ERR_OK) { + if (auto rv = send_conn_close(); !rv) { return rv; } - return NETWORK_ERR_CLOSE_WAIT; + return std::unexpected{Error::CLOSE_WAIT}; } -int Handler::send_conn_close() { +std::expected Handler::send_conn_close() { if (!config.quiet) { - std::cerr << "Closing Period: TX CONNECTION_CLOSE" << std::endl; + std::println(stderr, "Closing Period: TX CONNECTION_CLOSE"); } assert(conn_closebuf_ && conn_closebuf_->size()); @@ -1933,10 +1932,10 @@ int Handler::send_conn_close() { /* ecn = */ 0, conn_closebuf_->data()); } -int Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, - const ngtcp2_pkt_info *pi, - std::span data) { +std::expected +Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, + const Address &remote_addr, const ngtcp2_pkt_info *pi, + std::span data) { assert(conn_closebuf_ && conn_closebuf_->size()); close_wait_.bytes_recv += data.size(); @@ -1945,20 +1944,20 @@ int Handler::send_conn_close(const Endpoint &ep, const Address &local_addr, if (close_wait_.num_pkts_recv < close_wait_.next_pkts_recv || close_wait_.bytes_recv * 3 < close_wait_.bytes_sent + conn_closebuf_->size()) { - return 0; + return {}; } - auto rv = server_->send_packet(ep, as_ngtcp2_addr(local_addr), - as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, conn_closebuf_->data()); - if (rv != 0) { + if (auto rv = server_->send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, conn_closebuf_->data()); + !rv) { return rv; } close_wait_.bytes_sent += conn_closebuf_->size(); close_wait_.next_pkts_recv *= 2; - return 0; + return {}; } void Handler::update_timer() { @@ -1968,8 +1967,7 @@ void Handler::update_timer() { if (expiry <= now) { if (!config.quiet) { auto t = static_cast(now - expiry) / NGTCP2_SECONDS; - std::cerr << "Timer has already expired: " << std::fixed << t << "s" - << std::defaultfloat << std::endl; + std::println(stderr, "Timer has already expired: {:.9f}s", t); } ev_feed_event(loop_, &timer_, EV_TIMER); @@ -1979,48 +1977,49 @@ void Handler::update_timer() { auto t = static_cast(expiry - now) / NGTCP2_SECONDS; if (!config.quiet) { - std::cerr << "Set timer=" << std::fixed << t << "s" << std::defaultfloat - << std::endl; + std::println(stderr, "Set timer={:.9f}s", t); } timer_.repeat = t; ev_timer_again(loop_, &timer_); } -int Handler::recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data) { +std::expected +Handler::recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data) { if (!config.quiet && !config.no_quic_dump) { debug::print_stream_data(stream_id, data); } if (!httpconn_) { - return 0; + return {}; } 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_stream2: " - << nghttp3_strerror(static_cast(nconsumed)) << std::endl; + std::println(stderr, "nghttp3_conn_read_stream2: {}", + nghttp3_strerror(static_cast(nconsumed))); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(static_cast(nconsumed)), nullptr, 0); - return -1; + return std::unexpected{Error::HTTP3}; } ngtcp2_conn_extend_max_stream_offset(conn_, stream_id, static_cast(nconsumed)); ngtcp2_conn_extend_max_offset(conn_, static_cast(nconsumed)); - return 0; + return {}; } -int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen) { +std::expected +Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, + const uint8_t *current_tx_secret, size_t secretlen) { auto crypto_ctx = ngtcp2_conn_get_crypto_ctx(conn_); auto aead = &crypto_ctx->aead; auto keylen = ngtcp2_crypto_aead_keylen(aead); @@ -2034,26 +2033,27 @@ int Handler::update_key(uint8_t *rx_secret, uint8_t *tx_secret, rx_key.data(), rx_iv, tx_aead_ctx, tx_key.data(), tx_iv, current_rx_secret, current_tx_secret, secretlen) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } if (!config.quiet && config.show_secret) { - std::cerr << "application_traffic rx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic rx secret {}", nkey_update_); debug::print_secrets({rx_secret, secretlen}, {rx_key.data(), keylen}, {rx_iv, ivlen}); - std::cerr << "application_traffic tx secret " << nkey_update_ << std::endl; + std::println(stderr, "application_traffic tx secret {}", nkey_update_); debug::print_secrets({tx_secret, secretlen}, {tx_key.data(), keylen}, {tx_iv, ivlen}); } - return 0; + return {}; } Server *Handler::server() const { return server_; } -int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) { +std::expected Handler::on_stream_close(int64_t stream_id, + uint64_t app_error_code) { if (!config.quiet) { - std::cerr << "QUIC stream " << stream_id << " closed" << std::endl; + std::println(stderr, "QUIC stream {:#x} closed", stream_id); } if (httpconn_) { @@ -2072,15 +2072,15 @@ int Handler::on_stream_close(int64_t stream_id, uint64_t app_error_code) { } break; default: - std::cerr << "nghttp3_conn_close_stream: " << nghttp3_strerror(rv) - << std::endl; + std::println(stderr, "nghttp3_conn_close_stream: {}", + nghttp3_strerror(rv)); ngtcp2_ccerr_set_application_error( &last_error_, nghttp3_err_infer_quic_app_error_code(rv), nullptr, 0); - return -1; + return std::unexpected{Error::HTTP3}; } } - return 0; + return {}; } void Handler::shutdown_read(int64_t stream_id, uint64_t app_error_code) { @@ -2150,8 +2150,8 @@ void Server::close() { } namespace { -int create_sock(Address &local_addr, const char *addr, const char *port, - int family) { +std::expected create_sock(Address &local_addr, const char *addr, + const char *port, int family) { addrinfo hints{ .ai_flags = AI_PASSIVE, .ai_family = family, @@ -2165,8 +2165,8 @@ int create_sock(Address &local_addr, const char *addr, const char *port, } if (auto rv = getaddrinfo(addr, port, &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } auto res_d = defer([res] { freeaddrinfo(res); }); @@ -2174,12 +2174,14 @@ int create_sock(Address &local_addr, const char *addr, const char *port, int fd = -1; for (rp = res; rp; rp = rp->ai_next) { - fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (fd == -1) { + auto maybe_fd = util::create_nonblock_socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (!maybe_fd) { continue; } + fd = *maybe_fd; + if (rp->ai_family == AF_INET6) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, static_cast(sizeof(val))) == -1) { @@ -2217,16 +2219,16 @@ int create_sock(Address &local_addr, const char *addr, const char *port, } if (!rp) { - std::cerr << "Could not bind" << std::endl; - return -1; + std::println(stderr, "Could not bind"); + return std::unexpected{Error::SYSCALL}; } sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(fd, reinterpret_cast(&ss), &len) == -1) { - std::cerr << "getsockname: " << strerror(errno) << std::endl; + std::println(stderr, "getsockname: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } local_addr.set(reinterpret_cast(&ss)); @@ -2237,61 +2239,65 @@ int create_sock(Address &local_addr, const char *addr, const char *port, } // namespace namespace { -int add_endpoint(std::vector &endpoints, const char *addr, - const char *port, int af) { +std::expected add_endpoint(std::vector &endpoints, + const char *addr, const char *port, + int af) { Address dest; - auto fd = create_sock(dest, addr, port, af); - if (fd == -1) { - return -1; + auto maybe_fd = create_sock(dest, addr, port, af); + if (!maybe_fd) { + return std::unexpected{maybe_fd.error()}; } endpoints.emplace_back(); auto &ep = endpoints.back(); ep.addr = dest; - ep.fd = fd; + ep.fd = *maybe_fd; ev_io_init(&ep.rev, sreadcb, 0, EV_READ); ev_set_priority(&ep.rev, EV_MAXPRI); - return 0; + return {}; } } // namespace namespace { -int add_endpoint(std::vector &endpoints, const Address &addr) { +std::expected add_endpoint(std::vector &endpoints, + const Address &addr) { 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; + auto maybe_fd = util::create_nonblock_socket(family, SOCK_DGRAM, 0); + if (!maybe_fd) { + std::println(stderr, "socket: {}", strerror(errno)); + return std::unexpected{maybe_fd.error()}; } + auto fd = *maybe_fd; + int val = 1; if (family == AF_INET6) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } } else if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, static_cast(sizeof(val))) == -1) { close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } fd_set_recv_ecn(fd, family); @@ -2300,9 +2306,9 @@ int add_endpoint(std::vector &endpoints, const Address &addr) { fd_set_udp_gro(fd); if (bind(fd, addr.as_sockaddr(), addr.size()) == -1) { - std::cerr << "bind: " << strerror(errno) << std::endl; + std::println(stderr, "bind: {}", strerror(errno)); close(fd); - return -1; + return std::unexpected{Error::SYSCALL}; } endpoints.emplace_back(Endpoint{}); @@ -2312,33 +2318,44 @@ int add_endpoint(std::vector &endpoints, const Address &addr) { ev_io_init(&ep.rev, sreadcb, 0, EV_READ); ev_set_priority(&ep.rev, EV_MAXPRI); - return 0; + return {}; } } // namespace -int Server::init(const char *addr, const char *port) { +std::expected Server::init(const char *addr, const char *port) { endpoints_.reserve(4); auto ready = false; - if (!util::numeric_host(addr, AF_INET6) && - add_endpoint(endpoints_, addr, port, AF_INET) == 0) { - ready = true; + auto error = Error::INTERNAL; + + if (!util::numeric_host(addr, AF_INET6)) { + if (auto rv = add_endpoint(endpoints_, addr, port, AF_INET); !rv) { + error = rv.error(); + } else { + ready = true; + } } - if (!util::numeric_host(addr, AF_INET) && - add_endpoint(endpoints_, addr, port, AF_INET6) == 0) { - ready = true; + if (!util::numeric_host(addr, AF_INET)) { + if (auto rv = add_endpoint(endpoints_, addr, port, AF_INET6); !rv) { + error = rv.error(); + } else { + ready = true; + } } if (!ready) { - return -1; + return std::unexpected{error}; } - if (!config.preferred_ipv4_addr.empty() && - add_endpoint(endpoints_, config.preferred_ipv4_addr) != 0) { - return -1; + if (!config.preferred_ipv4_addr.empty()) { + if (auto rv = add_endpoint(endpoints_, config.preferred_ipv4_addr); !rv) { + return rv; + } } - if (!config.preferred_ipv6_addr.empty() && - add_endpoint(endpoints_, config.preferred_ipv6_addr) != 0) { - return -1; + + if (!config.preferred_ipv6_addr.empty()) { + if (auto rv = add_endpoint(endpoints_, config.preferred_ipv6_addr); !rv) { + return rv; + } } for (auto &ep : endpoints_) { @@ -2352,10 +2369,10 @@ int Server::init(const char *addr, const char *port) { ev_signal_start(loop_, &sigintev_); - return 0; + return {}; } -int Server::on_read(const Endpoint &ep) { +void Server::on_read(const Endpoint &ep) { sockaddr_storage ss; std::array buf; size_t pktcnt = 0; @@ -2381,7 +2398,7 @@ int Server::on_read(const Endpoint &ep) { for (; pktcnt < MAX_RECV_PKTS;) { if (util::recv_pkt_time_threshold_exceeded( config.cc_algo == NGTCP2_CC_ALGO_BBR, start, pktcnt)) { - return 0; + return; } msg.msg_namelen = sizeof(ss); @@ -2390,9 +2407,9 @@ int Server::on_read(const Endpoint &ep) { auto nread = recvmsg(ep.fd, &msg, 0); if (nread == -1) { if (!(errno == EAGAIN || errno == ENOTCONN)) { - std::cerr << "recvmsg: " << strerror(errno) << std::endl; + std::println(stderr, "recvmsg: {}", strerror(errno)); } - return 0; + return; } // Packets less than 21 bytes never be a valid QUIC packet. @@ -2415,7 +2432,7 @@ int Server::on_read(const Endpoint &ep) { auto local_addr = msghdr_get_local_addr(&msg, ss.ss_family); if (!local_addr) { ++pktcnt; - std::cerr << "Unable to obtain local address" << std::endl; + std::println(stderr, "Unable to obtain local address"); continue; } @@ -2435,11 +2452,11 @@ int Server::on_read(const Endpoint &ep) { if (!config.quiet) { std::array ifname; - 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(pi.ecn) - << std::dec << " " << datalen << " bytes" << std::endl; + std::println( + stderr, + "Received packet: local={} remote={} if={} ecn={:#x} {} bytes", + util::straddr(*local_addr), util::straddr(remote_addr), + if_indextoname(local_addr->ifindex, ifname.data()), pi.ecn, datalen); } // Packets less than 21 bytes never be a valid QUIC packet. @@ -2449,7 +2466,7 @@ int Server::on_read(const Endpoint &ep) { if (debug::packet_lost(config.rx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated incoming packet loss **" << std::endl; + std::println(stderr, "** Simulated incoming packet loss **"); } } else { read_pkt(ep, *local_addr, remote_addr, &pi, {data.data(), datalen}); @@ -2458,8 +2475,6 @@ int Server::on_read(const Endpoint &ep) { data = data.subspan(datalen); } } - - return 0; } void Server::read_pkt(const Endpoint &ep, const Address &local_addr, @@ -2478,8 +2493,9 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, remote_addr); return; default: - std::cerr << "Could not decode version and CID from QUIC packet header: " - << ngtcp2_strerror(rv) << std::endl; + std::println(stderr, + "Could not decode version and CID from QUIC packet header: {}", + ngtcp2_strerror(rv)); return; } @@ -2491,8 +2507,8 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, if (auto rv = ngtcp2_accept(&hd, data.data(), data.size()); rv != 0) { if (!config.quiet) { - std::cerr << "Unexpected packet received: length=" << data.size() - << std::endl; + std::println(stderr, "Unexpected packet received: length={}", + data.size()); } if (!(data[0] & 0x80) && data.size() >= NGTCP2_SV_SCIDLEN + 21) { @@ -2510,7 +2526,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, assert(hd.type == NGTCP2_PKT_INITIAL); if (config.validate_addr || hd.tokenlen) { - std::cerr << "Perform stateless address validation" << std::endl; + std::println(stderr, "Perform stateless address validation"); if (hd.tokenlen == 0) { send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); return; @@ -2524,23 +2540,23 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, switch (hd.token[0]) { case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY2: - 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, remote_addr); - return; - case 1: + if (auto rv = verify_retry_token(&ocid, &hd, remote_addr); !rv) { + if (rv.error() != Error::UNREADABLE_TOKEN) { + send_stateless_connection_close(&hd, ep, local_addr, remote_addr); + + return; + } + hd.token = nullptr; hd.tokenlen = 0; - break; + } else { + pocid = &ocid; + token_type = NGTCP2_TOKEN_TYPE_RETRY; } break; case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR: - if (verify_token(&hd, remote_addr) != 0) { + if (!verify_token(&hd, remote_addr)) { if (config.validate_addr) { send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); return; @@ -2554,7 +2570,7 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, break; default: if (!config.quiet) { - std::cerr << "Ignore unrecognized token" << std::endl; + std::println(stderr, "Ignore unrecognized token"); } if (config.validate_addr) { send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); @@ -2568,23 +2584,20 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, } auto h = std::make_unique(loop_, this); - if (h->init(ep, local_addr, remote_addr, &hd.scid, &hd.dcid, pocid, - {hd.token, hd.tokenlen}, token_type, hd.version, - tls_ctx_) != 0) { + if (!h->init(ep, local_addr, remote_addr, &hd.scid, &hd.dcid, pocid, + {hd.token, hd.tokenlen}, token_type, hd.version, tls_ctx_)) { return; } - switch (h->on_read(ep, local_addr, remote_addr, pi, data)) { - case 0: - break; - case NETWORK_ERR_RETRY: - send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); - return; - default: + if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); !rv) { + if (rv.error() == Error::RETRY_CONN) { + send_retry(&hd, ep, local_addr, remote_addr, data.size() * 3); + } + return; } - if (h->on_write() != 0) { + if (!h->on_write()) { return; } @@ -2609,7 +2622,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, remote_addr, pi, data) != 0) { + if (!h->send_conn_close(ep, local_addr, remote_addr, pi, data)) { remove(h); } return; @@ -2618,8 +2631,8 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, return; } - if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); rv != 0) { - if (rv != NETWORK_ERR_CLOSE_WAIT) { + if (auto rv = h->on_read(ep, local_addr, remote_addr, pi, data); !rv) { + if (rv.error() != Error::CLOSE_WAIT) { remove(h); } return; @@ -2630,32 +2643,30 @@ void Server::read_pkt(const Endpoint &ep, const Address &local_addr, namespace { uint32_t generate_reserved_version(const Address &addr, uint32_t version) { - uint32_t h = 0x811C9DC5u; + uint32_t h = 0x811C9DC5U; const uint8_t *p = reinterpret_cast(addr.as_sockaddr()); const uint8_t *ep = p + addr.size(); for (; p != ep; ++p) { h ^= *p; - h *= 0x01000193u; + h *= 0x01000193U; } version = htonl(version); p = (const uint8_t *)&version; ep = p + sizeof(version); for (; p != ep; ++p) { h ^= *p; - h *= 0x01000193u; + h *= 0x01000193U; } - h &= 0xf0f0f0f0u; - h |= 0x0a0a0a0au; + h &= 0xF0F0F0F0U; + h |= 0x0A0A0A0AU; return h; } } // namespace -int Server::send_version_negotiation(uint32_t version, - std::span dcid, - std::span scid, - const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr) { +std::expected Server::send_version_negotiation( + uint32_t version, std::span dcid, + std::span scid, const Endpoint &ep, const Address &local_addr, + const Address &remote_addr) { Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; std::array sv; @@ -2676,24 +2687,23 @@ int Server::send_version_negotiation(uint32_t version, dcid.data(), dcid.size(), scid.data(), scid.size(), sv.data(), as_unsigned(p - std::ranges::begin(sv))); if (nwrite < 0) { - std::cerr << "ngtcp2_pkt_write_version_negotiation: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; - return -1; + std::println(stderr, "ngtcp2_pkt_write_version_negotiation: {}", + ngtcp2_strerror(static_cast(nwrite))); + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep, - const Address &local_addr, const Address &remote_addr, - size_t max_pktlen) { +std::expected Server::send_retry(const ngtcp2_pkt_hd *chd, + const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + size_t max_pktlen) { std::array host; std::array port; @@ -2701,89 +2711,85 @@ int Server::send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep, host.data(), host.size(), port.data(), port.size(), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } if (!config.quiet) { - std::cerr << "Sending Retry packet to [" << host.data() - << "]:" << port.data() << std::endl; + std::println(stderr, "Sending Retry packet to [{}]:{}", host.data(), + port.data()); } ngtcp2_cid scid; scid.datalen = NGTCP2_SV_SCIDLEN; - if (util::generate_secure_random({scid.data, scid.datalen}) != 0) { - return -1; + if (auto rv = util::generate_secure_random({scid.data, scid.datalen}); !rv) { + return rv; } - std::array token; + std::array tokenbuf; auto t = util::system_clock_now(); auto tokenlen = ngtcp2_crypto_generate_retry_token2( - token.data(), config.static_secret.data(), config.static_secret.size(), + tokenbuf.data(), config.static_secret.data(), config.static_secret.size(), chd->version, remote_addr.as_sockaddr(), remote_addr.size(), &scid, &chd->dcid, t); if (tokenlen < 0) { - return -1; + return std::unexpected{Error::QUIC}; } + auto token = std::span{tokenbuf}.first(as_unsigned(tokenlen)); + if (!config.quiet) { - std::cerr << "Generated address validation token:" << std::endl; - util::hexdump(stderr, token.data(), as_unsigned(tokenlen)); + std::println(stderr, "Generated address validation token:"); + util::hexdump(stderr, token); } Buffer buf{ std::min(static_cast(NGTCP2_MAX_UDP_PAYLOAD_SIZE), max_pktlen)}; - auto nwrite = ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version, - &chd->scid, &scid, &chd->dcid, - token.data(), as_unsigned(tokenlen)); + auto nwrite = + ngtcp2_crypto_write_retry(buf.wpos(), buf.left(), chd->version, &chd->scid, + &scid, &chd->dcid, token.data(), token.size()); if (nwrite < 0) { - std::cerr << "ngtcp2_crypto_write_retry failed" << std::endl; - return -1; + std::println(stderr, "ngtcp2_crypto_write_retry failed"); + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::send_stateless_connection_close(const ngtcp2_pkt_hd *chd, - const Endpoint &ep, - const Address &local_addr, - const Address &remote_addr) { +std::expected Server::send_stateless_connection_close( + const ngtcp2_pkt_hd *chd, const Endpoint &ep, const Address &local_addr, + const Address &remote_addr) { Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; auto nwrite = ngtcp2_crypto_write_connection_close( buf.wpos(), buf.left(), chd->version, &chd->scid, &chd->dcid, NGTCP2_INVALID_TOKEN, nullptr, 0); if (nwrite < 0) { - std::cerr << "ngtcp2_crypto_write_connection_close failed" << std::endl; - return -1; + std::println(stderr, "ngtcp2_crypto_write_connection_close failed"); + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::send_stateless_reset(size_t pktlen, std::span dcid, - const Endpoint &ep, const Address &local_addr, - const Address &remote_addr) { +std::expected +Server::send_stateless_reset(size_t pktlen, std::span dcid, + const Endpoint &ep, const Address &local_addr, + const Address &remote_addr) { if (stateless_reset_bucket_ == 0) { - return 0; + return {}; } --stateless_reset_bucket_; @@ -2796,12 +2802,12 @@ int Server::send_stateless_reset(size_t pktlen, std::span dcid, ngtcp2_cid_init(&cid, dcid.data(), dcid.size()); - std::array token; + ngtcp2_stateless_reset_token token; if (ngtcp2_crypto_generate_stateless_reset_token( - token.data(), config.static_secret.data(), config.static_secret.size(), + token.data, config.static_secret.data(), config.static_secret.size(), &cid) != 0) { - return -1; + return std::unexpected{Error::QUIC}; } // SCID + minimum expansion - NGTCP2_STATELESS_RESET_TOKENLEN @@ -2820,33 +2826,33 @@ int Server::send_stateless_reset(size_t pktlen, std::span dcid, std::array rand_bytes; - if (util::generate_secure_random({rand_bytes.data(), rand_byteslen}) != 0) { - return -1; + if (auto rv = + util::generate_secure_random({rand_bytes.data(), rand_byteslen}); + !rv) { + return rv; } Buffer buf{NGTCP2_MAX_UDP_PAYLOAD_SIZE}; - auto nwrite = ngtcp2_pkt_write_stateless_reset( - buf.wpos(), buf.left(), token.data(), rand_bytes.data(), rand_byteslen); + auto nwrite = ngtcp2_pkt_write_stateless_reset2( + buf.wpos(), buf.left(), &token, rand_bytes.data(), rand_byteslen); if (nwrite < 0) { - std::cerr << "ngtcp2_pkt_write_stateless_reset: " - << ngtcp2_strerror(static_cast(nwrite)) << std::endl; + std::println(stderr, "ngtcp2_pkt_write_stateless_reset2: {}", + ngtcp2_strerror(static_cast(nwrite))); - return -1; + return std::unexpected{Error::QUIC}; } buf.push(as_unsigned(nwrite)); - if (send_packet(ep, as_ngtcp2_addr(local_addr), as_ngtcp2_addr(remote_addr), - /* ecn = */ 0, buf.data()) != NETWORK_ERR_OK) { - return -1; - } - - return 0; + return send_packet(ep, as_ngtcp2_addr(local_addr), + as_ngtcp2_addr(remote_addr), + /* ecn = */ 0, buf.data()); } -int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, - const Address &remote_addr) { +std::expected +Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, + const Address &remote_addr) { int rv; if (!config.quiet) { @@ -2857,13 +2863,13 @@ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, host.data(), host.size(), port.data(), port.size(), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } - std::cerr << "Verifying Retry token from [" << host.data() - << "]:" << port.data() << std::endl; - util::hexdump(stderr, hd->token, hd->tokenlen); + std::println(stderr, "Verifying Retry token from [{}]:{}", host.data(), + port.data()); + util::hexdump(stderr, {hd->token, hd->tokenlen}); } auto t = util::system_clock_now(); @@ -2876,24 +2882,25 @@ int Server::verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, case 0: break; case NGTCP2_CRYPTO_ERR_VERIFY_TOKEN: - std::cerr << "Could not verify Retry token" << std::endl; + std::println(stderr, "Could not verify Retry token"); - return -1; + return std::unexpected{Error::QUIC}; default: - std::cerr << "Could not read Retry token. Continue without the token" - << std::endl; + std::println(stderr, + "Could not read Retry token. Continue without the token"); - return 1; + return std::unexpected{Error::UNREADABLE_TOKEN}; } if (!config.quiet) { - std::cerr << "Token was successfully validated" << std::endl; + std::println(stderr, "Token was successfully validated"); } - return 0; + return {}; } -int Server::verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr) { +std::expected Server::verify_token(const ngtcp2_pkt_hd *hd, + const Address &remote_addr) { std::array host; std::array port; @@ -2901,14 +2908,14 @@ int Server::verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr) { host.data(), host.size(), port.data(), port.size(), NI_NUMERICHOST | NI_NUMERICSERV); rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } if (!config.quiet) { - std::cerr << "Verifying token from [" << host.data() << "]:" << port.data() - << std::endl; - util::hexdump(stderr, hd->token, hd->tokenlen); + std::println(stderr, "Verifying token from [{}]:{}", host.data(), + port.data()); + util::hexdump(stderr, {hd->token, hd->tokenlen}); } auto t = util::system_clock_now(); @@ -2917,56 +2924,64 @@ int Server::verify_token(const ngtcp2_pkt_hd *hd, const Address &remote_addr) { 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; + std::println(stderr, "Could not verify token"); - return -1; + return std::unexpected{Error::QUIC}; } if (!config.quiet) { - std::cerr << "Token was successfully validated" << std::endl; + std::println(stderr, "Token was successfully validated"); } - return 0; + return {}; } -int Server::send_packet(const Endpoint &ep, const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, unsigned int ecn, - std::span data) { +std::expected Server::send_packet(const Endpoint &ep, + const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data) { auto no_gso = false; - auto [_, rv] = + auto rest = send_packet(ep, no_gso, local_addr, remote_addr, ecn, data, data.size()); + if (!rest.empty()) { + return std::unexpected{Error::SEND_BLOCKED}; + } - return rv; + return {}; } -std::pair, int> -Server::send_packet(const Endpoint &ep, bool &no_gso, - const ngtcp2_addr &local_addr, - const ngtcp2_addr &remote_addr, unsigned int ecn, - std::span data, size_t gso_size) { +std::span Server::send_packet(const Endpoint &ep, bool &no_gso, + const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data, + size_t gso_size) { assert(gso_size); if (debug::packet_lost(config.tx_loss_prob)) { if (!config.quiet) { - std::cerr << "** Simulated outgoing packet loss **" << std::endl; + std::println(stderr, "** Simulated outgoing packet loss **"); } - return {{}, NETWORK_ERR_OK}; + return {}; } if (no_gso && data.size() > gso_size) { for (; !data.empty();) { auto len = std::min(gso_size, data.size()); - auto [_, rv] = send_packet(ep, no_gso, local_addr, remote_addr, ecn, - data.first(len), len); - if (rv != 0) { - return {data, rv}; + auto rest = send_packet(ep, no_gso, local_addr, remote_addr, ecn, + data.first(len), len); + if (!rest.empty()) { + assert(rest.size() == len); + + return data; } data = data.subspan(len); } - return {{}, 0}; + return {}; } iovec msg_iov{ @@ -3073,13 +3088,13 @@ Server::send_packet(const Endpoint &ep, bool &no_gso, #if EAGAIN != EWOULDBLOCK case EWOULDBLOCK: #endif // EAGAIN != EWOULDBLOCK - return {data, NETWORK_ERR_SEND_BLOCKED}; + return data; #ifdef UDP_SEGMENT case EIO: if (data.size() > gso_size) { // GSO failure; send each packet in a separate sendmsg call. - std::cerr << "sendmsg: disabling GSO due to " << strerror(errno) - << std::endl; + std::println(stderr, "sendmsg: disabling GSO due to {}", + strerror(errno)); no_gso = true; @@ -3090,22 +3105,20 @@ Server::send_packet(const Endpoint &ep, bool &no_gso, #endif // defined(UDP_SEGMENT) } - std::cerr << "sendmsg: " << strerror(errno) << std::endl; + std::println(stderr, "sendmsg: {}", strerror(errno)); // TODO We have packet which is expected to fail to send (e.g., // path validation to old path). - return {{}, NETWORK_ERR_OK}; + return {}; } if (!config.quiet) { - std::cerr << "Sent packet: local=" - << util::straddr(local_addr.addr, local_addr.addrlen) - << " remote=" - << util::straddr(remote_addr.addr, remote_addr.addrlen) - << " ecn=0x" << std::hex << ecn << std::dec << " " << nwrite - << " bytes" << std::endl; + std::println(stderr, "Sent packet: local={} remote={} ecn={:#x} {} bytes", + util::straddr(local_addr.addr, local_addr.addrlen), + util::straddr(remote_addr.addr, remote_addr.addrlen), ecn, + nwrite); } - return {{}, NETWORK_ERR_OK}; + return {}; } void Server::associate_cid(const ngtcp2_cid *cid, Handler *h) { @@ -3138,9 +3151,10 @@ void Server::on_stateless_reset_regen() { } namespace { -int parse_host_port(Address &dest, int af, const std::string_view &host_port) { +std::expected parse_host_port(int af, + std::string_view host_port) { if (host_port.empty()) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } auto first = std::ranges::begin(host_port); @@ -3153,19 +3167,19 @@ int parse_host_port(Address &dest, int af, const std::string_view &host_port) { auto it = std::ranges::find(first, last, ']'); if (it == last) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } hostv = std::string_view{first, it}; first = it + 1; if (first == last || *first != ':') { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } } else { auto it = std::ranges::find(first, last, ':'); if (it == last) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } hostv = std::string_view{first, it}; @@ -3173,7 +3187,7 @@ int parse_host_port(Address &dest, int af, const std::string_view &host_port) { } if (++first == last) { - return -1; + return std::unexpected{Error::INVALID_ARGUMENT}; } std::array host; @@ -3187,16 +3201,17 @@ int parse_host_port(Address &dest, int af, const std::string_view &host_port) { auto svc = first; if (auto rv = getaddrinfo(host.data(), svc, &hints, &res); rv != 0) { - std::cerr << "getaddrinfo: [" << host.data() << "]:" << svc << ": " - << gai_strerror(rv) << std::endl; - return -1; + std::println(stderr, "getaddrinfo: [{}]:{}: {}", host.data(), svc, + gai_strerror(rv)); + return std::unexpected{Error::LIBC}; } + Address dest; dest.set(res->ai_addr); freeaddrinfo(res); - return 0; + return dest; } } // namespace @@ -3205,17 +3220,17 @@ const char *prog = "server"; } // namespace namespace { -void print_usage() { - std::cerr << "Usage: " << prog - << " [OPTIONS] " - "" - << std::endl; +void print_usage(FILE *out) { + std::println( + out, + "Usage: {} [OPTIONS] ", + prog); } } // namespace namespace { void print_help() { - print_usage(); + print_usage(stdout); Config config; @@ -3481,7 +3496,7 @@ int main(int argc, char **argv) { // --htdocs auto path = realpath(optarg, nullptr); if (path == nullptr) { - std::cerr << "path: invalid path " << std::quoted(optarg) << std::endl; + std::println(stderr, "path: invalid path {}", optarg); exit(EXIT_FAILURE); } config.htdocs = path; @@ -3513,14 +3528,14 @@ int main(int argc, char **argv) { config.validate_addr = true; break; case '?': - print_usage(); + print_usage(stderr); exit(EXIT_FAILURE); case 0: switch (flag) { case 1: // --ciphers if (util::crypto_default_ciphers()[0] == '\0') { - std::cerr << "ciphers: not supported" << std::endl; + std::println(stderr, "ciphers: not supported"); exit(EXIT_FAILURE); } config.ciphers = optarg; @@ -3532,29 +3547,36 @@ int main(int argc, char **argv) { case 3: // --timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "timeout: invalid argument" << std::endl; + std::println(stderr, "timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.timeout = *t; } break; - case 4: + case 4: { // --preferred-ipv4-addr - if (parse_host_port(config.preferred_ipv4_addr, AF_INET, optarg) != 0) { - std::cerr << "preferred-ipv4-addr: could not use " - << std::quoted(optarg) << std::endl; + auto maybe_addr = parse_host_port(AF_INET, optarg); + if (!maybe_addr) { + std::println(stderr, "preferred-ipv4-addr: could not use {}", optarg); exit(EXIT_FAILURE); } + + config.preferred_ipv4_addr = *maybe_addr; + break; - case 5: + } + case 5: { // --preferred-ipv6-addr - if (parse_host_port(config.preferred_ipv6_addr, AF_INET6, optarg) != - 0) { - std::cerr << "preferred-ipv6-addr: could not use " - << std::quoted(optarg) << std::endl; + auto maybe_addr = parse_host_port(AF_INET6, optarg); + if (!maybe_addr) { + std::println(stderr, "preferred-ipv6-addr: could not use {}", optarg); exit(EXIT_FAILURE); } + + config.preferred_ipv6_addr = *maybe_addr; + break; + } case 6: // --mime-types-file config.mime_types_file = optarg; @@ -3582,7 +3604,7 @@ int main(int argc, char **argv) { case 12: // --max-data if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-data: invalid argument" << std::endl; + std::println(stderr, "max-data: invalid argument"); exit(EXIT_FAILURE); } else { config.max_data = *n; @@ -3591,8 +3613,7 @@ int main(int argc, char **argv) { case 13: // --max-stream-data-bidi-local if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-local: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-local: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_local = *n; @@ -3601,8 +3622,7 @@ int main(int argc, char **argv) { case 14: // --max-stream-data-bidi-remote if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-bidi-remote: invalid argument" - << std::endl; + std::println(stderr, "max-stream-data-bidi-remote: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_bidi_remote = *n; @@ -3611,7 +3631,7 @@ int main(int argc, char **argv) { case 15: // --max-stream-data-uni if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-data-uni: invalid argument" << std::endl; + std::println(stderr, "max-stream-data-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_data_uni = *n; @@ -3620,7 +3640,7 @@ int main(int argc, char **argv) { case 16: // --max-streams-bidi if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-bidi: invalid argument" << std::endl; + std::println(stderr, "max-streams-bidi: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_bidi = *n; @@ -3629,7 +3649,7 @@ int main(int argc, char **argv) { case 17: // --max-streams-uni if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "max-streams-uni: invalid argument" << std::endl; + std::println(stderr, "max-streams-uni: invalid argument"); exit(EXIT_FAILURE); } else { config.max_streams_uni = *n; @@ -3638,7 +3658,7 @@ int main(int argc, char **argv) { case 18: // --max-dyn-length if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-dyn-length: invalid argument" << std::endl; + std::println(stderr, "max-dyn-length: invalid argument"); exit(EXIT_FAILURE); } else { config.max_dyn_length = *n; @@ -3658,12 +3678,12 @@ int main(int argc, char **argv) { config.cc_algo = NGTCP2_CC_ALGO_BBR; break; } - std::cerr << "cc: specify cubic, reno, or bbr" << std::endl; + std::println(stderr, "cc: specify cubic, reno, or bbr"); exit(EXIT_FAILURE); case 20: // --initial-rtt if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "initial-rtt: invalid argument" << std::endl; + std::println(stderr, "initial-rtt: invalid argument"); exit(EXIT_FAILURE); } else { config.initial_rtt = *t; @@ -3672,11 +3692,11 @@ int main(int argc, char **argv) { case 21: // --max-udp-payload-size if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-udp-payload-size: invalid argument" << std::endl; + std::println(stderr, "max-udp-payload-size: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println(stderr, "max-udp-payload-size: must not exceed {}", + NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else { config.max_udp_payload_size = *n; @@ -3689,7 +3709,7 @@ int main(int argc, char **argv) { case 23: // --max-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-window: invalid argument" << std::endl; + std::println(stderr, "max-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_window = *n; @@ -3698,7 +3718,7 @@ int main(int argc, char **argv) { case 24: // --max-stream-window if (auto n = util::parse_uint_iec(optarg); !n) { - std::cerr << "max-stream-window: invalid argument" << std::endl; + std::println(stderr, "max-stream-window: invalid argument"); exit(EXIT_FAILURE); } else { config.max_stream_window = *n; @@ -3707,7 +3727,7 @@ int main(int argc, char **argv) { case 26: // --handshake-timeout if (auto t = util::parse_duration(optarg); !t) { - std::cerr << "handshake-timeout: invalid argument" << std::endl; + std::println(stderr, "handshake-timeout: invalid argument"); exit(EXIT_FAILURE); } else { config.handshake_timeout = *t; @@ -3717,8 +3737,9 @@ int main(int argc, char **argv) { // --preferred-versions auto l = util::split_str(optarg); if (l.size() > max_preferred_versionslen) { - std::cerr << "preferred-versions: too many versions > " - << max_preferred_versionslen << std::endl; + std::println(stderr, "preferred-versions: too many versions > {}", + max_preferred_versionslen); + exit(EXIT_FAILURE); } config.preferred_versions.resize(l.size()); auto it = std::ranges::begin(config.preferred_versions); @@ -3733,13 +3754,12 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "preferred-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: invalid version {}", k); exit(EXIT_FAILURE); } if (!ngtcp2_is_supported_version(*rv)) { - std::cerr << "preferred-versions: unsupported version " - << std::quoted(k) << std::endl; + std::println(stderr, "preferred-versions: unsupported version {}", + k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -3762,8 +3782,7 @@ int main(int argc, char **argv) { } auto rv = util::parse_version(k); if (!rv) { - std::cerr << "available-versions: invalid version " - << std::quoted(k) << std::endl; + std::println(stderr, "available-versions: invalid version {}", k); exit(EXIT_FAILURE); } *it++ = *rv; @@ -3777,10 +3796,10 @@ int main(int argc, char **argv) { case 30: // --ack-thresh if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "ack-thresh: invalid argument" << std::endl; + std::println(stderr, "ack-thresh: invalid argument"); exit(EXIT_FAILURE); } else if (*n > 100) { - std::cerr << "ack-thresh: must not exceed 100" << std::endl; + std::println(stderr, "ack-thresh: must not exceed 100"); exit(EXIT_FAILURE); } else { config.ack_thresh = *n; @@ -3789,11 +3808,11 @@ int main(int argc, char **argv) { case 31: // --initial-pkt-num if (auto n = util::parse_uint(optarg); !n) { - std::cerr << "initial-pkt-num: invalid argument" << std::endl; + std::println(stderr, "initial-pkt-num: invalid argument"); exit(EXIT_FAILURE); } else if (*n > INT32_MAX) { - std::cerr << "initial-pkt-num: must not exceed (1 << 31) - 1" - << std::endl; + std::println(stderr, + "initial-pkt-num: must not exceed (1 << 31) - 1"); exit(EXIT_FAILURE); } else { config.initial_pkt_num = static_cast(*n); @@ -3804,14 +3823,13 @@ int main(int argc, char **argv) { auto l = util::split_str(optarg); for (auto &s : l) { if (auto n = util::parse_uint_iec(s); !n) { - std::cerr << "pmtud-probes: invalid argument" << std::endl; + std::println(stderr, "pmtud-probes: invalid argument"); exit(EXIT_FAILURE); } 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; + std::println( + stderr, "pmtud-probes: must be in range [{}, {}], inclusive.", + NGTCP2_MAX_UDP_PAYLOAD_SIZE + 1, NGTCP2_MAX_TX_UDP_PAYLOAD_SIZE); exit(EXIT_FAILURE); } else { config.pmtud_probes.push_back(static_cast(*n)); @@ -3829,8 +3847,7 @@ int main(int argc, char **argv) { if (auto max = std::numeric_limits::max(); max < origin.size()) { - std::cerr << "origin: must be less than or equal to " << max - << std::endl; + std::println(stderr, "origin: must be less than or equal to {}", max); exit(EXIT_FAILURE); } @@ -3839,7 +3856,7 @@ int main(int argc, char **argv) { } config.origin_list->push_back(static_cast(origin.size() >> 8)); - config.origin_list->push_back(origin.size() & 0xff); + config.origin_list->push_back(origin.size() & 0xFF); std::ranges::copy(origin, std::back_inserter(*config.origin_list)); break; @@ -3856,13 +3873,13 @@ int main(int argc, char **argv) { // --gso-burst auto n = util::parse_uint(optarg); if (!n) { - std::cerr << "gso-burst: invalid argument" << std::endl; + std::println(stderr, "gso-burst: invalid argument"); exit(EXIT_FAILURE); } if (*n > 64) { - std::cerr << "gso-burst: must be in range [0, 64], inclusive." - << std::endl; + std::println(stderr, + "gso-burst: must be in range [0, 64], inclusive."); exit(EXIT_FAILURE); } @@ -3878,8 +3895,8 @@ int main(int argc, char **argv) { } if (argc - optind < 4) { - std::cerr << "Too few arguments" << std::endl; - print_usage(); + std::println(stderr, "Too few arguments"); + print_usage(stderr); exit(EXIT_FAILURE); } @@ -3889,18 +3906,19 @@ int main(int argc, char **argv) { auto cert_file = argv[optind++]; if (auto n = util::parse_uint(port); !n) { - std::cerr << "port: invalid port number" << std::endl; + std::println(stderr, "port: invalid port number"); exit(EXIT_FAILURE); } else if (*n > 65535) { - std::cerr << "port: must not exceed 65535" << std::endl; + std::println(stderr, "port: must not exceed 65535"); exit(EXIT_FAILURE); } else { config.port = static_cast(*n); } if (auto mt = util::read_mime_types(config.mime_types_file); !mt) { - std::cerr << "mime-types-file: Could not read MIME media types file " - << std::quoted(config.mime_types_file) << std::endl; + std::println(stderr, + "mime-types-file: Could not read MIME media types file {}", + config.mime_types_file); } else { config.mime_types = std::move(*mt); } @@ -3908,8 +3926,8 @@ int main(int argc, char **argv) { if (!ech_config_file.empty()) { auto ech_config = util::read_ech_server_config(ech_config_file); if (!ech_config) { - std::cerr << "ech-config-file: Could not read private key and ECHConfig" - << std::endl; + std::println(stderr, + "ech-config-file: Could not read private key and ECHConfig"); exit(EXIT_FAILURE); } @@ -3918,7 +3936,7 @@ int main(int argc, char **argv) { TLSServerContext tls_ctx; - if (tls_ctx.init(private_key_file, cert_file, AppProtocol::H3) != 0) { + if (!tls_ctx.init(private_key_file, cert_file, AppProtocol::H3)) { exit(EXIT_FAILURE); } @@ -3926,7 +3944,7 @@ int main(int argc, char **argv) { config.htdocs += '/'; } - std::cerr << "Using document root " << config.htdocs << std::endl; + std::println(stderr, "Using document root {}", config.htdocs); auto ev_loop_d = defer([] { ev_loop_destroy(EV_DEFAULT); }); @@ -3938,13 +3956,13 @@ int main(int argc, char **argv) { } } - if (util::generate_secret(config.static_secret) != 0) { - std::cerr << "Unable to generate static secret" << std::endl; + if (!util::generate_secure_random(config.static_secret)) { + std::println(stderr, "Unable to generate static secret"); exit(EXIT_FAILURE); } Server s(EV_DEFAULT, tls_ctx); - if (s.init(addr, port) != 0) { + if (!s.init(addr, port)) { exit(EXIT_FAILURE); } diff --git a/deps/ngtcp2/ngtcp2/examples/server.h b/deps/ngtcp2/ngtcp2/examples/server.h index ad12f040fe17bb..3f0cdee8574038 100644 --- a/deps/ngtcp2/ngtcp2/examples/server.h +++ b/deps/ngtcp2/ngtcp2/examples/server.h @@ -57,14 +57,16 @@ struct FileEntry; struct Stream { Stream(int64_t stream_id, Handler *handler); - int start_response(nghttp3_conn *conn); - std::pair open_file(const std::string &path); + std::expected start_response(nghttp3_conn *conn); + std::expected open_file(const std::string &path); void map_file(const FileEntry &fe); - int send_status_response(nghttp3_conn *conn, unsigned int status_code, - const std::vector &extra_headers = {}); - int send_redirect_response(nghttp3_conn *conn, unsigned int status_code, - const std::string_view &path); - int64_t find_dyn_length(const std::string_view &path); + std::expected + send_status_response(nghttp3_conn *conn, unsigned int status_code, + const std::vector &extra_headers = {}); + std::expected send_redirect_response(nghttp3_conn *conn, + unsigned int status_code, + std::string_view path); + std::expected find_dyn_length(std::string_view path); void http_acked_stream_data(uint64_t datalen); int64_t stream_id; @@ -101,73 +103,88 @@ class Handler : public HandlerBase { Handler(struct ev_loop *loop, Server *server); ~Handler(); - 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 token, ngtcp2_token_type token_type, - uint32_t version, TLSServerContext &tls_ctx); + std::expected + 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 token, ngtcp2_token_type token_type, + uint32_t version, TLSServerContext &tls_ctx); - int on_read(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data); - int on_write(); - int write_streams(); - int feed_data(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data); + std::expected on_read(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data); + std::expected on_write(); + std::expected write_streams(); + std::expected feed_data(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data); void update_timer(); - int handle_expiry(); + std::expected handle_expiry(); void signal_write(); - int handshake_completed(); + std::expected handshake_completed(); Server *server() const; - int recv_stream_data(uint32_t flags, int64_t stream_id, - std::span data); - int acked_stream_data_offset(int64_t stream_id, uint64_t datalen); + std::expected recv_stream_data(uint32_t flags, int64_t stream_id, + std::span data); + std::expected acked_stream_data_offset(int64_t stream_id, + uint64_t datalen); uint32_t version() const; void on_stream_open(int64_t stream_id); - int on_stream_close(int64_t stream_id, uint64_t app_error_code); + std::expected on_stream_close(int64_t stream_id, + uint64_t app_error_code); void start_draining_period(); - int start_closing_period(); - int handle_error(); - int send_conn_close(); - int send_conn_close(const Endpoint &ep, const Address &local_addr, - const Address &remote_addr, const ngtcp2_pkt_info *pi, - std::span data); + std::expected start_closing_period(); + std::expected handle_error(); + std::expected send_conn_close(); + std::expected send_conn_close(const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + const ngtcp2_pkt_info *pi, + std::span data); - int update_key(uint8_t *rx_secret, uint8_t *tx_secret, - ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, - ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, - const uint8_t *current_rx_secret, - const uint8_t *current_tx_secret, size_t secretlen); + std::expected + update_key(uint8_t *rx_secret, uint8_t *tx_secret, + ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv, + ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv, + const uint8_t *current_rx_secret, const uint8_t *current_tx_secret, + size_t secretlen); - int setup_httpconn(); + std::expected setup_httpconn(); void http_consume(int64_t stream_id, size_t nconsumed); void extend_max_remote_streams_bidi(uint64_t max_streams); Stream *find_stream(int64_t stream_id); void http_begin_request_headers(int64_t stream_id); void http_recv_request_header(Stream *stream, int32_t token, nghttp3_rcbuf *name, nghttp3_rcbuf *value); - int http_end_request_headers(Stream *stream); - int http_end_stream(Stream *stream); - int start_response(Stream *stream); - int on_stream_reset(int64_t stream_id); - int on_stream_stop_sending(int64_t stream_id); - int extend_max_stream_data(int64_t stream_id, uint64_t max_data); + std::expected http_end_request_headers(Stream *stream); + std::expected http_end_stream(Stream *stream); + std::expected start_response(Stream *stream); + std::expected on_stream_reset(int64_t stream_id); + std::expected on_stream_stop_sending(int64_t stream_id); + std::expected extend_max_stream_data(int64_t stream_id, + uint64_t max_data); void shutdown_read(int64_t stream_id, uint64_t app_error_code); void http_acked_stream_data(Stream *stream, uint64_t datalen); void http_stream_close(int64_t stream_id, uint64_t app_error_code); - int http_stop_sending(int64_t stream_id, uint64_t app_error_code); - int http_reset_stream(int64_t stream_id, uint64_t app_error_code); + std::expected http_stop_sending(int64_t stream_id, + uint64_t app_error_code); + std::expected http_reset_stream(int64_t stream_id, + uint64_t app_error_code); void write_qlog(const void *data, size_t datalen); void on_send_blocked(const ngtcp2_path &path, unsigned int ecn, std::span data, size_t gso_size); void start_wev_endpoint(const Endpoint &ep); - int send_packet(const ngtcp2_path &path, unsigned int ecn, - std::span data, size_t gso_size); - int send_blocked_packet(); + std::expected send_packet(const ngtcp2_path &path, + unsigned int ecn, + std::span data, + size_t gso_size); + void send_blocked_packet(); ngtcp2_ssize write_pkt(ngtcp2_path *path, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts); @@ -215,35 +232,44 @@ class Server { Server(struct ev_loop *loop, TLSServerContext &tls_ctx); ~Server(); - int init(const char *addr, const char *port); + std::expected init(const char *addr, const char *port); void disconnect(); void close(); - int on_read(const Endpoint &ep); + void on_read(const Endpoint &ep); void read_pkt(const Endpoint &ep, const Address &local_addr, const Address &remote_addr, const ngtcp2_pkt_info *pi, std::span data); - int send_version_negotiation(uint32_t version, std::span dcid, - std::span scid, - const Endpoint &ep, const Address &local_addr, - const Address &remote_addr); - int send_retry(const ngtcp2_pkt_hd *chd, const Endpoint &ep, - 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 Address &remote_addr); - int send_stateless_reset(size_t pktlen, std::span dcid, - const Endpoint &ep, const Address &local_addr, + std::expected + send_version_negotiation(uint32_t version, std::span dcid, + std::span scid, const Endpoint &ep, + const Address &local_addr, const Address &remote_addr); - int verify_retry_token(ngtcp2_cid *ocid, const ngtcp2_pkt_hd *hd, - 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 data); - std::pair, int> + std::expected send_retry(const ngtcp2_pkt_hd *chd, + const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr, + size_t max_pktlen); + std::expected + send_stateless_connection_close(const ngtcp2_pkt_hd *chd, const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr); + std::expected send_stateless_reset(size_t pktlen, + std::span dcid, + const Endpoint &ep, + const Address &local_addr, + const Address &remote_addr); + std::expected verify_retry_token(ngtcp2_cid *ocid, + const ngtcp2_pkt_hd *hd, + const Address &remote_addr); + std::expected verify_token(const ngtcp2_pkt_hd *hd, + const Address &remote_addr); + std::expected send_packet(const Endpoint &ep, + const ngtcp2_addr &local_addr, + const ngtcp2_addr &remote_addr, + unsigned int ecn, + std::span data); + std::span send_packet(const Endpoint &ep, bool &no_gso, const ngtcp2_addr &local_addr, const ngtcp2_addr &remote_addr, unsigned int ecn, std::span data, size_t gso_size); diff --git a/deps/ngtcp2/ngtcp2/examples/server_base.h b/deps/ngtcp2/ngtcp2/examples/server_base.h index 5c838bf6971c20..a600c433ab32e3 100644 --- a/deps/ngtcp2/ngtcp2/examples/server_base.h +++ b/deps/ngtcp2/ngtcp2/examples/server_base.h @@ -171,7 +171,7 @@ struct Config { }; struct HTTPHeader { - HTTPHeader(const std::string_view &name, const std::string_view &value) + HTTPHeader(std::string_view name, std::string_view value) : name{name}, value{value} {} std::string_view name; diff --git a/deps/ngtcp2/ngtcp2/examples/shared.cc b/deps/ngtcp2/ngtcp2/examples/shared.cc index 66c44ab51951ed..f9714c69ec14f1 100644 --- a/deps/ngtcp2/ngtcp2/examples/shared.cc +++ b/deps/ngtcp2/ngtcp2/examples/shared.cc @@ -92,13 +92,13 @@ void fd_set_recv_ecn(int fd, int family) { case AF_INET: if (setsockopt(fd, IPPROTO_IP, IP_RECVTOS, &tos, static_cast(sizeof(tos))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); } break; case AF_INET6: if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS, &tos, static_cast(sizeof(tos))) == -1) { - std::cerr << "setsockopt: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: {}", strerror(errno)); } break; } @@ -113,16 +113,15 @@ void fd_set_ip_mtu_discover(int fd, int family) { val = IP_PMTUDISC_PROBE; if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: IP_MTU_DISCOVER: " << strerror(errno) - << std::endl; + std::println(stderr, "setsockopt: IP_MTU_DISCOVER: {}", strerror(errno)); } break; case AF_INET6: val = IPV6_PMTUDISC_PROBE; if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: IPV6_MTU_DISCOVER: " << strerror(errno) - << std::endl; + std::println(stderr, "setsockopt: IPV6_MTU_DISCOVER: {}", + strerror(errno)); } break; } @@ -137,14 +136,13 @@ void fd_set_ip_dontfrag(int fd, int family) { case AF_INET: if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: IP_DONTFRAG: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: IP_DONTFRAG: {}", strerror(errno)); } break; case AF_INET6: if (setsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: IPV6_DONTFRAG: " << strerror(errno) - << std::endl; + std::println(stderr, "setsockopt: IPV6_DONTFRAG: {}", strerror(errno)); } break; } @@ -157,12 +155,12 @@ void fd_set_udp_gro(int fd) { if (setsockopt(fd, IPPROTO_UDP, UDP_GRO, &val, static_cast(sizeof(val))) == -1) { - std::cerr << "setsockopt: UDP_GRO: " << strerror(errno) << std::endl; + std::println(stderr, "setsockopt: UDP_GRO: {}", strerror(errno)); } #endif // defined(UDP_GRO) } -std::optional
msghdr_get_local_addr(msghdr *msg, int family) { +std::expected msghdr_get_local_addr(msghdr *msg, int family) { switch (family) { case AF_INET: for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { @@ -178,7 +176,7 @@ std::optional
msghdr_get_local_addr(msghdr *msg, int family) { return res; } } - return {}; + return std::unexpected{Error::NOT_FOUND}; case AF_INET6: for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { @@ -193,9 +191,9 @@ std::optional
msghdr_get_local_addr(msghdr *msg, int family) { return res; } } - return {}; + return std::unexpected{Error::NOT_FOUND}; } - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } size_t msghdr_get_udp_gro(msghdr *msg) { @@ -224,7 +222,8 @@ struct nlmsg { }; namespace { -int send_netlink_msg(int fd, const Address &remote_addr, uint32_t seq) { +std::expected send_netlink_msg(int fd, const Address &remote_addr, + uint32_t seq) { nlmsg nlmsg{ .hdr{ .nlmsg_type = RTM_GETROUTE, @@ -285,17 +284,17 @@ int send_netlink_msg(int fd, const Address &remote_addr, uint32_t seq) { } while (nwrite == -1 && errno == EINTR); if (nwrite == -1) { - std::cerr << "sendmsg: Could not write netlink message: " << strerror(errno) - << std::endl; - return -1; + std::println(stderr, "sendmsg: Could not write netlink message: {}", + strerror(errno)); + return std::unexpected{Error::SYSCALL}; } - return 0; + return {}; } } // namespace namespace { -int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { +std::expected recv_netlink_msg(int fd, uint32_t seq) { std::array buf; iovec iov = { .iov_base = buf.data(), @@ -309,41 +308,42 @@ int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { .msg_iovlen = 1, }; ssize_t nread; + InAddr ia; do { nread = recvmsg(fd, &msg, 0); } while (nread == -1 && errno == EINTR); if (nread == -1) { - std::cerr << "recvmsg: Could not receive netlink message: " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "recvmsg: Could not receive netlink message: {}", + strerror(errno)); + return std::unexpected{Error::SYSCALL}; } for (auto hdr = reinterpret_cast(buf.data()); NLMSG_OK(hdr, nread); hdr = NLMSG_NEXT(hdr, nread)) { if (seq != hdr->nlmsg_seq) { - std::cerr << "netlink: unexpected sequence number " << hdr->nlmsg_seq - << " while expecting " << seq << std::endl; - return -1; + std::println(stderr, + "netlink: unexpected sequence number {} while expecting {}", + hdr->nlmsg_seq, seq); + return std::unexpected{Error::INTERNAL}; } if (hdr->nlmsg_flags & NLM_F_MULTI) { - std::cerr << "netlink: unexpected NLM_F_MULTI flag set" << std::endl; - return -1; + std::println(stderr, "netlink: unexpected NLM_F_MULTI flag set"); + return std::unexpected{Error::INTERNAL}; } switch (hdr->nlmsg_type) { case NLMSG_DONE: - std::cerr << "netlink: unexpected NLMSG_DONE" << std::endl; - return -1; + std::println(stderr, "netlink: unexpected NLMSG_DONE"); + return std::unexpected{Error::INTERNAL}; case NLMSG_NOOP: continue; case NLMSG_ERROR: - std::cerr << "netlink: " - << strerror(-static_cast(NLMSG_DATA(hdr))->error) - << std::endl; - return -1; + std::println(stderr, "netlink: {}", + strerror(-static_cast(NLMSG_DATA(hdr))->error)); + return std::unexpected{Error::INTERNAL}; } auto attrlen = hdr->nlmsg_len - NLMSG_SPACE(sizeof(rtmsg)); @@ -359,7 +359,7 @@ int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { case AF_INET: { constexpr auto in_addrlen = sizeof(in_addr); if (RTA_LENGTH(in_addrlen) != rta->rta_len) { - return -1; + return std::unexpected{Error::INTERNAL}; } in_addr addr; @@ -372,7 +372,7 @@ int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { case AF_INET6: { constexpr auto in_addrlen = sizeof(in6_addr); if (RTA_LENGTH(in_addrlen) != rta->rta_len) { - return -1; + return std::unexpected{Error::INTERNAL}; } in6_addr addr; @@ -392,7 +392,7 @@ int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { } if (in_addr_empty(ia)) { - return -1; + return std::unexpected{Error::NOT_FOUND}; } // Read ACK @@ -411,9 +411,9 @@ int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { } while (nread == -1 && errno == EINTR); if (nread == -1) { - std::cerr << "recvmsg: Could not receive netlink message: " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "recvmsg: Could not receive netlink message: {}", + strerror(errno)); + return std::unexpected{Error::SYSCALL}; } error = -1; @@ -421,20 +421,21 @@ int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { for (auto hdr = reinterpret_cast(buf.data()); NLMSG_OK(hdr, nread); hdr = NLMSG_NEXT(hdr, nread)) { if (seq != hdr->nlmsg_seq) { - std::cerr << "netlink: unexpected sequence number " << hdr->nlmsg_seq - << " while expecting " << seq << std::endl; - return -1; + std::println(stderr, + "netlink: unexpected sequence number {} while expecting {}", + hdr->nlmsg_seq, seq); + return std::unexpected{Error::INTERNAL}; } if (hdr->nlmsg_flags & NLM_F_MULTI) { - std::cerr << "netlink: unexpected NLM_F_MULTI flag set" << std::endl; - return -1; + std::println(stderr, "netlink: unexpected NLM_F_MULTI flag set"); + return std::unexpected{Error::INTERNAL}; } switch (hdr->nlmsg_type) { case NLMSG_DONE: - std::cerr << "netlink: unexpected NLMSG_DONE" << std::endl; - return -1; + std::println(stderr, "netlink: unexpected NLMSG_DONE"); + return std::unexpected{Error::INTERNAL}; case NLMSG_NOOP: continue; case NLMSG_ERROR: @@ -443,47 +444,47 @@ int recv_netlink_msg(InAddr &ia, int fd, uint32_t seq) { break; } - std::cerr << "netlink: " << strerror(error) << std::endl; + std::println(stderr, "netlink: {}", strerror(error)); - return -1; + return std::unexpected{Error::INTERNAL}; } } if (error != 0) { - return -1; + return std::unexpected{Error::INTERNAL}; } - return 0; + return ia; } } // namespace -int get_local_addr(InAddr &ia, const Address &remote_addr) { +std::expected get_local_addr(const Address &remote_addr) { sockaddr_nl sa{ .nl_family = AF_NETLINK, }; auto fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd == -1) { - std::cerr << "socket: Could not create netlink socket: " << strerror(errno) - << std::endl; - return -1; + std::println(stderr, "socket: Could not create netlink socket: {}", + strerror(errno)); + return std::unexpected{Error::SYSCALL}; } auto fd_d = defer([fd] { close(fd); }); if (bind(fd, reinterpret_cast(&sa), sizeof(sa)) == -1) { - std::cerr << "bind: Could not bind netlink socket: " << strerror(errno) - << std::endl; - return -1; + std::println(stderr, "bind: Could not bind netlink socket: {}", + strerror(errno)); + return std::unexpected{Error::SYSCALL}; } uint32_t seq = 1; - if (send_netlink_msg(fd, remote_addr, seq) != 0) { - return -1; + if (auto rv = send_netlink_msg(fd, remote_addr, seq); !rv) { + return std::unexpected{rv.error()}; } - return recv_netlink_msg(ia, fd, seq); + return recv_netlink_msg(fd, seq); } #endif // defined(HAVE_LINUX_NETLINK_H) diff --git a/deps/ngtcp2/ngtcp2/examples/shared.h b/deps/ngtcp2/ngtcp2/examples/shared.h index 26e678816e8f98..5c4a97646a06be 100644 --- a/deps/ngtcp2/ngtcp2/examples/shared.h +++ b/deps/ngtcp2/ngtcp2/examples/shared.h @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include @@ -41,23 +43,61 @@ using namespace std::literals; namespace ngtcp2 { +enum class Error { + // the generic errors that are not covered by more specific error + // codes. + INTERNAL, + // function arguments are invalid + INVALID_ARGUMENT, + // integer overflow error + INTEGER_OVERFLOW, + // file I/O error + IO, + // function is not implemented yet + NOT_IMPLEMENTED, + // the operation is not supported + UNSUPPORTED, + // entity is not found (e.g., file not found) + NOT_FOUND, + // crypto related error (e.g., error from TLS stack) + CRYPTO, + // system call error + SYSCALL, + // C library error (e.g., error from getaddrinfo) + LIBC, + // HTTP3 library error (e.g., error from nghttp3 API) + HTTP3, + // QUIC library error (e.g., error from ngtcp2 API) + QUIC, + // sending packet is blocked by kernel + SEND_BLOCKED, + // QUIC connection is in close-wait. + CLOSE_WAIT, + // QUIC connection should be retried. + RETRY_CONN, + // QUIC connection should be dropped. + DROP_CONN, + // Retry token is unreadable, and should be ignored. + UNREADABLE_TOKEN, +}; + enum class AppProtocol { H3, HQ, }; template -consteval std::span as_uint8_span(const uint8_t (&s)[N]) { +consteval std::span span_from_lit(const uint8_t (&s)[N]) { return {s, N - 1}; } -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); +inline constexpr uint8_t RAW_HQ_ALPN[] = "\xAhq-interop"; +inline constexpr auto HQ_ALPN = span_from_lit(RAW_HQ_ALPN); +inline constexpr auto HQ_ALPN_V1 = span_from_lit(RAW_HQ_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); +inline constexpr auto H3_ALPN = span_from_lit(RAW_H3_ALPN); +inline constexpr auto H3_ALPN_V1 = span_from_lit(RAW_H3_ALPN); inline constexpr uint32_t TLS_ALERT_ECH_REQUIRED = 121; @@ -81,15 +121,15 @@ void fd_set_ip_dontfrag(int fd, int family); // fd_set_udp_gro sets UDP_GRO socket option to |fd|. void fd_set_udp_gro(int fd); -std::optional
msghdr_get_local_addr(msghdr *msg, int family); +std::expected msghdr_get_local_addr(msghdr *msg, int family); // msghdr_get_udp_gro returns UDP_GRO value from |msg|. If UDP_GRO is // not found, or UDP_GRO is not supported, this function returns 0. size_t msghdr_get_udp_gro(msghdr *msg); -// get_local_addr stores preferred local address (interface address) -// in |ia| for a given destination address |remote_addr|. -int get_local_addr(InAddr &ia, const Address &remote_addr); +// get_local_addr returns the preferred local address (interface +// address) for a given destination address |remote_addr|. +std::expected get_local_addr(const Address &remote_addr); // addreq returns true if |addr| and |ia| contain the same address. bool addreq(const Address &addr, const InAddr &ia); @@ -145,4 +185,67 @@ void sockaddr_set(Sockaddr &skaddr, const sockaddr *sa); } // namespace ngtcp2 +template <> +struct std::formatter : public std::formatter { + auto format(ngtcp2::Error e, format_context &ctx) const { + auto s = "unknown"sv; + + switch (e) { + case ngtcp2::Error::INTERNAL: + s = "internal"sv; + break; + case ngtcp2::Error::INVALID_ARGUMENT: + s = "invalid argument"sv; + break; + case ngtcp2::Error::INTEGER_OVERFLOW: + s = "integer overflow"sv; + break; + case ngtcp2::Error::IO: + s = "I/O"sv; + break; + case ngtcp2::Error::NOT_IMPLEMENTED: + s = "not implemented"sv; + break; + case ngtcp2::Error::UNSUPPORTED: + s = "unsupported"sv; + break; + case ngtcp2::Error::NOT_FOUND: + s = "not found"sv; + break; + case ngtcp2::Error::CRYPTO: + s = "crypto"sv; + break; + case ngtcp2::Error::SYSCALL: + s = "syscall"sv; + break; + case ngtcp2::Error::LIBC: + s = "libc"sv; + break; + case ngtcp2::Error::HTTP3: + s = "HTTP3"sv; + break; + case ngtcp2::Error::QUIC: + s = "QUIC"sv; + break; + case ngtcp2::Error::SEND_BLOCKED: + s = "send blocked"sv; + break; + case ngtcp2::Error::CLOSE_WAIT: + s = "close wait"sv; + break; + case ngtcp2::Error::RETRY_CONN: + s = "retry connection"sv; + break; + case ngtcp2::Error::DROP_CONN: + s = "drop connection"sv; + break; + case ngtcp2::Error::UNREADABLE_TOKEN: + s = "unreadable token"sv; + break; + } + + return std::formatter::format(s, ctx); + } +}; + #endif // !defined(SHARED_H) diff --git a/deps/ngtcp2/ngtcp2/examples/sim.cc b/deps/ngtcp2/ngtcp2/examples/sim.cc index b1e778f165dbbc..326c3701caf18c 100644 --- a/deps/ngtcp2/ngtcp2/examples/sim.cc +++ b/deps/ngtcp2/ngtcp2/examples/sim.cc @@ -36,7 +36,6 @@ #include "ngtcp2/ngtcp2_crypto_wolfssl.h" #include "util.h" -#include "shared.h" #include "debug.h" using namespace std::literals; @@ -48,30 +47,31 @@ 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 data) { +std::expected generate_secure_random(std::span data) { if (wolfSSL_RAND_bytes(data.data(), static_cast(data.size())) != 1) { - return -1; + return std::unexpected{Error::CRYPTO}; } - return 0; + return {}; } 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); + assert(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) { +int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, + ngtcp2_stateless_reset_token *token, size_t cidlen, + void *user_data) { + if (!generate_secure_random({cid->data, cidlen})) { return NGTCP2_ERR_CALLBACK_FAILURE; } cid->datalen = cidlen; if (ngtcp2_crypto_generate_stateless_reset_token( - token, SERVER_SECRET, sizeof(SERVER_SECRET) - 1, cid) != 0) { + token->data, SERVER_SECRET, sizeof(SERVER_SECRET) - 1, cid) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -124,12 +124,12 @@ ngtcp2_callbacks default_client_callbacks() { .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, + .get_new_connection_id2 = get_new_connection_id, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; } @@ -142,12 +142,12 @@ ngtcp2_callbacks default_server_callbacks() { .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, + .get_new_connection_id2 = get_new_connection_id, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; } @@ -325,17 +325,16 @@ SJ9Gq0lvEXEcAiBwWBNUASBqLaje3hmtgwxcF7EIqqiGo5j8f9Ufgu6SRg== )"sv; } // namespace -int Endpoint::setup_server(std::span original_dcid, - std::span client_scid, - uint32_t version, const ngtcp2_addr *remote_addr) { - int rv; - +std::expected +Endpoint::setup_server(std::span original_dcid, + std::span client_scid, uint32_t version, + const ngtcp2_addr *remote_addr) { ngtcp2_cid scid{ .datalen = CIDLEN, }; - if (generate_secure_random({scid.data, scid.datalen}) != 0) { - return -1; + if (auto rv = generate_secure_random({scid.data, scid.datalen}); !rv) { + return rv; } ngtcp2_cid dcid; @@ -348,8 +347,8 @@ int Endpoint::setup_server(std::span original_dcid, if (ngtcp2_crypto_generate_stateless_reset_token( params.stateless_reset_token, SERVER_SECRET, sizeof(SERVER_SECRET) - 1, - &scid)) { - return -1; + &scid) != 0) { + return std::unexpected{Error::QUIC}; } auto path = ngtcp2_path{ @@ -357,43 +356,42 @@ int Endpoint::setup_server(std::span original_dcid, .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; + if (ngtcp2_conn_server_new(&conn_, &dcid, &scid, &path, version, + &config_.callbacks, &config_.settings, ¶ms, + nullptr, config_.user_data) != 0) { + return std::unexpected{Error::QUIC}; } ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); if (!ssl_ctx_) { - return -1; + return std::unexpected{Error::CRYPTO}; } if (ngtcp2_crypto_wolfssl_configure_server_context(ssl_ctx_) != 0) { - return -1; + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_use_certificate_buffer( ssl_ctx_, reinterpret_cast(tls_crt.data()), static_cast(tls_crt.size()), SSL_FILETYPE_PEM) != SSL_SUCCESS) { - return -1; + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_use_PrivateKey_buffer( ssl_ctx_, reinterpret_cast(tls_key.data()), static_cast(tls_key.size()), SSL_FILETYPE_PEM) != SSL_SUCCESS) { - return -1; + return std::unexpected{Error::CRYPTO}; } ssl_ = wolfSSL_new(ssl_ctx_); if (!ssl_) { - return -1; + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_UseALPN(ssl_, const_cast(ALPN_LIST.data()), ALPN_LIST.size(), WOLFSSL_ALPN_FAILED_ON_MISMATCH) != WOLFSSL_SUCCESS) { - return -1; + return std::unexpected{Error::CRYPTO}; } wolfSSL_set_app_data(ssl_, &conn_ref_); @@ -404,12 +402,11 @@ int Endpoint::setup_server(std::span original_dcid, initialized_ = true; - return 0; + return {}; } -int Endpoint::setup_client(const ngtcp2_addr *remote_addr) { - int rv; - +std::expected +Endpoint::setup_client(const ngtcp2_addr *remote_addr) { ngtcp2_cid dcid{ .datalen = CIDLEN, }; @@ -417,10 +414,12 @@ int Endpoint::setup_client(const ngtcp2_addr *remote_addr) { .datalen = CIDLEN, }; - if (generate_secure_random({dcid.data, dcid.datalen}) != 0 || - generate_secure_random({scid.data, scid.datalen}) != 0) { - assert(0); - return -1; + if (auto rv = generate_secure_random({dcid.data, dcid.datalen}); !rv) { + return rv; + } + + if (auto rv = generate_secure_random({scid.data, scid.datalen}); !rv) { + return rv; } auto path = ngtcp2_path{ @@ -428,31 +427,30 @@ int Endpoint::setup_client(const ngtcp2_addr *remote_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; + if (ngtcp2_conn_client_new( + &conn_, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1, &config_.callbacks, + &config_.settings, &config_.params, nullptr, config_.user_data) != 0) { + return std::unexpected{Error::QUIC}; } ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); if (!ssl_ctx_) { - return -1; + return std::unexpected{Error::CRYPTO}; } if (ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx_) != 0) { - return -1; + return std::unexpected{Error::CRYPTO}; } ssl_ = wolfSSL_new(ssl_ctx_); if (!ssl_) { - return -1; + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_UseALPN(ssl_, const_cast(ALPN_LIST.data()), ALPN_LIST.size(), WOLFSSL_ALPN_FAILED_ON_MISMATCH) != WOLFSSL_SUCCESS) { - return -1; + return std::unexpected{Error::CRYPTO}; } wolfSSL_set_app_data(ssl_, &conn_ref_); @@ -463,11 +461,12 @@ int Endpoint::setup_client(const ngtcp2_addr *remote_addr) { initialized_ = true; - return 0; + return {}; } -int Endpoint::on_read(const NetworkPath &path, std::span pkt, - const Context &ctx) { +std::expected Endpoint::on_read(const NetworkPath &path, + std::span pkt, + const Context &ctx) { auto ts = to_ngtcp2_tstamp(ctx.ts); auto cpath = to_ngtcp2_path(path); @@ -475,35 +474,35 @@ int Endpoint::on_read(const NetworkPath &path, std::span pkt, 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; + return std::unexpected{Error::QUIC}; } ctx.endpoint->get_channel().schedule_timeout(ctx.ts); - return 0; + return {}; } -int Endpoint::on_write(const Context &ctx) { - if (config_.on_write(conn_, ctx) != 0) { - return -1; +std::expected Endpoint::on_write(const Context &ctx) { + if (auto rv = config_.on_write(conn_, ctx); !rv) { + return rv; } auto next_expiry_ts = ngtcp2_conn_get_expiry(conn_); if (next_expiry_ts == UINT64_MAX) { - return 0; + return {}; } ctx.endpoint->get_channel().schedule_timeout(to_timestamp(next_expiry_ts)); - return 0; + return {}; } -int Endpoint::on_timeout(const Context &ctx) { +std::expected 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 std::unexpected{Error::QUIC}; } return on_write(ctx); @@ -701,10 +700,14 @@ std::optional> Simulator::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; +std::expected Simulator::run() { + if (client_.get_initialized()) { + return std::unexpected{Error::INTERNAL}; + } + + if (auto rv = client_.setup_client(&server_.get_endpoint_config().local_addr); + !rv) { + return rv; } auto ts = Timestamp{}; @@ -744,15 +747,15 @@ int Simulator::run() { .endpoint = &ep, }; - if (ep.on_timeout(ctx) != 0) { - return -1; + if (auto rv = ep.on_timeout(ctx); !rv) { + return rv; } break; } case EVENT_TYPE_PKT: - if (deliver_pkt(ep, event.path.invert(), event.pkt, ts) != 0) { - return -1; + if (auto rv = deliver_pkt(ep, event.path.invert(), event.pkt, ts); !rv) { + return rv; } break; @@ -760,18 +763,20 @@ int Simulator::run() { } if (k == max_events_) { - return -1; + return std::unexpected{Error::INTERNAL}; } - return 0; + return {}; } 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 pkt, Timestamp ts) { +std::expected Simulator::deliver_pkt(Endpoint &remote_ep, + const NetworkPath &path, + std::span pkt, + Timestamp ts) { auto &local_ep = get_opposite_endpoint(remote_ep); if (!local_ep.get_initialized() && local_ep.get_endpoint_config().server) { @@ -780,19 +785,20 @@ int Simulator::deliver_pkt(Endpoint &remote_ep, const NetworkPath &path, auto rv = ngtcp2_pkt_decode_version_cid(&vcid, pkt.data(), pkt.size(), CIDLEN); if (rv != 0) { - return 0; + return std::unexpected{Error::QUIC}; } ngtcp2_pkt_hd hd; if (ngtcp2_accept(&hd, pkt.data(), pkt.size()) != 0) { - return 0; + return {}; } - if (local_ep.setup_server( + if (auto rv = local_ep.setup_server( {vcid.dcid, vcid.dcidlen}, {vcid.scid, vcid.scidlen}, vcid.version, - &remote_ep.get_endpoint_config().local_addr) != 0) { - return -1; + &remote_ep.get_endpoint_config().local_addr); + !rv) { + return rv; } } @@ -820,7 +826,8 @@ void HandshakeApp::configure(EndpointConfig &config) { config.callbacks.handshake_confirmed = handshake_confirmed; } - config.on_write = [](ngtcp2_conn *conn, const Context &ctx) { + config.on_write = [](ngtcp2_conn *conn, + const Context &ctx) -> std::expected { std::array buf; auto ts = to_ngtcp2_tstamp(ctx.ts); @@ -833,11 +840,11 @@ void HandshakeApp::configure(EndpointConfig &config) { if (nwrite < 0) { std::cerr << "ngtcp2_conn_write_pkt: " << ngtcp2_strerror(static_cast(nwrite)) << std::endl; - return -1; + return std::unexpected{Error::QUIC}; } if (nwrite == 0) { - return 0; + return {}; } ngtcp2_conn_update_pkt_tx_time(conn, ts); @@ -845,7 +852,7 @@ void HandshakeApp::configure(EndpointConfig &config) { ctx.endpoint->get_channel().send_pkt( to_network_path(&ps.path), {buf.data(), static_cast(nwrite)}); - return 0; + return {}; }; config.user_data = this; @@ -872,7 +879,11 @@ void UniStreamApp::configure(EndpointConfig &config) { [](ngtcp2_conn *conn, uint64_t max_streams, void *user_data) { auto app = static_cast(user_data); - return app->extend_max_local_streams_uni(conn); + if (!app->extend_max_local_streams_uni(conn)) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; }; config.on_write = [this](ngtcp2_conn *conn, const Context &ctx) { @@ -903,9 +914,10 @@ void UniStreamApp::stream_close(ngtcp2_conn *conn, int64_t stream_id) { } } -int UniStreamApp::extend_max_local_streams_uni(ngtcp2_conn *conn) { +std::expected +UniStreamApp::extend_max_local_streams_uni(ngtcp2_conn *conn) { if (stream_id_ != -1) { - return 0; + return {}; } int64_t stream_id; @@ -914,16 +926,17 @@ int UniStreamApp::extend_max_local_streams_uni(ngtcp2_conn *conn) { if (rv != 0) { std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv) << std::endl; - return NGTCP2_ERR_CALLBACK_FAILURE; + return std::unexpected{Error::QUIC}; } stream_id_ = stream_id; start_ts_ = to_timestamp(ngtcp2_conn_get_timestamp(conn)); - return 0; + return {}; } -int UniStreamApp::on_write(ngtcp2_conn *conn, const Context &ctx) { +std::expected UniStreamApp::on_write(ngtcp2_conn *conn, + const Context &ctx) { std::array buf; int64_t stream_id; @@ -958,17 +971,17 @@ int UniStreamApp::on_write(ngtcp2_conn *conn, const Context &ctx) { &ndatalen, flags, stream_id, &vec, veccnt, ts); if (nwrite < 0) { if (nwrite == NGTCP2_ERR_STREAM_DATA_BLOCKED) { - return 0; + return {}; } std::cerr << "ngtcp2_conn_writev_stream: " << ngtcp2_strerror(static_cast(nwrite)) << std::endl; - return -1; + return std::unexpected{Error::QUIC}; } if (nwrite == 0) { - return 0; + return {}; } if (ndatalen > 0) { @@ -980,7 +993,7 @@ int UniStreamApp::on_write(ngtcp2_conn *conn, const Context &ctx) { ctx.endpoint->get_channel().send_pkt( to_network_path(&ps.path), {buf.data(), static_cast(nwrite)}); - return 0; + return {}; } } // namespace ngtcp2 diff --git a/deps/ngtcp2/ngtcp2/examples/sim.h b/deps/ngtcp2/ngtcp2/examples/sim.h index a70388686ae9da..c8fa7c203045d3 100644 --- a/deps/ngtcp2/ngtcp2/examples/sim.h +++ b/deps/ngtcp2/ngtcp2/examples/sim.h @@ -42,6 +42,7 @@ #include #include "network.h" +#include "shared.h" namespace ngtcp2 { inline constexpr size_t MAX_UDP_PAYLOAD_SIZE = 1500; @@ -106,7 +107,8 @@ struct EndpointConfig { void *user_data{}; LinkConfig link; - std::function on_write; + std::function(ngtcp2_conn *, const Context &)> + on_write; }; ngtcp2_callbacks default_client_callbacks(); @@ -206,17 +208,19 @@ class Endpoint { Endpoint &operator=(const Endpoint &) = delete; Endpoint &operator=(Endpoint &&) noexcept; - int setup_client(const ngtcp2_addr *remote_addr); - int setup_server(std::span original_dcid, - std::span client_scid, uint32_t version, - const ngtcp2_addr *remote_addr); + std::expected setup_client(const ngtcp2_addr *remote_addr); + std::expected + setup_server(std::span original_dcid, + std::span 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 pkt, - const Context &ctx); - int on_write(const Context &ctx); - int on_timeout(const Context &ctx); + std::expected on_read(const NetworkPath &path, + std::span pkt, + const Context &ctx); + std::expected on_write(const Context &ctx); + std::expected on_timeout(const Context &ctx); Channel &get_channel() { return channel_; } private: @@ -238,14 +242,16 @@ class Simulator { Simulator &operator=(const Simulator &) = delete; Simulator &operator=(Simulator &&) noexcept; - int run(); + std::expected run(); void set_max_events(size_t n) { max_events_ = n; } private: Endpoint &get_opposite_endpoint(const Endpoint &ep); std::optional> get_next_event(); - int deliver_pkt(Endpoint &remote_ep, const NetworkPath &path, - std::span pkt, Timestamp ts); + std::expected deliver_pkt(Endpoint &remote_ep, + const NetworkPath &path, + std::span pkt, + Timestamp ts); Endpoint client_; Endpoint server_; @@ -279,8 +285,8 @@ class UniStreamApp { 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); + std::expected extend_max_local_streams_uni(ngtcp2_conn *conn); + std::expected on_write(ngtcp2_conn *conn, const Context &ctx); int64_t stream_id_{-1}; uint64_t max_bytes_{}; diff --git a/deps/ngtcp2/ngtcp2/examples/sim_test.cc b/deps/ngtcp2/ngtcp2/examples/sim_test.cc index 76e1c1e498f7fb..6755907ec5605e 100644 --- a/deps/ngtcp2/ngtcp2/examples/sim_test.cc +++ b/deps/ngtcp2/ngtcp2/examples/sim_test.cc @@ -80,13 +80,9 @@ void test_sim_handshake(void) { svapp.configure(sv); sv.link = link; - int rv; + auto rv = Simulator{Endpoint(cl), Endpoint(sv)}.run(); - { - rv = Simulator{Endpoint(cl), Endpoint(sv)}.run(); - } - - assert_int(0, ==, rv); + assert_true(rv.has_value()); assert_true(clapp.get_handshake_confirmed()); assert_true(svapp.get_handshake_confirmed()); } @@ -132,13 +128,9 @@ void test_sim_unistream(void) { svapp.configure(sv); sv.link = link; - int rv; - - { - rv = Simulator{Endpoint(cl), Endpoint(sv)}.run(); - } + auto rv = Simulator{Endpoint(cl), Endpoint(sv)}.run(); - assert_int(0, ==, rv); + assert_true(rv.has_value()); assert_true(svapp.is_all_bytes_sent()); assert_uint64(link.compute_expected_goodput(link.delay * 2), <=, svapp.compute_goodput()); diff --git a/deps/ngtcp2/ngtcp2/examples/simpleclient.c b/deps/ngtcp2/ngtcp2/examples/simpleclient.c index 549aeb68a90246..fb0b8862979c94 100644 --- a/deps/ngtcp2/ngtcp2/examples/simpleclient.c +++ b/deps/ngtcp2/ngtcp2/examples/simpleclient.c @@ -48,7 +48,7 @@ #define REMOTE_HOST "127.0.0.1" #define REMOTE_PORT "4433" -#define ALPN "\xahq-interop" +#define ALPN "\xAhq-interop" #define MESSAGE "GET /\r\n" /* @@ -206,8 +206,8 @@ static void rand_cb(uint8_t *dest, size_t destlen, } static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid, - uint8_t *token, size_t cidlen, - void *user_data) { + ngtcp2_stateless_reset_token *token, + size_t cidlen, void *user_data) { (void)conn; (void)user_data; @@ -217,7 +217,7 @@ static int get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid, cid->datalen = cidlen; - if (RAND_bytes(token, NGTCP2_STATELESS_RESET_TOKENLEN) != 1) { + if (RAND_bytes(token->data, sizeof(token->data)) != 1) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -293,12 +293,12 @@ static int client_quic_init(struct client *c, .recv_retry = ngtcp2_crypto_recv_retry_cb, .extend_max_local_streams_bidi = extend_max_local_streams_bidi, .rand = rand_cb, - .get_new_connection_id = get_new_connection_id_cb, .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, + .get_new_connection_id2 = get_new_connection_id_cb, + .get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb, }; ngtcp2_cid dcid, scid; ngtcp2_settings settings; @@ -593,7 +593,7 @@ static int client_init(struct client *c) { struct sockaddr_storage remote_addr, local_addr; socklen_t remote_addrlen, local_addrlen = sizeof(local_addr); - memset(c, 0, sizeof(*c)); + *c = (struct client){0}; ngtcp2_ccerr_default(&c->last_error); diff --git a/deps/ngtcp2/ngtcp2/examples/siphash.cc b/deps/ngtcp2/ngtcp2/examples/siphash.cc index ceeb4c93ea830d..58cad9d1b775ba 100644 --- a/deps/ngtcp2/ngtcp2/examples/siphash.cc +++ b/deps/ngtcp2/ngtcp2/examples/siphash.cc @@ -79,9 +79,9 @@ uint64_t siphash24(std::span key, std::span input) { const auto orig_input_len = input.size(); uint64_t v[]{ - key[0] ^ UINT64_C(0x736f6d6570736575), - key[1] ^ UINT64_C(0x646f72616e646f6d), - key[0] ^ UINT64_C(0x6c7967656e657261), + key[0] ^ UINT64_C(0x736F6D6570736575), + key[1] ^ UINT64_C(0x646F72616E646F6D), + key[0] ^ UINT64_C(0x6C7967656E657261), key[1] ^ UINT64_C(0x7465646279746573), }; @@ -97,7 +97,7 @@ uint64_t siphash24(std::span key, std::array last_block{}; std::ranges::copy(input, std::ranges::begin(last_block)); - last_block.back() = orig_input_len & 0xff; + last_block.back() = orig_input_len & 0xFF; auto last_block_word = CRYPTO_load_u64_le(last_block); v[3] ^= last_block_word; @@ -105,7 +105,7 @@ uint64_t siphash24(std::span key, siphash_round(v); v[0] ^= last_block_word; - v[2] ^= 0xff; + v[2] ^= 0xFF; siphash_round(v); siphash_round(v); siphash_round(v); diff --git a/deps/ngtcp2/ngtcp2/examples/siphash_test.cc b/deps/ngtcp2/ngtcp2/examples/siphash_test.cc index 9c64c69963563c..54f300444efa6e 100644 --- a/deps/ngtcp2/ngtcp2/examples/siphash_test.cc +++ b/deps/ngtcp2/ngtcp2/examples/siphash_test.cc @@ -62,7 +62,7 @@ void test_siphash(void) { std::array input; std::iota(std::ranges::begin(input), std::ranges::end(input), 0); - assert_uint64(0xa129ca6149be45e5ull, ==, siphash24(key, input)); + assert_uint64(0xA129CA6149BE45E5ULL, ==, siphash24(key, input)); } void test_siphash_vector(void) { diff --git a/deps/ngtcp2/ngtcp2/examples/siphash_vector.h b/deps/ngtcp2/ngtcp2/examples/siphash_vector.h index 62cc0e218c9341..5f4c294cf365cf 100644 --- a/deps/ngtcp2/ngtcp2/examples/siphash_vector.h +++ b/deps/ngtcp2/ngtcp2/examples/siphash_vector.h @@ -4,293 +4,293 @@ const uint8_t vectors_sip64[64][8] = { { 0x31, - 0x0e, - 0x0e, - 0xdd, + 0x0E, + 0x0E, + 0xDD, 0x47, - 0xdb, - 0x6f, + 0xDB, + 0x6F, 0x72, }, { - 0xfd, + 0xFD, 0x67, - 0xdc, + 0xDC, 0x93, - 0xc5, + 0xC5, 0x39, - 0xf8, + 0xF8, 0x74, }, { - 0x5a, - 0x4f, - 0xa9, - 0xd9, + 0x5A, + 0x4F, + 0xA9, + 0xD9, 0x09, 0x80, - 0x6c, - 0x0d, + 0x6C, + 0x0D, }, { - 0x2d, - 0x7e, - 0xfb, - 0xd7, + 0x2D, + 0x7E, + 0xFB, + 0xD7, 0x96, 0x66, 0x67, 0x85, }, { - 0xb7, + 0xB7, 0x87, 0x71, 0x27, - 0xe0, + 0xE0, 0x94, 0x27, - 0xcf, + 0xCF, }, { - 0x8d, - 0xa6, + 0x8D, + 0xA6, 0x99, - 0xcd, + 0xCD, 0x64, 0x55, 0x76, 0x18, }, { - 0xce, - 0xe3, - 0xfe, + 0xCE, + 0xE3, + 0xFE, 0x58, - 0x6e, + 0x6E, 0x46, - 0xc9, - 0xcb, + 0xC9, + 0xCB, }, { 0x37, - 0xd1, + 0xD1, 0x01, - 0x8b, - 0xf5, + 0x8B, + 0xF5, 0x00, 0x02, - 0xab, + 0xAB, }, { 0x62, 0x24, 0x93, - 0x9a, + 0x9A, 0x79, - 0xf5, - 0xf5, + 0xF5, + 0xF5, 0x93, }, { - 0xb0, - 0xe4, - 0xa9, - 0x0b, - 0xdf, + 0xB0, + 0xE4, + 0xA9, + 0x0B, + 0xDF, 0x82, 0x00, - 0x9e, + 0x9E, }, { - 0xf3, - 0xb9, - 0xdd, + 0xF3, + 0xB9, + 0xDD, 0x94, - 0xc5, - 0xbb, - 0x5d, - 0x7a, + 0xC5, + 0xBB, + 0x5D, + 0x7A, }, { - 0xa7, - 0xad, - 0x6b, + 0xA7, + 0xAD, + 0x6B, 0x22, 0x46, - 0x2f, - 0xb3, - 0xf4, + 0x2F, + 0xB3, + 0xF4, }, { - 0xfb, - 0xe5, - 0x0e, + 0xFB, + 0xE5, + 0x0E, 0x86, - 0xbc, - 0x8f, - 0x1e, + 0xBC, + 0x8F, + 0x1E, 0x75, }, { 0x90, - 0x3d, + 0x3D, 0x84, - 0xc0, + 0xC0, 0x27, 0x56, - 0xea, + 0xEA, 0x14, }, { - 0xee, - 0xf2, - 0x7a, - 0x8e, + 0xEE, + 0xF2, + 0x7A, + 0x8E, 0x90, - 0xca, + 0xCA, 0x23, - 0xf7, + 0xF7, }, { - 0xe5, + 0xE5, 0x45, - 0xbe, + 0xBE, 0x49, 0x61, - 0xca, + 0xCA, 0x29, - 0xa1, + 0xA1, }, { - 0xdb, - 0x9b, - 0xc2, + 0xDB, + 0x9B, + 0xC2, 0x57, - 0x7f, - 0xcc, - 0x2a, - 0x3f, + 0x7F, + 0xCC, + 0x2A, + 0x3F, }, { 0x94, 0x47, - 0xbe, - 0x2c, - 0xf5, - 0xe9, - 0x9a, + 0xBE, + 0x2C, + 0xF5, + 0xE9, + 0x9A, 0x69, }, { - 0x9c, - 0xd3, - 0x8d, + 0x9C, + 0xD3, + 0x8D, 0x96, - 0xf0, - 0xb3, - 0xc1, - 0x4b, + 0xF0, + 0xB3, + 0xC1, + 0x4B, }, { - 0xbd, + 0xBD, 0x61, 0x79, - 0xa7, - 0x1d, - 0xc9, - 0x6d, - 0xbb, + 0xA7, + 0x1D, + 0xC9, + 0x6D, + 0xBB, }, { 0x98, - 0xee, - 0xa2, - 0x1a, - 0xf2, - 0x5c, - 0xd6, - 0xbe, + 0xEE, + 0xA2, + 0x1A, + 0xF2, + 0x5C, + 0xD6, + 0xBE, }, { - 0xc7, + 0xC7, 0x67, - 0x3b, - 0x2e, - 0xb0, - 0xcb, - 0xf2, - 0xd0, + 0x3B, + 0x2E, + 0xB0, + 0xCB, + 0xF2, + 0xD0, }, { 0x88, - 0x3e, - 0xa3, - 0xe3, + 0x3E, + 0xA3, + 0xE3, 0x95, 0x67, 0x53, 0x93, }, { - 0xc8, - 0xce, - 0x5c, - 0xcd, - 0x8c, + 0xC8, + 0xCE, + 0x5C, + 0xCD, + 0x8C, 0x03, - 0x0c, - 0xa8, + 0x0C, + 0xA8, }, { 0x94, - 0xaf, + 0xAF, 0x49, - 0xf6, - 0xc6, + 0xF6, + 0xC6, 0x50, - 0xad, - 0xb8, + 0xAD, + 0xB8, }, { - 0xea, - 0xb8, + 0xEA, + 0xB8, 0x85, - 0x8a, - 0xde, + 0x8A, + 0xDE, 0x92, - 0xe1, - 0xbc, + 0xE1, + 0xBC, }, { - 0xf3, + 0xF3, 0x15, - 0xbb, - 0x5b, - 0xb8, + 0xBB, + 0x5B, + 0xB8, 0x35, - 0xd8, + 0xD8, 0x17, }, { - 0xad, - 0xcf, - 0x6b, + 0xAD, + 0xCF, + 0x6B, 0x07, 0x63, 0x61, - 0x2e, - 0x2f, + 0x2E, + 0x2F, }, { - 0xa5, - 0xc9, - 0x1d, - 0xa7, - 0xac, - 0xaa, - 0x4d, - 0xde, + 0xA5, + 0xC9, + 0x1D, + 0xA7, + 0xAC, + 0xAA, + 0x4D, + 0xDE, }, { 0x71, @@ -299,77 +299,77 @@ const uint8_t vectors_sip64[64][8] = { 0x87, 0x66, 0x50, - 0xa2, - 0xa6, + 0xA2, + 0xA6, }, { 0x28, - 0xef, + 0xEF, 0x49, - 0x5c, + 0x5C, 0x53, - 0xa3, + 0xA3, 0x87, - 0xad, + 0xAD, }, { 0x42, - 0xc3, + 0xC3, 0x41, - 0xd8, - 0xfa, + 0xD8, + 0xFA, 0x92, - 0xd8, + 0xD8, 0x32, }, { - 0xce, - 0x7c, - 0xf2, + 0xCE, + 0x7C, + 0xF2, 0x72, - 0x2f, + 0x2F, 0x51, 0x27, 0x71, }, { - 0xe3, + 0xE3, 0x78, 0x59, - 0xf9, + 0xF9, 0x46, 0x23, - 0xf3, - 0xa7, + 0xF3, + 0xA7, }, { 0x38, 0x12, 0x05, - 0xbb, - 0x1a, - 0xb0, - 0xe0, + 0xBB, + 0x1A, + 0xB0, + 0xE0, 0x12, }, { - 0xae, + 0xAE, 0x97, - 0xa1, - 0x0f, - 0xd4, + 0xA1, + 0x0F, + 0xD4, 0x34, - 0xe0, + 0xE0, 0x15, }, { - 0xb4, - 0xa3, + 0xB4, + 0xA3, 0x15, 0x08, - 0xbe, - 0xff, - 0x4d, + 0xBE, + 0xFF, + 0x4D, 0x31, }, { @@ -377,80 +377,80 @@ const uint8_t vectors_sip64[64][8] = { 0x39, 0x62, 0x29, - 0xf0, + 0xF0, 0x90, 0x79, 0x02, }, { - 0x4d, - 0x0c, - 0xf4, - 0x9e, - 0xe5, - 0xd4, - 0xdc, - 0xca, + 0x4D, + 0x0C, + 0xF4, + 0x9E, + 0xE5, + 0xD4, + 0xDC, + 0xCA, }, { - 0x5c, + 0x5C, 0x73, 0x33, - 0x6a, + 0x6A, 0x76, - 0xd8, - 0xbf, - 0x9a, + 0xD8, + 0xBF, + 0x9A, }, { - 0xd0, - 0xa7, + 0xD0, + 0xA7, 0x04, 0x53, - 0x6b, - 0xa9, - 0x3e, - 0x0e, + 0x6B, + 0xA9, + 0x3E, + 0x0E, }, { 0x92, 0x59, 0x58, - 0xfc, - 0xd6, + 0xFC, + 0xD6, 0x42, - 0x0c, - 0xad, + 0x0C, + 0xAD, }, { - 0xa9, + 0xA9, 0x15, - 0xc2, - 0x9b, - 0xc8, + 0xC2, + 0x9B, + 0xC8, 0x06, 0x73, 0x18, }, { 0x95, - 0x2b, + 0x2B, 0x79, - 0xf3, - 0xbc, - 0x0a, - 0xa6, - 0xd4, - }, - { - 0xf2, - 0x1d, - 0xf2, - 0xe4, - 0x1d, + 0xF3, + 0xBC, + 0x0A, + 0xA6, + 0xD4, + }, + { + 0xF2, + 0x1D, + 0xF2, + 0xE4, + 0x1D, 0x45, 0x35, - 0xf9, + 0xF9, }, { 0x87, @@ -458,188 +458,188 @@ const uint8_t vectors_sip64[64][8] = { 0x75, 0x19, 0x04, - 0x8f, + 0x8F, 0x53, - 0xa9, + 0xA9, }, { 0x10, - 0xa5, - 0x6c, - 0xf5, - 0xdf, - 0xcd, - 0x9a, - 0xdb, + 0xA5, + 0x6C, + 0xF5, + 0xDF, + 0xCD, + 0x9A, + 0xDB, }, { - 0xeb, + 0xEB, 0x75, 0x09, - 0x5c, - 0xcd, + 0x5C, + 0xCD, 0x98, - 0x6c, - 0xd0, + 0x6C, + 0xD0, }, { 0x51, - 0xa9, - 0xcb, - 0x9e, - 0xcb, - 0xa3, + 0xA9, + 0xCB, + 0x9E, + 0xCB, + 0xA3, 0x12, - 0xe6, + 0xE6, }, { 0x96, - 0xaf, - 0xad, - 0xfc, - 0x2c, - 0xe6, + 0xAF, + 0xAD, + 0xFC, + 0x2C, + 0xE6, 0x66, - 0xc7, + 0xC7, }, { 0x72, - 0xfe, + 0xFE, 0x52, 0x97, - 0x5a, + 0x5A, 0x43, 0x64, - 0xee, + 0xEE, }, { - 0x5a, + 0x5A, 0x16, 0x45, - 0xb2, + 0xB2, 0x76, - 0xd5, + 0xD5, 0x92, - 0xa1, + 0xA1, }, { - 0xb2, + 0xB2, 0x74, - 0xcb, - 0x8e, - 0xbf, + 0xCB, + 0x8E, + 0xBF, 0x87, 0x87, - 0x0a, + 0x0A, }, { - 0x6f, - 0x9b, - 0xb4, + 0x6F, + 0x9B, + 0xB4, 0x20, - 0x3d, - 0xe7, - 0xb3, + 0x3D, + 0xE7, + 0xB3, 0x81, }, { - 0xea, - 0xec, - 0xb2, - 0xa3, - 0x0b, + 0xEA, + 0xEC, + 0xB2, + 0xA3, + 0x0B, 0x22, - 0xa8, - 0x7f, + 0xA8, + 0x7F, }, { 0x99, 0x24, - 0xa4, - 0x3c, - 0xc1, + 0xA4, + 0x3C, + 0xC1, 0x31, 0x57, 0x24, }, { - 0xbd, + 0xBD, 0x83, - 0x8d, - 0x3a, - 0xaf, - 0xbf, - 0x8d, - 0xb7, + 0x8D, + 0x3A, + 0xAF, + 0xBF, + 0x8D, + 0xB7, }, { - 0x0b, - 0x1a, - 0x2a, + 0x0B, + 0x1A, + 0x2A, 0x32, 0x65, - 0xd5, - 0x1a, - 0xea, + 0xD5, + 0x1A, + 0xEA, }, { 0x13, 0x50, 0x79, - 0xa3, + 0xA3, 0x23, - 0x1c, - 0xe6, + 0x1C, + 0xE6, 0x60, }, { 0x93, - 0x2b, + 0x2B, 0x28, 0x46, - 0xe4, - 0xd7, + 0xE4, + 0xD7, 0x06, 0x66, }, { - 0xe1, + 0xE1, 0x91, - 0x5f, - 0x5c, - 0xb1, - 0xec, - 0xa4, - 0x6c, + 0x5F, + 0x5C, + 0xB1, + 0xEC, + 0xA4, + 0x6C, }, { - 0xf3, + 0xF3, 0x25, 0x96, - 0x5c, - 0xa1, - 0x6d, + 0x5C, + 0xA1, + 0x6D, 0x62, - 0x9f, + 0x9F, }, { 0x57, - 0x5f, - 0xf2, - 0x8e, + 0x5F, + 0xF2, + 0x8E, 0x60, 0x38, - 0x1b, - 0xe5, + 0x1B, + 0xE5, }, { 0x72, 0x45, 0x06, - 0xeb, - 0x4c, + 0xEB, + 0x4C, 0x32, - 0x8a, + 0x8A, 0x95, }, }; diff --git a/deps/ngtcp2/ngtcp2/examples/template.h b/deps/ngtcp2/ngtcp2/examples/template.h index 8c73bbf307483e..43ebe0b31e4056 100644 --- a/deps/ngtcp2/ngtcp2/examples/template.h +++ b/deps/ngtcp2/ngtcp2/examples/template.h @@ -41,6 +41,13 @@ template return static_cast>(n); } +template +[[nodiscard]] auto as_uint8_span(std::span s) noexcept { + return std::span{ + reinterpret_cast(s.data()), s.size_bytes()}; +} + template struct Defer { explicit Defer(F &&f) noexcept(std::is_nothrow_constructible_v) : f(std::forward(f)) {} @@ -89,4 +96,16 @@ as_writable_uint8_span(std::span s) noexcept { reinterpret_cast(s.data()), s.size_bytes()}; } +template +requires(std::ranges::contiguous_range && std::ranges::sized_range && + std::ranges::borrowed_range && + !std::is_array_v> && + sizeof(std::ranges::range_value_t) == + sizeof(std::string_view::value_type)) +[[nodiscard]] std::string_view as_string_view(R &&r) { + return std::string_view{ + reinterpret_cast(std::ranges::data(r)), + std::ranges::size(r)}; +} + #endif // !defined(TEMPLATE_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc index c7f0bf7e2086b8..40205ace4e72a2 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.cc @@ -55,13 +55,13 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { auto f = BIO_new_file(config.session_file, "w"); if (f == nullptr) { - std::cerr << "Could not write TLS session in " << config.session_file - << std::endl; + std::println(stderr, "Could not write TLS session in {}", + config.session_file); return 0; } if (!PEM_write_bio_SSL_SESSION(f, session)) { - std::cerr << "Unable to write TLS session to file" << std::endl; + std::println(stderr, "Unable to write TLS session to file"); } BIO_free(f); @@ -70,40 +70,40 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { } } // namespace -int TLSClientContext::init(const char *private_key_file, - const char *cert_file) { +std::expected TLSClientContext::init(const char *private_key_file, + const char *cert_file) { ssl_ctx_ = SSL_CTX_new(TLS_client_method()); if (!ssl_ctx_) { - std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_CTX_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx_) != 0) { - std::cerr << "ngtcp2_crypto_boringssl_configure_client_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_boringssl_configure_client_context failed"); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_default_verify_paths(ssl_ctx_); if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) { - std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set1_groups_list failed"); + return std::unexpected{Error::CRYPTO}; } if (private_key_file && cert_file) { if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != 1) { - std::cerr << "SSL_CTX_use_PrivateKey_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_PrivateKey_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) { - std::cerr << "SSL_CTX_use_certificate_chain_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_certificate_chain_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } } @@ -117,12 +117,12 @@ int TLSClientContext::init(const char *private_key_file, if (!SSL_CTX_add_cert_compression_alg( ssl_ctx_, ngtcp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, ngtcp2::tls::cert_compress, ngtcp2::tls::cert_decompress)) { - std::cerr << "SSL_CTX_add_cert_compression_alg failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_add_cert_compression_alg failed"); + return std::unexpected{Error::CRYPTO}; } #endif // defined(HAVE_LIBBROTLI) - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.h index 47e7b02e097241..3f3fab08380cde 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_boringssl.h @@ -31,12 +31,17 @@ #include +#include "shared.h" + +using namespace ngtcp2; + class TLSClientContext { public: TLSClientContext() = default; ~TLSClientContext(); - int init(const char *private_key_file, const char *cert_file); + std::expected init(const char *private_key_file, + const char *cert_file); SSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc index 561db9473144d1..5eab5bc8fe47ec 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.cc @@ -67,17 +67,17 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { if (SSL_SESSION_get_max_early_data(session) != std::numeric_limits::max()) { - std::cerr << "max_early_data_size is not 0xffffffff" << std::endl; + std::println(stderr, "max_early_data_size is not 0xffffffff"); } auto f = BIO_new_file(config.session_file, "w"); if (f == nullptr) { - std::cerr << "Could not write TLS session in " << config.session_file - << std::endl; + std::println(stderr, "Could not write TLS session in {}", + config.session_file); return 0; } if (!PEM_write_bio_SSL_SESSION(f, session)) { - std::cerr << "Unable to write TLS session to file" << std::endl; + std::println(stderr, "Unable to write TLS session to file"); } BIO_free(f); @@ -86,40 +86,40 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { } } // namespace -int TLSClientContext::init(const char *private_key_file, - const char *cert_file) { +std::expected TLSClientContext::init(const char *private_key_file, + const char *cert_file) { ssl_ctx_ = SSL_CTX_new(TLS_client_method()); if (!ssl_ctx_) { - std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_CTX_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_default_verify_paths(ssl_ctx_); if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) { - std::cerr << "SSL_CTX_set_ciphersuites: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set_ciphersuites: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) { - std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set1_groups_list failed"); + return std::unexpected{Error::CRYPTO}; } if (private_key_file && cert_file) { if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != 1) { - std::cerr << "SSL_CTX_use_PrivateKey_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_PrivateKey_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) { - std::cerr << "SSL_CTX_use_certificate_chain_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_certificate_chain_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } } @@ -129,7 +129,7 @@ int TLSClientContext::init(const char *private_key_file, SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb); } - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.h index 5c33bfbeadfdeb..fad71595f2579c 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_ossl.h @@ -31,12 +31,17 @@ #include +#include "shared.h" + +using namespace ngtcp2; + class TLSClientContext { public: TLSClientContext() = default; ~TLSClientContext(); - int init(const char *private_key_file, const char *cert_file); + std::expected init(const char *private_key_file, + const char *cert_file); SSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc index 72ce8dd69f8810..f70df693ef44cd 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.cc @@ -47,14 +47,14 @@ int save_ticket_cb(ptls_save_ticket_t *self, ptls_t *ptls, ptls_iovec_t input) { auto f = BIO_new_file(config.session_file, "w"); if (f == nullptr) { - std::cerr << "Could not write TLS session in " << config.session_file - << std::endl; + std::println(stderr, "Could not write TLS session in {}", + config.session_file); return 0; } if (!PEM_write_bio(f, "PICOTLS SESSION PARAMETERS", "", input.base, static_cast(input.len))) { - std::cerr << "Unable to write TLS session to file" << std::endl; + std::println(stderr, "Unable to write TLS session to file"); } BIO_free(f); @@ -113,12 +113,12 @@ TLSClientContext::~TLSClientContext() { ptls_context_t *TLSClientContext::get_native_handle() { return &ctx_; } -int TLSClientContext::init(const char *private_key_file, - const char *cert_file) { +std::expected TLSClientContext::init(const char *private_key_file, + const char *cert_file) { if (ngtcp2_crypto_picotls_configure_client_context(&ctx_) != 0) { - std::cerr << "ngtcp2_crypto_picotls_configure_client_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_picotls_configure_client_context failed"); + return std::unexpected{Error::CRYPTO}; } if (config.session_file) { @@ -127,45 +127,46 @@ int TLSClientContext::init(const char *private_key_file, if (private_key_file && cert_file) { if (ptls_load_certificates(&ctx_, cert_file) != 0) { - std::cerr << "ptls_load_certificates failed" << std::endl; - return -1; + std::println(stderr, "ptls_load_certificates failed"); + return std::unexpected{Error::CRYPTO}; } - if (load_private_key(private_key_file) != 0) { - return -1; + if (auto rv = load_private_key(private_key_file); !rv) { + return rv; } } - return 0; + return {}; } -int TLSClientContext::load_private_key(const char *private_key_file) { +std::expected +TLSClientContext::load_private_key(const char *private_key_file) { auto fp = fopen(private_key_file, "rb"); if (fp == nullptr) { - std::cerr << "Could not open private key file " << private_key_file << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "Could not open private key file {}: {}", + private_key_file, strerror(errno)); + return std::unexpected{Error::IO}; } auto fp_d = defer([fp] { fclose(fp); }); auto pkey = PEM_read_PrivateKey(fp, nullptr, nullptr, nullptr); if (pkey == nullptr) { - std::cerr << "Could not read private key file " << private_key_file - << std::endl; - return -1; + std::println(stderr, "Could not read private key file {}", + private_key_file); + return std::unexpected{Error::IO}; } 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; - return -1; + std::println(stderr, "ptls_openssl_init_sign_certificate failed"); + return std::unexpected{Error::CRYPTO}; } ctx_.sign_certificate = &sign_cert_.super; - return 0; + return {}; } void TLSClientContext::enable_keylog() { ctx_.log_event = &log_event; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.h b/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.h index b07a2023817991..7f111fd58e0df9 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_picotls.h @@ -32,19 +32,24 @@ #include #include +#include "shared.h" + +using namespace ngtcp2; + class TLSClientContext { public: TLSClientContext(); ~TLSClientContext(); - int init(const char *private_key_file, const char *cert_file); + std::expected init(const char *private_key_file, + const char *cert_file); ptls_context_t *get_native_handle(); void enable_keylog(); private: - int load_private_key(const char *private_key_file); + std::expected load_private_key(const char *private_key_file); ptls_context_t ctx_; ptls_openssl_sign_certificate_t sign_cert_{}; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc index 6b5a37b4b09783..ce4ac8dbf7d29b 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.cc @@ -67,17 +67,17 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { if (SSL_SESSION_get_max_early_data(session) != std::numeric_limits::max()) { - std::cerr << "max_early_data_size is not 0xffffffff" << std::endl; + std::println(stderr, "max_early_data_size is not 0xffffffff"); } auto f = BIO_new_file(config.session_file, "w"); if (f == nullptr) { - std::cerr << "Could not write TLS session in " << config.session_file - << std::endl; + std::println(stderr, "Could not write TLS session in {}", + config.session_file); return 0; } if (!PEM_write_bio_SSL_SESSION(f, session)) { - std::cerr << "Unable to write TLS session to file" << std::endl; + std::println(stderr, "Unable to write TLS session to file"); } BIO_free(f); @@ -86,46 +86,46 @@ int new_session_cb(SSL *ssl, SSL_SESSION *session) { } } // namespace -int TLSClientContext::init(const char *private_key_file, - const char *cert_file) { +std::expected TLSClientContext::init(const char *private_key_file, + const char *cert_file) { ssl_ctx_ = SSL_CTX_new(TLS_client_method()); if (!ssl_ctx_) { - std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_CTX_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (ngtcp2_crypto_quictls_configure_client_context(ssl_ctx_) != 0) { - std::cerr << "ngtcp2_crypto_quictls_configure_client_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_quictls_configure_client_context failed"); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_default_verify_paths(ssl_ctx_); if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) { - std::cerr << "SSL_CTX_set_ciphersuites: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set_ciphersuites: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) { - std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set1_groups_list failed"); + return std::unexpected{Error::CRYPTO}; } if (private_key_file && cert_file) { if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != 1) { - std::cerr << "SSL_CTX_use_PrivateKey_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_PrivateKey_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) { - std::cerr << "SSL_CTX_use_certificate_chain_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_certificate_chain_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } } @@ -135,7 +135,7 @@ int TLSClientContext::init(const char *private_key_file, SSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb); } - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.h b/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.h index c76353c89e9670..97cb478f75ac4b 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_quictls.h @@ -31,12 +31,17 @@ #include +#include "shared.h" + +using namespace ngtcp2; + class TLSClientContext { public: TLSClientContext() = default; ~TLSClientContext(); - int init(const char *private_key_file, const char *cert_file); + std::expected init(const char *private_key_file, + const char *cert_file); SSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc index 4d287c42ce75a5..cca571a7c1da36 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.cc @@ -49,8 +49,6 @@ WOLFSSL_CTX *TLSClientContext::get_native_handle() const { return ssl_ctx_; } namespace { int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) { - std::cerr << "new_session_cb called" << std::endl; - auto conn_ref = static_cast(wolfSSL_get_app_data(ssl)); auto c = static_cast(conn_ref->user_data); @@ -60,18 +58,18 @@ int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) { #ifdef HAVE_SESSION_TICKET if (wolfSSL_SESSION_get_max_early_data(session) != std::numeric_limits::max()) { - std::cerr << "max_early_data_size is not 0xffffffff" << std::endl; + std::println(stderr, "max_early_data_size is not 0xffffffff"); } unsigned char sbuffer[16 * 1024], *data; auto sz = wolfSSL_i2d_SSL_SESSION(session, nullptr); if (sz <= 0) { - std::cerr << "Could not export TLS session in " << config.session_file - << std::endl; + std::println(stderr, "Could not export TLS session in {}", + config.session_file); return 0; } if (static_cast(sz) > sizeof(sbuffer)) { - std::cerr << "Exported TLS session too large" << std::endl; + std::println(stderr, "Exported TLS session too large"); return 0; } data = sbuffer; @@ -79,8 +77,8 @@ int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) { auto f = wolfSSL_BIO_new_file(config.session_file, "w"); if (f == nullptr) { - std::cerr << "Could not write TLS session in " << config.session_file - << std::endl; + std::println(stderr, "Could not write TLS session in {}", + config.session_file); return 0; } @@ -88,32 +86,29 @@ int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) { if (!wolfSSL_PEM_write_bio(f, "WOLFSSL SESSION PARAMETERS", "", sbuffer, sz)) { - std::cerr << "Unable to write TLS session to file" << std::endl; + std::println(stderr, "Unable to write TLS session to file"); return 0; } - std::cerr << "new_session_cb: wrote " << sz << " of session data" - << std::endl; #else // !defined(HAVE_SESSION_TICKET) - std::cerr << "TLS session tickets not enabled in wolfSSL " << std::endl; + std::println(stderr, "TLS session tickets not enabled in wolfSSL"); #endif // !defined(HAVE_SESSION_TICKET) return 0; } } // namespace -int TLSClientContext::init(const char *private_key_file, - const char *cert_file) { +std::expected TLSClientContext::init(const char *private_key_file, + const char *cert_file) { ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); if (!ssl_ctx_) { - std::cerr << "wolfSSL_CTX_new: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_new: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx_) != 0) { - std::cerr << "ngtcp2_crypto_wolfssl_configure_client_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_wolfssl_configure_client_context failed"); + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_set_default_verify_paths(ssl_ctx_) == @@ -124,34 +119,31 @@ int TLSClientContext::init(const char *private_key_file, if (wolfSSL_CTX_set_cipher_list(ssl_ctx_, config.ciphers) != WOLFSSL_SUCCESS) { - std::cerr << "wolfSSL_CTX_set_cipher_list: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_set_cipher_list: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_set1_groups_list( ssl_ctx_, const_cast(config.groups)) != WOLFSSL_SUCCESS) { - std::cerr << "wolfSSL_CTX_set1_groups_list(" << config.groups << ") failed" - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_set1_groups_list({}) failed", + config.groups); + return std::unexpected{Error::CRYPTO}; } if (private_key_file && cert_file) { if (wolfSSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != WOLFSSL_SUCCESS) { - std::cerr << "wolfSSL_CTX_use_PrivateKey_file: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_use_PrivateKey_file: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != WOLFSSL_SUCCESS) { - std::cerr << "wolfSSL_CTX_use_certificate_chain_file: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_use_certificate_chain_file: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } } @@ -160,7 +152,7 @@ int TLSClientContext::init(const char *private_key_file, wolfSSL_CTX_sess_set_new_cb(ssl_ctx_, new_session_cb); } - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.h index 07d967026d9de2..a8a66ed50d0a60 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_context_wolfssl.h @@ -33,12 +33,17 @@ #include #include +#include "shared.h" + +using namespace ngtcp2; + class TLSClientContext { public: TLSClientContext() = default; ~TLSClientContext(); - int init(const char *private_key_file, const char *cert_file); + std::expected init(const char *private_key_file, + const char *cert_file); WOLFSSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc index e72405cb6a2794..109265641a52c5 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.cc @@ -35,19 +35,20 @@ extern Config config; -int TLSClientSession::init(bool &early_data_enabled, - const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, - uint32_t quic_version, AppProtocol app_proto) { +std::expected +TLSClientSession::init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, const char *remote_addr, + ClientBase *client, uint32_t quic_version, + AppProtocol app_proto) { early_data_enabled = false; auto ssl_ctx = tls_ctx.get_native_handle(); ssl_ = SSL_new(ssl_ctx); if (!ssl_) { - std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_set_app_data(ssl_, client->conn_ref()); @@ -75,17 +76,17 @@ int TLSClientSession::init(bool &early_data_enabled, if (config.session_file) { auto f = BIO_new_file(config.session_file, "r"); if (f == nullptr) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr); BIO_free(f); if (session == nullptr) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { if (!SSL_set_session(ssl_, session)) { - std::cerr << "Could not set session" << std::endl; + std::println(stderr, "Could not set session"); } else if (!config.disable_early_data && SSL_SESSION_early_data_capable(session)) { early_data_enabled = true; @@ -99,12 +100,12 @@ int TLSClientSession::init(bool &early_data_enabled, if (!config.ech_config_list.empty() && SSL_set1_ech_config_list(ssl_, config.ech_config_list.data(), config.ech_config_list.size()) != 1) { - std::cerr << "Could not set ECHConfigList: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "Could not set ECHConfigList: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } - return 0; + return {}; } bool TLSClientSession::get_early_data_accepted() const { @@ -115,20 +116,21 @@ bool TLSClientSession::get_ech_accepted() const { return SSL_ech_accepted(ssl_); } -int TLSClientSession::write_ech_config_list(const char *path) const { +std::expected +TLSClientSession::write_ech_config_list(const char *path) const { const uint8_t *retry_configs; size_t retry_configslen; SSL_get0_ech_retry_configs(ssl_, &retry_configs, &retry_configslen); if (retry_configslen == 0) { - std::cerr << "No ECH retry configs found" << std::endl; - return -1; + std::println(stderr, "No ECH retry configs found"); + return std::unexpected{Error::CRYPTO}; } auto f = std::ofstream(path); if (!f) { - return -1; + return std::unexpected{Error::IO}; } f.write(reinterpret_cast(retry_configs), @@ -136,8 +138,8 @@ int TLSClientSession::write_ech_config_list(const char *path) const { f.close(); if (!f) { - return -1; + return std::unexpected{Error::IO}; } - return 0; + return {}; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h index 3ce70e9e363415..fad6372cc801c1 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_boringssl.h @@ -41,13 +41,14 @@ class TLSClientSession : public TLSSessionBase { public: TLSClientSession() = default; - int init(bool &early_data_enabled, const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, uint32_t quic_version, - AppProtocol app_proto); + std::expected init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, + const char *remote_addr, ClientBase *client, + uint32_t quic_version, AppProtocol app_proto); bool get_early_data_accepted() const; bool get_ech_accepted() const; - int write_ech_config_list(const char *path) const; + std::expected write_ech_config_list(const char *path) const; }; #endif // !defined(TLS_CLIENT_SESSION_BORINGSSL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc index 74871bf019f120..c5edb78881ce91 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.cc @@ -36,27 +36,27 @@ extern Config config; -int TLSClientSession::init(bool &early_data_enabled, - const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, - uint32_t quic_version, AppProtocol app_proto) { +std::expected +TLSClientSession::init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, const char *remote_addr, + ClientBase *client, uint32_t quic_version, + AppProtocol app_proto) { early_data_enabled = false; auto ssl_ctx = tls_ctx.get_native_handle(); auto ssl = SSL_new(ssl_ctx); if (!ssl) { - std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } ngtcp2_crypto_ossl_ctx_set_ssl(ossl_ctx_, ssl); if (ngtcp2_crypto_ossl_configure_client_session(ssl) != 0) { - std::cerr << "ngtcp2_crypto_ossl_configure_client_session failed" - << std::endl; - return -1; + std::println(stderr, "ngtcp2_crypto_ossl_configure_client_session failed"); + return std::unexpected{Error::CRYPTO}; } SSL_set_app_data(ssl, client->conn_ref()); @@ -84,17 +84,17 @@ int TLSClientSession::init(bool &early_data_enabled, if (config.session_file) { auto f = BIO_new_file(config.session_file, "r"); if (f == nullptr) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr); BIO_free(f); if (session == nullptr) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { if (!SSL_set_session(ssl, session)) { - std::cerr << "Could not set session" << std::endl; + std::println(stderr, "Could not set session"); } else if (!config.disable_early_data && SSL_SESSION_get_max_early_data(session)) { early_data_enabled = true; @@ -106,7 +106,7 @@ int TLSClientSession::init(bool &early_data_enabled, } } - return 0; + return {}; } bool TLSClientSession::get_early_data_accepted() const { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h index c11e94cd264507..9b08292f9679f3 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_ossl.h @@ -41,13 +41,16 @@ class TLSClientSession : public TLSSessionBase { public: TLSClientSession() = default; - int init(bool &early_data_enabled, const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, uint32_t quic_version, - AppProtocol app_proto); + std::expected init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, + const char *remote_addr, ClientBase *client, + uint32_t quic_version, AppProtocol app_proto); bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - int write_ech_config_list(const char *path) const { return 0; } + std::expected write_ech_config_list(const char *path) const { + return {}; + } }; #endif // !defined(TLS_CLIENT_SESSION_OSSL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc index 3f68bc48ad5503..31b26653899f6e 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.cc @@ -68,13 +68,14 @@ auto negotiated_protocols_hq = std::to_array({ }); } // namespace -int TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, - uint32_t quic_version, AppProtocol app_proto) { +std::expected +TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, + const char *remote_addr, ClientBase *client, + uint32_t quic_version, AppProtocol app_proto) { cptls_.ptls = ptls_client_new(tls_ctx.get_native_handle()); if (!cptls_.ptls) { - std::cerr << "ptls_client_new failed" << std::endl; - return -1; + std::println(stderr, "ptls_client_new failed"); + return std::unexpected{Error::CRYPTO}; } *ptls_get_data_ptr(cptls_.ptls) = client->conn_ref(); @@ -92,9 +93,9 @@ int TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, }; if (ngtcp2_crypto_picotls_configure_client_session(&cptls_, conn) != 0) { - std::cerr << "ngtcp2_crypto_picotls_configure_client_session failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_picotls_configure_client_session failed"); + return std::unexpected{Error::CRYPTO}; } switch (app_proto) { @@ -121,8 +122,8 @@ int TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, if (config.session_file) { auto f = BIO_new_file(config.session_file, "r"); if (f == nullptr) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { auto f_d = defer([f] { BIO_free(f); }); @@ -131,12 +132,12 @@ int TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, long datalen; if (PEM_read_bio(f, &name, &header, &data, &datalen) != 1) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { if ("PICOTLS SESSION PARAMETERS"sv != name) { - std::cerr << "TLS session file contains unexpected name: " << name - << std::endl; + std::println(stderr, "TLS session file contains unexpected name: {}", + name); } else { hsprops.client.session_ticket.base = new uint8_t[static_cast(datalen)]; @@ -158,7 +159,7 @@ int TLSClientSession::init(bool &early_data_enabled, TLSClientContext &tls_ctx, } } - return 0; + return {}; } bool TLSClientSession::get_early_data_accepted() const { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h index 6410caf0ab085d..1dd36a2732f242 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_picotls.h @@ -42,13 +42,16 @@ class TLSClientSession : public TLSSessionBase { TLSClientSession() = default; ~TLSClientSession(); - int init(bool &early_data_enabled, TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, uint32_t quic_version, - AppProtocol app_proto); + std::expected init(bool &early_data_enabled, + TLSClientContext &tls_ctx, + const char *remote_addr, ClientBase *client, + uint32_t quic_version, AppProtocol app_proto); bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - int write_ech_config_list(const char *path) const { return 0; } + std::expected write_ech_config_list(const char *path) const { + return {}; + } }; #endif // !defined(TLS_CLIENT_SESSION_PICOTLS_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc index 1693530255c732..11aa3174018c32 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.cc @@ -36,19 +36,20 @@ extern Config config; -int TLSClientSession::init(bool &early_data_enabled, - const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, - uint32_t quic_version, AppProtocol app_proto) { +std::expected +TLSClientSession::init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, const char *remote_addr, + ClientBase *client, uint32_t quic_version, + AppProtocol app_proto) { early_data_enabled = false; auto ssl_ctx = tls_ctx.get_native_handle(); ssl_ = SSL_new(ssl_ctx); if (!ssl_) { - std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_set_app_data(ssl_, client->conn_ref()); @@ -76,17 +77,17 @@ int TLSClientSession::init(bool &early_data_enabled, if (config.session_file) { auto f = BIO_new_file(config.session_file, "r"); if (f == nullptr) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { auto session = PEM_read_bio_SSL_SESSION(f, nullptr, 0, nullptr); BIO_free(f); if (session == nullptr) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { if (!SSL_set_session(ssl_, session)) { - std::cerr << "Could not set session" << std::endl; + std::println(stderr, "Could not set session"); } #ifndef LIBRESSL_VERSION_NUMBER else if (!config.disable_early_data && @@ -100,7 +101,7 @@ int TLSClientSession::init(bool &early_data_enabled, } } - return 0; + return {}; } bool TLSClientSession::get_early_data_accepted() const { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h index e462c0a5021f64..53e7a474fddb2b 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_quictls.h @@ -41,13 +41,16 @@ class TLSClientSession : public TLSSessionBase { public: TLSClientSession() = default; - int init(bool &early_data_enabled, const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, uint32_t quic_version, - AppProtocol app_proto); + std::expected init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, + const char *remote_addr, ClientBase *client, + uint32_t quic_version, AppProtocol app_proto); bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - int write_ech_config_list(const char *path) const { return 0; } + std::expected write_ech_config_list(const char *path) const { + return {}; + } }; #endif // !defined(TLS_CLIENT_SESSION_QUICTLS_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc index e487c143f9e05b..ad9c2d16faf1fc 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.cc @@ -37,27 +37,20 @@ using namespace std::literals; extern Config config; -namespace { -int wolfssl_session_ticket_cb(WOLFSSL *ssl, const unsigned char *ticket, - int ticketSz, void *cb_ctx) { - std::cerr << "session ticket callback invoked" << std::endl; - return 0; -} -} // namespace - -int TLSClientSession::init(bool &early_data_enabled, - const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, - uint32_t quic_version, AppProtocol app_proto) { +std::expected +TLSClientSession::init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, const char *remote_addr, + ClientBase *client, uint32_t quic_version, + AppProtocol app_proto) { early_data_enabled = false; auto ssl_ctx = tls_ctx.get_native_handle(); ssl_ = wolfSSL_new(ssl_ctx); if (!ssl_) { - std::cerr << "wolfSSL_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } wolfSSL_set_app_data(ssl_, client->conn_ref()); @@ -92,8 +85,8 @@ int TLSClientSession::init(bool &early_data_enabled, #ifdef HAVE_SESSION_TICKET auto f = wolfSSL_BIO_new_file(config.session_file, "r"); if (f == nullptr) { - std::cerr << "Could not open TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not open TLS session file {}", + config.session_file); } else { char *name, *header; unsigned char *data; @@ -102,23 +95,23 @@ int TLSClientSession::init(bool &early_data_enabled, WOLFSSL_SESSION *session; if (wolfSSL_PEM_read_bio(f, &name, &header, &data, &datalen) != 1) { - std::cerr << "Could not read TLS session file " << config.session_file - << std::endl; + std::println(stderr, "Could not read TLS session file {}", + config.session_file); } else { if ("WOLFSSL SESSION PARAMETERS"sv != name) { - std::cerr << "TLS session file contains unexpected name: " << name - << std::endl; + std::println(stderr, "TLS session file contains unexpected name: {}", + name); } else { pdata = data; session = wolfSSL_d2i_SSL_SESSION(nullptr, &pdata, datalen); if (session == nullptr) { - std::cerr << "Could not parse TLS session from file " - << config.session_file << std::endl; + std::println(stderr, "Could not parse TLS session from file {}", + config.session_file); } else { auto ret = wolfSSL_set_session(ssl_, session); if (ret != WOLFSSL_SUCCESS) { - std::cerr << "Could not install TLS session from file " - << config.session_file << std::endl; + std::println(stderr, "Could not install TLS session from file {}", + config.session_file); } else { if (!config.disable_early_data && wolfSSL_SESSION_get_max_early_data(session)) { @@ -137,13 +130,12 @@ int TLSClientSession::init(bool &early_data_enabled, wolfSSL_BIO_free(f); } wolfSSL_UseSessionTicket(ssl_); - wolfSSL_set_SessionTicket_cb(ssl_, wolfssl_session_ticket_cb, nullptr); #else // !defined(HAVE_SESSION_TICKET) - std::cerr << "TLS session im-/export not enabled in wolfSSL" << std::endl; + std::println(stderr, "TLS session im-/export not enabled in wolfSSL"); #endif // !defined(HAVE_SESSION_TICKET) } - return 0; + return {}; } bool TLSClientSession::get_early_data_accepted() const { diff --git a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h index d3a6e166b796ca..0621a8b21f2939 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_client_session_wolfssl.h @@ -41,13 +41,16 @@ class TLSClientSession : public TLSSessionBase { public: TLSClientSession() = default; - int init(bool &early_data_enabled, const TLSClientContext &tls_ctx, - const char *remote_addr, ClientBase *client, uint32_t quic_version, - AppProtocol app_proto); + std::expected init(bool &early_data_enabled, + const TLSClientContext &tls_ctx, + const char *remote_addr, ClientBase *client, + uint32_t quic_version, AppProtocol app_proto); bool get_early_data_accepted() const; bool get_ech_accepted() const { return false; } - int write_ech_config_list(const char *path) const { return 0; } + std::expected write_ech_config_list(const char *path) const { + return {}; + } }; #endif // !defined(TLS_CLIENT_SESSION_WOLFSSL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc index 2c168514cca7cd..06b7c34c9fed22 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.cc @@ -64,8 +64,7 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -80,7 +79,8 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(H3_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -103,8 +103,7 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -119,7 +118,8 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(HQ_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -134,15 +134,16 @@ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { } } // namespace -int TLSServerContext::init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto) { +std::expected TLSServerContext::init(const char *private_key_file, + const char *cert_file, + AppProtocol app_proto) { constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; ssl_ctx_ = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx_) { - std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_CTX_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } constexpr auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) | @@ -152,16 +153,16 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, SSL_CTX_set_options(ssl_ctx_, ssl_opts); if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) { - std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set1_groups_list failed"); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS); if (ngtcp2_crypto_boringssl_configure_server_context(ssl_ctx_) != 0) { - std::cerr << "ngtcp2_crypto_boringssl_configure_server_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_boringssl_configure_server_context failed"); + return std::unexpected{Error::CRYPTO}; } switch (app_proto) { @@ -177,21 +178,21 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != 1) { - std::cerr << "SSL_CTX_use_PrivateKey_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_PrivateKey_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) { - std::cerr << "SSL_CTX_use_certificate_chain_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_certificate_chain_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_check_private_key(ssl_ctx_) != 1) { - std::cerr << "SSL_CTX_check_private_key: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_check_private_key: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1); @@ -207,8 +208,8 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, if (!SSL_CTX_add_cert_compression_alg( ssl_ctx_, ngtcp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, ngtcp2::tls::cert_compress, ngtcp2::tls::cert_decompress)) { - std::cerr << "SSL_CTX_add_cert_compression_alg failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_add_cert_compression_alg failed"); + return std::unexpected{Error::CRYPTO}; } #endif // defined(HAVE_LIBBROTLI) @@ -220,10 +221,10 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, if (EVP_HPKE_KEY_init(pkey, EVP_hpke_x25519_hkdf_sha256(), echconf.private_key.bytes.data(), echconf.private_key.bytes.size()) != 1) { - std::cerr << "EVP_HPKE_KEY_init failed: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; + std::println(stderr, "EVP_HPKE_KEY_init failed: {}", + ERR_error_string(ERR_get_error(), nullptr)); - return -1; + return std::unexpected{Error::CRYPTO}; } auto pkey_d = defer([pkey] { EVP_HPKE_KEY_free(pkey); }); @@ -233,19 +234,19 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, if (SSL_ECH_KEYS_add(keys, 1, echconf.ech_config.data(), echconf.ech_config.size(), pkey) != 1) { - std::cerr << "SSL_ECH_KEYS_add failed: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_ECH_KEYS_add failed: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_set1_ech_keys(ssl_ctx_, keys) != 1) { - std::cerr << "SSL_CTX_set1_ech_keys failed: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set1_ech_keys failed: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } } - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.h b/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.h index 57045c122ef4e3..c55e24c034fbbb 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_boringssl.h @@ -40,8 +40,8 @@ class TLSServerContext { TLSServerContext() = default; ~TLSServerContext(); - int init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto); + std::expected init(const char *private_key_file, + const char *cert_file, AppProtocol app_proto); SSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc index 148224651182dc..9b382351c51caf 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.cc @@ -75,8 +75,7 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -91,7 +90,8 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(H3_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -114,8 +114,7 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -130,7 +129,8 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(HQ_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -212,15 +212,16 @@ SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session, } } // namespace -int TLSServerContext::init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto) { +std::expected TLSServerContext::init(const char *private_key_file, + const char *cert_file, + AppProtocol app_proto) { constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; ssl_ctx_ = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx_) { - std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_CTX_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_max_early_data(ssl_ctx_, UINT32_MAX); @@ -233,14 +234,14 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, SSL_CTX_set_options(ssl_ctx_, ssl_opts); if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) { - std::cerr << "SSL_CTX_set_ciphersuites: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set_ciphersuites: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) { - std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set1_groups_list failed"); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS); @@ -258,21 +259,21 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != 1) { - std::cerr << "SSL_CTX_use_PrivateKey_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_PrivateKey_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) { - std::cerr << "SSL_CTX_use_certificate_chain_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_certificate_chain_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_check_private_key(ssl_ctx_) != 1) { - std::cerr << "SSL_CTX_check_private_key: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_check_private_key: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1); @@ -287,7 +288,7 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, SSL_CTX_set_session_ticket_cb(ssl_ctx_, gen_ticket_cb, decrypt_ticket_cb, nullptr); - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.h b/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.h index d187b25552f6bd..619f1310fec093 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_ossl.h @@ -40,8 +40,8 @@ class TLSServerContext { TLSServerContext() = default; ~TLSServerContext(); - int init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto); + std::expected init(const char *private_key_file, + const char *cert_file, AppProtocol app_proto); SSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc index a1f8e4753fe695..e1498c159957e5 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.cc @@ -308,8 +308,9 @@ TLSServerContext::~TLSServerContext() { ptls_context_t *TLSServerContext::get_native_handle() { return &ctx_; } -int TLSServerContext::init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto) { +std::expected TLSServerContext::init(const char *private_key_file, + const char *cert_file, + AppProtocol app_proto) { switch (app_proto) { case AppProtocol::H3: ctx_.on_client_hello = &on_client_hello_h3; @@ -322,54 +323,55 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, } if (ngtcp2_crypto_picotls_configure_server_context(&ctx_) != 0) { - std::cerr << "ngtcp2_crypto_picotls_configure_server_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_picotls_configure_server_context failed"); + return std::unexpected{Error::CRYPTO}; } if (ptls_load_certificates(&ctx_, cert_file) != 0) { - std::cerr << "ptls_load_certificates failed" << std::endl; - return -1; + std::println(stderr, "ptls_load_certificates failed"); + return std::unexpected{Error::CRYPTO}; } - if (load_private_key(private_key_file) != 0) { - return -1; + if (auto rv = load_private_key(private_key_file); !rv) { + return rv; } if (config.verify_client) { ctx_.require_client_authentication = 1; } - return 0; + return {}; } -int TLSServerContext::load_private_key(const char *private_key_file) { +std::expected +TLSServerContext::load_private_key(const char *private_key_file) { auto fp = fopen(private_key_file, "rb"); if (fp == nullptr) { - std::cerr << "Could not open private key file " << private_key_file << ": " - << strerror(errno) << std::endl; - return -1; + std::println(stderr, "Could not open private key file {}: {}", + private_key_file, strerror(errno)); + return std::unexpected{Error::IO}; } auto fp_d = defer([fp] { fclose(fp); }); auto pkey = PEM_read_PrivateKey(fp, nullptr, nullptr, nullptr); if (pkey == nullptr) { - std::cerr << "Could not read private key file " << private_key_file - << std::endl; - return -1; + std::println(stderr, "Could not read private key file {}", + private_key_file); + return std::unexpected{Error::IO}; } 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; - return -1; + std::println(stderr, "ptls_openssl_init_sign_certificate failed"); + return std::unexpected{Error::CRYPTO}; } ctx_.sign_certificate = &sign_cert_.super; - return 0; + return {}; } void TLSServerContext::enable_keylog() { ctx_.log_event = &log_event; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.h b/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.h index acfa3d6bd2afc2..862568f96bed48 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_picotls.h @@ -41,15 +41,15 @@ class TLSServerContext { TLSServerContext(); ~TLSServerContext(); - int init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto); + std::expected init(const char *private_key_file, + const char *cert_file, AppProtocol app_proto); ptls_context_t *get_native_handle(); void enable_keylog(); private: - int load_private_key(const char *private_key_file); + std::expected load_private_key(const char *private_key_file); ptls_context_t ctx_; ptls_openssl_sign_certificate_t sign_cert_{}; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc index 664956814febd0..2a2be68510018f 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.cc @@ -75,8 +75,7 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -91,7 +90,8 @@ int alpn_select_proto_h3_cb(SSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(H3_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -114,8 +114,7 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -130,7 +129,8 @@ int alpn_select_proto_hq_cb(SSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(HQ_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -214,21 +214,22 @@ SSL_TICKET_RETURN decrypt_ticket_cb(SSL *ssl, SSL_SESSION *session, } // namespace #endif // !defined(LIBRESSL_VERSION_NUMBER) -int TLSServerContext::init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto) { +std::expected TLSServerContext::init(const char *private_key_file, + const char *cert_file, + AppProtocol app_proto) { constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; ssl_ctx_ = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx_) { - std::cerr << "SSL_CTX_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_CTX_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (ngtcp2_crypto_quictls_configure_server_context(ssl_ctx_) != 0) { - std::cerr << "ngtcp2_crypto_quictls_configure_server_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_quictls_configure_server_context failed"); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_max_early_data(ssl_ctx_, UINT32_MAX); @@ -244,14 +245,14 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, SSL_CTX_set_options(ssl_ctx_, ssl_opts); if (SSL_CTX_set_ciphersuites(ssl_ctx_, config.ciphers) != 1) { - std::cerr << "SSL_CTX_set_ciphersuites: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set_ciphersuites: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_set1_groups_list(ssl_ctx_, config.groups) != 1) { - std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; - return -1; + std::println(stderr, "SSL_CTX_set1_groups_list failed"); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS); @@ -269,21 +270,21 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != 1) { - std::cerr << "SSL_CTX_use_PrivateKey_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_PrivateKey_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) { - std::cerr << "SSL_CTX_use_certificate_chain_file: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_use_certificate_chain_file: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (SSL_CTX_check_private_key(ssl_ctx_) != 1) { - std::cerr << "SSL_CTX_check_private_key: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "SSL_CTX_check_private_key: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1); @@ -300,7 +301,7 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, nullptr); #endif // !defined(LIBRESSL_VERSION_NUMBER) - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.h b/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.h index 1f14349e3e7718..ccb485c48ac01a 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_quictls.h @@ -40,8 +40,8 @@ class TLSServerContext { TLSServerContext() = default; ~TLSServerContext(); - int init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto); + std::expected init(const char *private_key_file, + const char *cert_file, AppProtocol app_proto); SSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc index 53a22175e293d3..4c87a6d2666bcc 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.cc @@ -62,8 +62,7 @@ int alpn_select_proto_h3_cb(WOLFSSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -78,7 +77,8 @@ int alpn_select_proto_h3_cb(WOLFSSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &H3_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(H3_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -102,8 +102,7 @@ int alpn_select_proto_hq_cb(WOLFSSL *ssl, const unsigned char **out, break; default: if (!config.quiet) { - std::cerr << "Unexpected quic protocol version: " << std::hex << "0x" - << version << std::dec << std::endl; + std::println(stderr, "Unexpected quic protocol version: {:#x}", version); } return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -118,7 +117,8 @@ int alpn_select_proto_hq_cb(WOLFSSL *ssl, const unsigned char **out, } if (!config.quiet) { - std::cerr << "Client did not present ALPN " << &HQ_ALPN_V1[1] << std::endl; + std::println(stderr, "Client did not present ALPN {}", + as_string_view(HQ_ALPN_V1.subspan(1))); } return SSL_TLSEXT_ERR_ALERT_FATAL; @@ -133,8 +133,9 @@ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { } } // namespace -int TLSServerContext::init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto) { +std::expected TLSServerContext::init(const char *private_key_file, + const char *cert_file, + AppProtocol app_proto) { constexpr static unsigned char sid_ctx[] = "ngtcp2 server"; #ifdef DEBUG_WOLFSSL @@ -145,16 +146,15 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, ssl_ctx_ = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); if (!ssl_ctx_) { - std::cerr << "wolfSSL_CTX_new: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_new: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (ngtcp2_crypto_wolfssl_configure_server_context(ssl_ctx_) != 0) { - std::cerr << "ngtcp2_crypto_wolfssl_configure_server_context failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_wolfssl_configure_server_context failed"); + return std::unexpected{Error::CRYPTO}; } #ifdef WOLFSSL_EARLY_DATA @@ -168,16 +168,16 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, wolfSSL_CTX_set_options(ssl_ctx_, ssl_opts); if (wolfSSL_CTX_set_cipher_list(ssl_ctx_, config.ciphers) != 1) { - std::cerr << "wolfSSL_CTX_set_cipher_list: " - << ERR_error_string(ERR_get_error(), nullptr) << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_set_cipher_list: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_set1_groups_list(ssl_ctx_, const_cast(config.groups)) != 1) { - std::cerr << "wolfSSL_CTX_set1_groups_list(" << config.groups << ") failed" - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_set1_groups_list({}) failed", + config.groups); + return std::unexpected{Error::CRYPTO}; } wolfSSL_CTX_set_mode(ssl_ctx_, SSL_MODE_RELEASE_BUFFERS); @@ -195,24 +195,21 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, if (wolfSSL_CTX_use_PrivateKey_file(ssl_ctx_, private_key_file, SSL_FILETYPE_PEM) != 1) { - std::cerr << "wolfSSL_CTX_use_PrivateKey_file: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_use_PrivateKey_file: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file) != 1) { - std::cerr << "wolfSSL_CTX_use_certificate_chain_file: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_use_certificate_chain_file: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } if (wolfSSL_CTX_check_private_key(ssl_ctx_) != 1) { - std::cerr << "wolfSSL_CTX_check_private_key: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_CTX_check_private_key: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } wolfSSL_CTX_set_session_id_context(ssl_ctx_, sid_ctx, sizeof(sid_ctx) - 1); @@ -224,7 +221,7 @@ int TLSServerContext::init(const char *private_key_file, const char *cert_file, verify_cb); } - return 0; + return {}; } extern std::ofstream keylog_file; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.h b/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.h index 0a5aa70e4bf8a5..2f235ca4570b47 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_context_wolfssl.h @@ -41,8 +41,8 @@ class TLSServerContext { TLSServerContext() = default; ~TLSServerContext(); - int init(const char *private_key_file, const char *cert_file, - AppProtocol app_proto); + std::expected init(const char *private_key_file, + const char *cert_file, AppProtocol app_proto); WOLFSSL_CTX *get_native_handle() const; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc index 99af497130f4e0..89c581708c3a99 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.cc @@ -34,15 +34,15 @@ extern Config config; -int TLSServerSession::init(const TLSServerContext &tls_ctx, - HandlerBase *handler) { +std::expected +TLSServerSession::init(const TLSServerContext &tls_ctx, HandlerBase *handler) { auto ssl_ctx = tls_ctx.get_native_handle(); ssl_ = SSL_new(ssl_ctx); if (!ssl_) { - std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_set_app_data(ssl_, handler->conn_ref()); @@ -63,18 +63,17 @@ int TLSServerSession::init(const TLSServerContext &tls_ctx, auto quic_early_data_ctxlen = ngtcp2_transport_params_encode( quic_early_data_ctx.data(), quic_early_data_ctx.size(), ¶ms); if (quic_early_data_ctxlen < 0) { - std::cerr << "ngtcp2_transport_params_encode: " - << ngtcp2_strerror(static_cast(quic_early_data_ctxlen)) - << std::endl; - return -1; + std::println(stderr, "ngtcp2_transport_params_encode: {}", + ngtcp2_strerror(static_cast(quic_early_data_ctxlen))); + return std::unexpected{Error::CRYPTO}; } if (SSL_set_quic_early_data_context(ssl_, quic_early_data_ctx.data(), as_unsigned(quic_early_data_ctxlen)) != 1) { - std::cerr << "SSL_set_quic_early_data_context failed" << std::endl; - return -1; + std::println(stderr, "SSL_set_quic_early_data_context failed"); + return std::unexpected{Error::CRYPTO}; } - return 0; + return {}; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.h b/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.h index 7ffa4f0214abb8..3599e9a6c12081 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_boringssl.h @@ -30,6 +30,9 @@ #endif // defined(HAVE_CONFIG_H) #include "tls_session_base_quictls.h" +#include "shared.h" + +using namespace ngtcp2; class TLSServerContext; class HandlerBase; @@ -38,9 +41,10 @@ class TLSServerSession : public TLSSessionBase { public: TLSServerSession() = default; - int init(const TLSServerContext &tls_ctx, HandlerBase *handler); + std::expected init(const TLSServerContext &tls_ctx, + HandlerBase *handler); // ticket is sent automatically. - int send_session_ticket() { return 0; } + std::expected send_session_ticket() { return {}; } }; #endif // !defined(TLS_SERVER_SESSION_BORINGSSL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc index 0857c83f0b6940..1b708ede2c0c3a 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.cc @@ -31,28 +31,27 @@ #include "tls_server_context_ossl.h" #include "server_base.h" -int TLSServerSession::init(const TLSServerContext &tls_ctx, - HandlerBase *handler) { +std::expected +TLSServerSession::init(const TLSServerContext &tls_ctx, HandlerBase *handler) { auto ssl_ctx = tls_ctx.get_native_handle(); auto ssl = SSL_new(ssl_ctx); if (!ssl) { - std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } ngtcp2_crypto_ossl_ctx_set_ssl(ossl_ctx_, ssl); if (ngtcp2_crypto_ossl_configure_server_session(ssl) != 0) { - std::cerr << "ngtcp2_crypto_ossl_configure_server_session failed" - << std::endl; - return -1; + std::println(stderr, "ngtcp2_crypto_ossl_configure_server_session failed"); + return std::unexpected{Error::CRYPTO}; } SSL_set_app_data(ssl, handler->conn_ref()); SSL_set_accept_state(ssl); SSL_set_quic_tls_early_data_enabled(ssl, 1); - return 0; + return {}; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.h b/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.h index 195672c3cbb747..6f859e25e8d614 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_ossl.h @@ -30,6 +30,9 @@ #endif // defined(HAVE_CONFIG_H) #include "tls_session_base_ossl.h" +#include "shared.h" + +using namespace ngtcp2; class TLSServerContext; class HandlerBase; @@ -38,9 +41,10 @@ class TLSServerSession : public TLSSessionBase { public: TLSServerSession() = default; - int init(const TLSServerContext &tls_ctx, HandlerBase *handler); + std::expected init(const TLSServerContext &tls_ctx, + HandlerBase *handler); // ticket is sent automatically. - int send_session_ticket() { return 0; } + std::expected send_session_ticket() { return {}; } }; #endif // !defined(TLS_SERVER_SESSION_OSSL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc index 9039fd14ff34a9..1d7071df2fb916 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.cc @@ -37,11 +37,12 @@ using namespace ngtcp2; extern Config config; -int TLSServerSession::init(TLSServerContext &tls_ctx, HandlerBase *handler) { +std::expected TLSServerSession::init(TLSServerContext &tls_ctx, + HandlerBase *handler) { cptls_.ptls = ptls_server_new(tls_ctx.get_native_handle()); if (!cptls_.ptls) { - std::cerr << "ptls_server_new failed" << std::endl; - return -1; + std::println(stderr, "ptls_server_new failed"); + return std::unexpected{Error::CRYPTO}; } *ptls_get_data_ptr(cptls_.ptls) = handler->conn_ref(); @@ -57,10 +58,10 @@ int TLSServerSession::init(TLSServerContext &tls_ctx, HandlerBase *handler) { }; if (ngtcp2_crypto_picotls_configure_server_session(&cptls_) != 0) { - std::cerr << "ngtcp2_crypto_picotls_configure_server_session failed" - << std::endl; - return -1; + std::println(stderr, + "ngtcp2_crypto_picotls_configure_server_session failed"); + return std::unexpected{Error::CRYPTO}; } - return 0; + return {}; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.h b/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.h index 811b44559d95c9..fb15ee81f4dd47 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_picotls.h @@ -30,6 +30,9 @@ #endif // defined(HAVE_CONFIG_H) #include "tls_session_base_picotls.h" +#include "shared.h" + +using namespace ngtcp2; class TLSServerContext; class HandlerBase; @@ -38,9 +41,10 @@ class TLSServerSession : public TLSSessionBase { public: TLSServerSession() = default; - int init(TLSServerContext &tls_ctx, HandlerBase *handler); + std::expected init(TLSServerContext &tls_ctx, + HandlerBase *handler); // ticket is sent automatically. - int send_session_ticket() { return 0; } + std::expected send_session_ticket() { return {}; } }; #endif // !defined(TLS_SERVER_SESSION_PICOTLS_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc index 39a57ac9a505e4..5600efea0ed87a 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.cc @@ -31,15 +31,15 @@ #include "tls_server_context_quictls.h" #include "server_base.h" -int TLSServerSession::init(const TLSServerContext &tls_ctx, - HandlerBase *handler) { +std::expected +TLSServerSession::init(const TLSServerContext &tls_ctx, HandlerBase *handler) { auto ssl_ctx = tls_ctx.get_native_handle(); ssl_ = SSL_new(ssl_ctx); if (!ssl_) { - std::cerr << "SSL_new: " << ERR_error_string(ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "SSL_new: {}", + ERR_error_string(ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } SSL_set_app_data(ssl_, handler->conn_ref()); @@ -48,5 +48,5 @@ int TLSServerSession::init(const TLSServerContext &tls_ctx, SSL_set_quic_early_data_enabled(ssl_, 1); #endif // !defined(LIBRESSL_VERSION_NUMBER) - return 0; + return {}; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.h b/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.h index 94c24f851cda7c..a5b493bd6bdf94 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_quictls.h @@ -30,6 +30,9 @@ #endif // defined(HAVE_CONFIG_H) #include "tls_session_base_quictls.h" +#include "shared.h" + +using namespace ngtcp2; class TLSServerContext; class HandlerBase; @@ -38,9 +41,10 @@ class TLSServerSession : public TLSSessionBase { public: TLSServerSession() = default; - int init(const TLSServerContext &tls_ctx, HandlerBase *handler); + std::expected init(const TLSServerContext &tls_ctx, + HandlerBase *handler); // ticket is sent automatically. - int send_session_ticket() { return 0; } + std::expected send_session_ticket() { return {}; } }; #endif // !defined(TLS_SERVER_SESSION_QUICTLS_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc index 0cc2dd64950b7d..c596b79893a3c4 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.cc @@ -29,16 +29,15 @@ #include "tls_server_context_wolfssl.h" #include "server_base.h" -int TLSServerSession::init(const TLSServerContext &tls_ctx, - HandlerBase *handler) { +std::expected +TLSServerSession::init(const TLSServerContext &tls_ctx, HandlerBase *handler) { auto ssl_ctx = tls_ctx.get_native_handle(); ssl_ = wolfSSL_new(ssl_ctx); if (!ssl_) { - std::cerr << "wolfSSL_new: " - << wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr) - << std::endl; - return -1; + std::println(stderr, "wolfSSL_new: {}", + wolfSSL_ERR_error_string(wolfSSL_ERR_get_error(), nullptr)); + return std::unexpected{Error::CRYPTO}; } wolfSSL_set_app_data(ssl_, handler->conn_ref()); @@ -49,5 +48,5 @@ int TLSServerSession::init(const TLSServerContext &tls_ctx, // Just use QUIC v1 wolfSSL_set_quic_transport_version(ssl_, 0x39); - return 0; + return {}; } diff --git a/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.h b/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.h index 47458828939dbc..8d5f4bcc45eed8 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_server_session_wolfssl.h @@ -30,6 +30,9 @@ #endif // defined(HAVE_CONFIG_H) #include "tls_session_base_wolfssl.h" +#include "shared.h" + +using namespace ngtcp2; class TLSServerContext; class HandlerBase; @@ -38,9 +41,10 @@ class TLSServerSession : public TLSSessionBase { public: TLSServerSession() = default; - int init(const TLSServerContext &tls_ctx, HandlerBase *handler); + std::expected init(const TLSServerContext &tls_ctx, + HandlerBase *handler); // ticket is sent automatically. - int send_session_ticket() { return 0; } + std::expected send_session_ticket() { return {}; } }; #endif // !defined(TLS_SERVER_SESSION_WOLFSSL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.cc index d0465b8559f75a..ce5c2ebe9edbca 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.cc @@ -42,6 +42,17 @@ std::string TLSSessionBase::get_cipher_name() const { return wolfSSL_get_cipher_name(ssl_); } +std::string_view TLSSessionBase::get_negotiated_group() const { + using namespace std::literals; + + auto name = wolfSSL_get_curve_name(ssl_); + if (!name) { + return ""sv; + } + + return name; +} + std::string TLSSessionBase::get_selected_alpn() const { char *alpn = nullptr; unsigned short alpnlen; diff --git a/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.h b/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.h index ec9933da2be97c..b3942bc8e78d27 100644 --- a/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.h +++ b/deps/ngtcp2/ngtcp2/examples/tls_session_base_wolfssl.h @@ -44,11 +44,7 @@ class TLSSessionBase { WOLFSSL *get_native_handle() const; std::string get_cipher_name() const; - std::string_view get_negotiated_group() const { - using namespace std::literals; - - return ""sv; - } + std::string_view get_negotiated_group() const; std::string get_selected_alpn() const; // Keylog is enabled per SSL_CTX. void enable_keylog() {} diff --git a/deps/ngtcp2/ngtcp2/examples/util.cc b/deps/ngtcp2/ngtcp2/examples/util.cc index c5baac9073e9f3..b398210179e080 100644 --- a/deps/ngtcp2/ngtcp2/examples/util.cc +++ b/deps/ngtcp2/ngtcp2/examples/util.cc @@ -57,17 +57,19 @@ namespace ngtcp2 { namespace util { -std::optional -read_hpke_private_key_pem(const std::string_view &filename); +std::expected +read_hpke_private_key_pem(std::string_view filename); -std::optional> read_pem(const std::string_view &filename, - const std::string_view &name, - const std::string_view &type); +std::expected, Error> read_pem(std::string_view filename, + std::string_view name, + std::string_view type); -int write_pem(const std::string_view &filename, const std::string_view &name, - const std::string_view &type, std::span data); +std::expected write_pem(std::string_view filename, + std::string_view name, + std::string_view type, + std::span data); -std::string decode_hex(const std::string_view &s) { +std::string decode_hex(std::string_view s) { assert(s.size() % 2 == 0); std::string res(s.size() / 2, '0'); auto p = std::ranges::begin(res); @@ -182,7 +184,7 @@ uint8_t *hexdump_ascii(uint8_t *dest, std::span data) { *dest++ = '|'; for (auto c : data) { - if (0x20 <= c && c <= 0x7e) { + if (0x20 <= c && c <= 0x7E) { *dest++ = c; } else { *dest++ = '.'; @@ -244,23 +246,24 @@ uint8_t *hexdump_line(uint8_t *dest, std::span data, } // namespace namespace { -int hexdump_write(int fd, std::span data) { +std::expected hexdump_write(int fd, + std::span data) { ssize_t nwrite; for (; (nwrite = write(fd, data.data(), data.size())) == -1 && errno == EINTR;) ; if (nwrite == -1) { - return -1; + return std::unexpected{Error::IO}; } - return 0; + return {}; } } // namespace -int hexdump(FILE *out, const void *data, size_t datalen) { - if (datalen == 0) { - return 0; +std::expected hexdump(FILE *out, std::span data) { + if (data.empty()) { + return {}; } // min_space is the additional minimum space that the buffer must @@ -271,7 +274,7 @@ int hexdump(FILE *out, const void *data, size_t datalen) { auto fd = fileno(out); std::array buf; - auto input = std::span{reinterpret_cast(data), datalen}; + auto input = data; auto last = buf.data(); auto repeated = false; std::span s, last_s{}; @@ -298,22 +301,21 @@ int hexdump(FILE *out, const void *data, size_t datalen) { repeated = false; } - last = hexdump_line( - last, s, as_unsigned(s.data() - reinterpret_cast(data))); + last = hexdump_line(last, s, as_unsigned(s.data() - data.data())); *last++ = '\n'; last_s = s; auto len = static_cast(last - buf.data()); if (len + min_space > buf.size()) { - if (hexdump_write(fd, {buf.data(), len}) != 0) { - return -1; + if (auto rv = hexdump_write(fd, {buf.data(), len}); !rv) { + return rv; } last = buf.data(); } } - last = hexdump_addr(last, datalen); + last = hexdump_addr(last, data.size()); *last++ = '\n'; auto len = static_cast(last - buf.data()); @@ -321,7 +323,7 @@ int hexdump(FILE *out, const void *data, size_t datalen) { return hexdump_write(fd, {buf.data(), len}); } - return 0; + return {}; } ngtcp2_cid make_cid_key(std::span cid) { @@ -342,7 +344,7 @@ std::string straddr(const sockaddr *sa, socklen_t salen) { auto rv = getnameinfo(sa, salen, host.data(), host.size(), port.data(), port.size(), NI_NUMERICHOST | NI_NUMERICSERV); if (rv != 0) { - std::cerr << "getnameinfo: " << gai_strerror(rv) << std::endl; + std::println(stderr, "getnameinfo: {}", gai_strerror(rv)); return ""; } std::string res = "["; @@ -387,11 +389,11 @@ namespace { constexpr bool rws(char c) { return c == '\t' || c == ' '; } } // namespace -std::optional> -read_mime_types(const std::string_view &filename) { +std::expected, Error> +read_mime_types(std::string_view filename) { std::ifstream f(filename.data()); if (!f) { - return {}; + return std::unexpected{Error::IO}; } std::unordered_map dest; @@ -442,12 +444,12 @@ std::string format_duration(ngtcp2_duration n) { } namespace { -std::optional> -parse_uint_internal(const std::string_view &s) { +std::expected, Error> +parse_uint_internal(std::string_view s) { uint64_t res = 0; if (s.empty()) { - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } for (size_t i = 0; i < s.size(); ++i) { @@ -458,7 +460,7 @@ parse_uint_internal(const std::string_view &s) { auto d = static_cast(c - '0'); if (res > (std::numeric_limits::max() - d) / 10) { - return {}; + return std::unexpected{Error::INTEGER_OVERFLOW}; } res *= 10; @@ -469,29 +471,29 @@ parse_uint_internal(const std::string_view &s) { } } // namespace -std::optional parse_uint(const std::string_view &s) { +std::expected parse_uint(std::string_view s) { auto o = parse_uint_internal(s); if (!o) { - return {}; + return std::unexpected{o.error()}; } auto [res, idx] = *o; if (idx != s.size()) { - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } return res; } -std::optional parse_uint_iec(const std::string_view &s) { +std::expected parse_uint_iec(std::string_view s) { auto o = parse_uint_internal(s); if (!o) { - return {}; + return std::unexpected{o.error()}; } auto [res, idx] = *o; if (idx == s.size()) { return res; } if (idx + 1 != s.size()) { - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } uint64_t m; @@ -509,20 +511,20 @@ std::optional parse_uint_iec(const std::string_view &s) { m = 1 << 10; break; default: - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } if (res > std::numeric_limits::max() / m) { - return {}; + return std::unexpected{Error::INTEGER_OVERFLOW}; } return res * m; } -std::optional parse_duration(const std::string_view &s) { +std::expected parse_duration(std::string_view s) { auto o = parse_uint_internal(s); if (!o) { - return {}; + return std::unexpected{o.error()}; } auto [res, idx] = *o; if (idx == s.size()) { @@ -545,7 +547,7 @@ std::optional parse_duration(const std::string_view &s) { m = NGTCP2_SECONDS; break; default: - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } } else if (idx + 2 == s.size() && (s[idx + 1] == 's' || s[idx + 1] == 'S')) { switch (s[idx]) { @@ -561,14 +563,14 @@ std::optional parse_duration(const std::string_view &s) { case 'n': return res; default: - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } } else { - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } if (res > std::numeric_limits::max() / m) { - return {}; + return std::unexpected{Error::INTEGER_OVERFLOW}; } return res * m; @@ -611,12 +613,17 @@ template InputIt eat_dir(InputIt first, InputIt last) { } } // namespace -std::string normalize_path(const std::string_view &path) { - assert(path.size() <= 1024); +std::expected normalize_path(std::string_view path) { + constexpr size_t max_path = 1024; + + if (path.size() > max_path) { + return std::unexpected{Error::INVALID_ARGUMENT}; + } + assert(path.size() > 0); assert(path[0] == '/'); - std::array res; + std::array res; auto p = res.data(); auto first = std::ranges::begin(path); @@ -664,32 +671,37 @@ std::string normalize_path(const std::string_view &path) { return std::string{res.data(), p}; } -int make_socket_nonblocking(int fd) { +std::expected make_socket_nonblocking(int fd) { int rv; int flags; while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR) ; if (flags == -1) { - return -1; + return std::unexpected{Error::SYSCALL}; } while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR) ; - return rv; + if (rv == -1) { + return std::unexpected{Error::SYSCALL}; + } + + return {}; } -int create_nonblock_socket(int domain, int type, int protocol) { +std::expected create_nonblock_socket(int domain, int type, + int protocol) { #ifdef SOCK_NONBLOCK auto fd = socket(domain, type | SOCK_NONBLOCK, protocol); if (fd == -1) { - return -1; + return std::unexpected{Error::SYSCALL}; } #else // !defined(SOCK_NONBLOCK) auto fd = socket(domain, type, protocol); if (fd == -1) { - return -1; + return std::unexpected{Error::SYSCALL}; } make_socket_nonblocking(fd); @@ -698,7 +710,7 @@ int create_nonblock_socket(int domain, int type, int protocol) { return fd; } -std::vector split_str(const std::string_view &s, char delim) { +std::vector split_str(std::string_view s, char delim) { size_t len = 1; auto last = std::ranges::end(s); std::string_view::const_iterator d; @@ -722,85 +734,91 @@ std::vector split_str(const std::string_view &s, char delim) { return list; } -std::optional parse_version(const std::string_view &s) { +std::expected parse_version(std::string_view s) { if (!util::istarts_with(s, "0x"sv)) { - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } auto k = s.substr(2); auto k_last = k.data() + k.size(); uint32_t v; auto rv = std::from_chars(k.data(), k_last, v, 16); if (rv.ptr != k_last || rv.ec != std::errc{}) { - return {}; + return std::unexpected{Error::INVALID_ARGUMENT}; } return v; } -std::optional> -read_token(const std::string_view &filename) { +std::expected, Error> +read_token(std::string_view filename) { return read_pem(filename, "token"sv, "QUIC TOKEN"sv); } -int write_token(const std::string_view &filename, - std::span token) { +std::expected write_token(std::string_view filename, + std::span token) { return write_pem(filename, "token"sv, "QUIC TOKEN"sv, token); } -std::optional> -read_transport_params(const std::string_view &filename) { +std::expected, Error> +read_transport_params(std::string_view filename) { return read_pem(filename, "transport parameters"sv, "QUIC TRANSPORT PARAMETERS"sv); } -int write_transport_params(const std::string_view &filename, - std::span data) { +std::expected +write_transport_params(std::string_view filename, + std::span data) { return write_pem(filename, "transport parameters"sv, "QUIC TRANSPORT PARAMETERS"sv, data); } -std::string percent_decode(const std::string_view &s) { +std::string percent_decode(std::string_view s) { std::string result; - result.resize(s.size()); - auto p = std::ranges::begin(result); - for (auto first = std::ranges::begin(s), last = std::ranges::end(s); - first != last; ++first) { - if (*first != '%') { + + result.resize_and_overwrite(s.size(), [s](auto p, auto len) { + auto head = p; + + for (auto first = std::ranges::begin(s), last = std::ranges::end(s); + first != last; ++first) { + if (*first != '%') { + *p++ = *first; + continue; + } + + if (first + 1 != last && first + 2 != last && + is_hex_digit(*(first + 1)) && is_hex_digit(*(first + 2))) { + *p++ = static_cast((hex_to_uint(*(first + 1)) << 4) + + hex_to_uint(*(first + 2))); + first += 2; + continue; + } + *p++ = *first; - continue; } - if (first + 1 != last && first + 2 != last && is_hex_digit(*(first + 1)) && - is_hex_digit(*(first + 2))) { - *p++ = static_cast((hex_to_uint(*(first + 1)) << 4) + - hex_to_uint(*(first + 2))); - first += 2; - continue; - } + return p - head; + }); - *p++ = *first; - } - result.resize(as_unsigned(p - std::ranges::begin(result))); return result; } -std::optional> read_file(const std::string_view &path) { +std::expected, Error> read_file(std::string_view path) { auto fd = open(path.data(), O_RDONLY); if (fd == -1) { - return {}; + return std::unexpected{Error::IO}; } auto fd_d = defer([fd] { close(fd); }); auto size = lseek(fd, 0, SEEK_END); if (size == static_cast(-1)) { - return {}; + return std::unexpected{Error::IO}; } auto addr = mmap(nullptr, static_cast(size), PROT_READ, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { - return {}; + return std::unexpected{Error::IO}; } auto addr_d = @@ -825,16 +843,16 @@ bool recv_pkt_time_threshold_exceeded(bool time_sensitive, ngtcp2_tstamp start, util::timestamp() - start >= NGTCP2_MILLISECONDS; } -std::optional -read_ech_server_config(const std::string_view &path) { +std::expected +read_ech_server_config(std::string_view path) { auto pkey = read_hpke_private_key_pem(path); if (!pkey) { - return {}; + return std::unexpected{pkey.error()}; } auto ech_config = read_pem(path, "ECH config"sv, "ECHCONFIG"sv); if (!ech_config) { - return {}; + return std::unexpected{ech_config.error()}; } return ECHServerConfig{ @@ -847,8 +865,7 @@ std::span generate_siphash_key() { static auto key = [] { std::array key; - auto rv = generate_secure_random(as_writable_uint8_span(std::span{key})); - if (rv != 0) { + if (!generate_secure_random(as_writable_uint8_span(std::span{key}))) { assert(0); abort(); } diff --git a/deps/ngtcp2/ngtcp2/examples/util.h b/deps/ngtcp2/ngtcp2/examples/util.h index cccd13c3b1d23a..81306fd03d91a1 100644 --- a/deps/ngtcp2/ngtcp2/examples/util.h +++ b/deps/ngtcp2/ngtcp2/examples/util.h @@ -33,12 +33,12 @@ #include #include -#include #include #include #include #include #include +#include #include #include @@ -48,13 +48,14 @@ #include "network.h" #include "siphash.h" #include "template.h" +#include "shared.h" namespace ngtcp2 { namespace util { -inline nghttp3_nv make_nv(const std::string_view &name, - const std::string_view &value, uint8_t flags) { +inline nghttp3_nv make_nv(std::string_view name, std::string_view value, + uint8_t flags) { return nghttp3_nv{ reinterpret_cast(const_cast(std::ranges::data(name))), reinterpret_cast(const_cast(std::ranges::data(value))), @@ -64,18 +65,15 @@ inline nghttp3_nv make_nv(const std::string_view &name, }; } -inline nghttp3_nv make_nv_cc(const std::string_view &name, - const std::string_view &value) { +inline nghttp3_nv make_nv_cc(std::string_view name, std::string_view value) { return make_nv(name, value, NGHTTP3_NV_FLAG_NONE); } -inline nghttp3_nv make_nv_nc(const std::string_view &name, - const std::string_view &value) { +inline nghttp3_nv make_nv_nc(std::string_view name, std::string_view value) { return make_nv(name, value, NGHTTP3_NV_FLAG_NO_COPY_NAME); } -inline nghttp3_nv make_nv_nn(const std::string_view &name, - const std::string_view &value) { +inline nghttp3_nv make_nv_nn(std::string_view name, std::string_view value) { return make_nv(name, value, NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE); } @@ -90,7 +88,7 @@ constexpr O format_hex_uint8(uint8_t b, O result) { # pragma GCC diagnostic ignored "-Wsign-conversion" #endif // __GNUC__ *result++ = LOWER_XDIGITS[b >> 4]; - *result++ = LOWER_XDIGITS[b & 0xf]; + *result++ = LOWER_XDIGITS[b & 0xF]; #ifdef __GNUC__ # pragma GCC diagnostic pop #endif // __GNUC__ @@ -135,9 +133,12 @@ constexpr std::string format_hex(I first, std::iter_difference_t n) { std::string res; - res.resize(as_unsigned(n * 2)); + res.resize_and_overwrite(as_unsigned(n * 2), [first = std::move(first), + n](auto p, auto len) mutable { + format_hex(std::move(first), n, p); - format_hex(std::move(first), std::move(n), std::ranges::begin(res)); + return len; + }); return res; } @@ -155,15 +156,18 @@ constexpr O format_hex(R &&r, O result) { } // format_hex converts |R| in hex format, and returns the result. -template +template requires(!std::is_array_v> && sizeof(std::ranges::range_value_t) == sizeof(uint8_t)) constexpr std::string format_hex(R &&r) { std::string res; - res.resize(as_unsigned(std::ranges::distance(r) * 2)); + res.resize_and_overwrite(as_unsigned(std::ranges::distance(r) * 2), + [&r](auto p, auto len) { + format_hex(r, p); - format_hex(std::forward(r), std::ranges::begin(res)); + return len; + }); return res; } @@ -201,14 +205,16 @@ constexpr O format_hex(T n, O result) { template constexpr std::string format_hex(T n) { std::string res; - res.resize(sizeof(n) * 2); + res.resize_and_overwrite(sizeof(n) * 2, [n](auto p, auto len) { + format_hex(n, p); - format_hex(std::move(n), std::ranges::begin(res)); + return len; + }); return res; } -std::string decode_hex(const std::string_view &s); +std::string decode_hex(std::string_view s); // format_durationf formats |ns| in human readable manner. |ns| must // be nanoseconds resolution. This function uses the largest unit so @@ -228,10 +234,14 @@ bool numeric_host(const char *hostname); bool numeric_host(const char *hostname, int family); -// hexdump dumps |data| of length |datalen| in the format similar to -// hexdump(1) with -C option. This function returns 0 if it succeeds, -// or -1. -int hexdump(FILE *out, const void *data, size_t datalen); +// hexdump dumps |data| in the format similar to hexdump(1) with -C +// option. +std::expected hexdump(FILE *out, std::span data); + +template +std::expected hexdump(FILE *out, std::span data) { + return hexdump(out, as_uint8_span(data)); +} inline constexpr auto lowcase_tbl = [] { std::array tbl; @@ -259,8 +269,7 @@ struct CaseCmp { // istarts_with returns true if |s| starts with |prefix|. Comparison // is performed in case-insensitive manner. -constexpr bool istarts_with(const std::string_view &s, - const std::string_view &prefix) { +constexpr bool istarts_with(std::string_view s, std::string_view prefix) { return s.size() >= prefix.size() && std::ranges::equal(s.substr(0, prefix.size()), prefix, CaseCmp()); } @@ -285,8 +294,8 @@ std::string_view strccalgo(ngtcp2_cc_algo cc_algo); // read_mime_types reads "MIME media types and the extensions" file // denoted by |filename| and returns the mapping of extension to MIME // media type. -std::optional> -read_mime_types(const std::string_view &filename); +std::expected, Error> +read_mime_types(std::string_view filename); inline constexpr auto count_digit_tbl = [] { std::array::digits10> tbl; @@ -379,9 +388,11 @@ template constexpr std::string format_uint(T n) { std::string res; - res.resize(count_digit(n)); + res.resize_and_overwrite(count_digit(n), [n](auto p, auto len) { + utos(n, p); - utos(n, std::ranges::begin(res)); + return len; + }); return res; } @@ -411,31 +422,27 @@ std::string format_duration(ngtcp2_duration n); // parse_uint parses |s| as 64-bit unsigned integer. If it cannot // parse |s|, the return value does not contain a value. -std::optional parse_uint(const std::string_view &s); +std::expected parse_uint(std::string_view s); // parse_uint_iec parses |s| as 64-bit unsigned integer. It accepts // IEC unit letter (either "G", "M", or "K") in |s|. If it cannot // parse |s|, the return value does not contain a value. -std::optional parse_uint_iec(const std::string_view &s); +std::expected parse_uint_iec(std::string_view s); // parse_duration parses |s| as 64-bit unsigned integer. It accepts a // unit (either "h", "m", "s", "ms", "us", or "ns") in |s|. If no // unit is present, the unit "s" is assumed. If it cannot parse |s|, // the return value does not contain a value. -std::optional parse_duration(const std::string_view &s); +std::expected parse_duration(std::string_view s); // generate_secure_random generates a cryptographically secure pseudo // random data of |data|. -int generate_secure_random(std::span data); - -// generate_secret generates secret and writes it to |secret|. -// Currently, |secret| must be 32 bytes long. -int generate_secret(std::span secret); +std::expected generate_secure_random(std::span data); // normalize_path removes ".." by consuming a previous path component. // It also removes ".". It assumes that |path| starts with "/". If // it cannot consume a previous path component, it just removes "..". -std::string normalize_path(const std::string_view &path); +std::expected normalize_path(std::string_view path); template Pred> consteval auto pred_tbl_gen256(Pred pred) { @@ -469,7 +476,7 @@ constexpr bool is_hex_digit(char c) noexcept { // is_hex_string returns true if the length of |s| is even, and |s| // does not contain a character other than [0-9A-Fa-f]. It returns // false otherwise. -template +template requires(!std::is_array_v>) constexpr bool is_hex_string(R &&r) { return !(std::ranges::size(r) & 1) && std::ranges::all_of(r, is_hex_digit); @@ -501,21 +508,23 @@ constexpr uint32_t hex_to_uint(char c) noexcept { return hex_to_uint_tbl[static_cast(c)]; } -std::string percent_decode(const std::string_view &s); +std::string percent_decode(std::string_view s); -int make_socket_nonblocking(int fd); +std::expected make_socket_nonblocking(int fd); -int create_nonblock_socket(int domain, int type, int protocol); +std::expected create_nonblock_socket(int domain, int type, + int protocol); -std::optional> -read_token(const std::string_view &filename); -int write_token(const std::string_view &filename, - std::span token); +std::expected, Error> +read_token(std::string_view filename); +std::expected write_token(std::string_view filename, + std::span token); -std::optional> -read_transport_params(const std::string_view &filename); -int write_transport_params(const std::string_view &filename, - std::span data); +std::expected, Error> +read_transport_params(std::string_view filename); +std::expected +write_transport_params(std::string_view filename, + std::span data); const char *crypto_default_ciphers(); @@ -524,15 +533,14 @@ const char *crypto_default_groups(); // split_str parses delimited strings in |s| and returns substrings // delimited by |delim|. The any white spaces around substring are // treated as a part of substring. -std::vector split_str(const std::string_view &s, - char delim = ','); +std::vector split_str(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). -std::optional parse_version(const std::string_view &s); +std::expected parse_version(std::string_view s); // read_file reads a file denoted by |path| and returns its content. -std::optional> read_file(const std::string_view &path); +std::expected, Error> read_file(std::string_view path); size_t clamp_buffer_size(ngtcp2_conn *conn, size_t buflen, size_t gso_burst); @@ -562,16 +570,15 @@ struct ECHServerConfig { // read_ech_server_config reads server-side ECH configuration from a // file denoted by |path|. -std::optional -read_ech_server_config(const std::string_view &path); +std::expected +read_ech_server_config(std::string_view path); std::span generate_siphash_key(); // get_string returns a URL component specified by |f| of |uri|. This // function assumes that u.field_set & (1 << f) is nonzero. -constexpr std::string_view get_string(const std::string_view &uri, - const urlparse_url &u, - urlparse_url_fields f) { +constexpr std::string_view +get_string(std::string_view uri, const urlparse_url &u, urlparse_url_fields f) { assert(u.field_set & (1 << f)); auto p = &u.field_data[f]; @@ -606,4 +613,19 @@ inline bool operator==(const ngtcp2_cid &lhs, const ngtcp2_cid &rhs) { return ngtcp2_cid_eq(&lhs, &rhs); } +template <> +struct std::formatter : public std::formatter { + auto format(ngtcp2_cid cid, format_context &ctx) const { + std::array buf; + buf[0] = '0'; + buf[1] = 'x'; + + auto end = ngtcp2::util::format_hex(std::span{cid.data, cid.datalen}, + std::ranges::begin(buf) + 2); + + return std::formatter::format( + {std::ranges::begin(buf), end}, ctx); + } +}; + #endif // !defined(UTIL_H) diff --git a/deps/ngtcp2/ngtcp2/examples/util_openssl.cc b/deps/ngtcp2/ngtcp2/examples/util_openssl.cc index 85ff90d18d7e86..382eb3039c2f3d 100644 --- a/deps/ngtcp2/ngtcp2/examples/util_openssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/util_openssl.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -42,7 +43,7 @@ namespace ngtcp2 { namespace util { -int generate_secure_random(std::span data) { +std::expected generate_secure_random(std::span data) { #ifdef WITH_EXAMPLE_BORINGSSL using size_type = size_t; #else // !defined(WITH_EXAMPLE_BORINGSSL) @@ -50,49 +51,18 @@ int generate_secure_random(std::span data) { #endif // !defined(WITH_EXAMPLE_BORINGSSL) if (RAND_bytes(data.data(), static_cast(data.size())) != 1) { - return -1; + return std::unexpected{Error::CRYPTO}; } - return 0; + return {}; } -int generate_secret(std::span secret) { - std::array rand; - - if (generate_secure_random(rand) != 0) { - return -1; - } - - auto ctx = EVP_MD_CTX_new(); - if (ctx == nullptr) { - return -1; - } - - 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(secret.size()); - if (!EVP_DigestInit_ex(ctx, sha256, nullptr) || - !EVP_DigestUpdate(ctx, rand.data(), rand.size()) || - !EVP_DigestFinal_ex(ctx, secret.data(), &mdlen)) { - return -1; - } - - return 0; -} - -std::optional -read_hpke_private_key_pem(const std::string_view &filename) { +std::expected +read_hpke_private_key_pem(std::string_view filename) { auto f = BIO_new_file(filename.data(), "r"); if (f == nullptr) { - std::cerr << "Could not open file " << filename << std::endl; - return {}; + std::println(stderr, "Could not open file {}", filename); + return std::unexpected{Error::IO}; } auto f_d = defer([f] { BIO_free(f); }); @@ -100,7 +70,7 @@ read_hpke_private_key_pem(const std::string_view &filename) { EVP_PKEY *pkey; if (PEM_read_bio_PrivateKey(f, &pkey, nullptr, nullptr) == nullptr) { - return {}; + return std::unexpected{Error::IO}; } auto pkey_d = defer([pkey] { EVP_PKEY_free(pkey); }); @@ -122,19 +92,19 @@ read_hpke_private_key_pem(const std::string_view &filename) { break; } default: - return {}; + return std::unexpected{Error::UNSUPPORTED}; } return res; } -std::optional> read_pem(const std::string_view &filename, - const std::string_view &name, - const std::string_view &type) { +std::expected, Error> read_pem(std::string_view filename, + std::string_view name, + std::string_view type) { auto f = BIO_new_file(filename.data(), "r"); if (f == nullptr) { - std::cerr << "Could not open " << name << " file " << filename << std::endl; - return {}; + std::println(stderr, "Could not open {} file {}", name, filename); + return std::unexpected{Error::IO}; } auto f_d = defer([f] { BIO_free(f); }); @@ -145,9 +115,8 @@ std::optional> read_pem(const std::string_view &filename, long datalen; if (PEM_read_bio(f, &pem_type, &header, &data, &datalen) != 1) { - std::cerr << "Could not read " << name << " file " << filename - << std::endl; - return {}; + std::println(stderr, "Could not read {} file {}", name, filename); + return std::unexpected{Error::IO}; } auto pem_d = defer([pem_type, header, data] { @@ -164,19 +133,21 @@ std::optional> read_pem(const std::string_view &filename, } } -int write_pem(const std::string_view &filename, const std::string_view &name, - const std::string_view &type, std::span data) { +std::expected write_pem(std::string_view filename, + std::string_view name, + std::string_view type, + std::span data) { auto f = BIO_new_file(filename.data(), "w"); if (f == nullptr) { - std::cerr << "Could not write " << name << " in " << filename << std::endl; - return -1; + std::println(stderr, "Could not write {} in {}", name, filename); + return std::unexpected{Error::IO}; } PEM_write_bio(f, type.data(), "", data.data(), static_cast(data.size())); BIO_free(f); - return 0; + return {}; } const char *crypto_default_ciphers() { diff --git a/deps/ngtcp2/ngtcp2/examples/util_test.cc b/deps/ngtcp2/ngtcp2/examples/util_test.cc index f234de7c00480e..430a61a9734202 100644 --- a/deps/ngtcp2/ngtcp2/examples/util_test.cc +++ b/deps/ngtcp2/ngtcp2/examples/util_test.cc @@ -26,6 +26,8 @@ #include #include +#include +#include #include "util.h" @@ -57,29 +59,33 @@ const MunitSuite util_suite{ }; namespace util { -std::optional -read_hpke_private_key_pem(const std::string_view &filename) { - return {}; +std::expected +read_hpke_private_key_pem(std::string_view filename) { + return std::unexpected{Error::NOT_IMPLEMENTED}; } } // namespace util namespace util { -std::optional> read_pem(const std::string_view &filename, - const std::string_view &name, - const std::string_view &type) { - return {}; +std::expected, Error> read_pem(std::string_view filename, + std::string_view name, + std::string_view type) { + return std::unexpected{Error::NOT_IMPLEMENTED}; } } // namespace util namespace util { -int write_pem(const std::string_view &filename, const std::string_view &name, - const std::string_view &type, std::span data) { - return -1; +std::expected write_pem(std::string_view filename, + std::string_view name, + std::string_view type, + std::span data) { + return std::unexpected{Error::NOT_IMPLEMENTED}; } } // namespace util namespace util { -int generate_secure_random(std::span data) { return -1; } +std::expected generate_secure_random(std::span data) { + return std::unexpected{Error::NOT_IMPLEMENTED}; +} } // namespace util void test_util_format_durationf() { @@ -92,26 +98,26 @@ void test_util_format_durationf() { assert_stdstring_equal("2.00us", util::format_durationf(1999)); assert_stdstring_equal("1.00ms", util::format_durationf(999999)); assert_stdstring_equal("3.50ms", util::format_durationf(3500111)); - assert_stdstring_equal("9999.99s", util::format_durationf(9999990000000llu)); + assert_stdstring_equal("9999.99s", util::format_durationf(9999990000000ULL)); } void test_util_format_uint() { - assert_stdstring_equal("0"s, util::format_uint(0u)); + assert_stdstring_equal("0"s, util::format_uint(0U)); assert_stdstring_equal("18446744073709551615"s, - util::format_uint(18446744073709551615ull)); + util::format_uint(18446744073709551615ULL)); } void test_util_format_uint_iec() { - assert_stdstring_equal("0"s, util::format_uint_iec(0u)); - assert_stdstring_equal("1023"s, util::format_uint_iec((1u << 10) - 1)); - assert_stdstring_equal("1K"s, util::format_uint_iec(1u << 10)); - assert_stdstring_equal("1M"s, util::format_uint_iec(1u << 20)); - assert_stdstring_equal("1G"s, util::format_uint_iec(1u << 30)); + assert_stdstring_equal("0"s, util::format_uint_iec(0U)); + assert_stdstring_equal("1023"s, util::format_uint_iec((1U << 10) - 1)); + assert_stdstring_equal("1K"s, util::format_uint_iec(1U << 10)); + assert_stdstring_equal("1M"s, util::format_uint_iec(1U << 20)); + assert_stdstring_equal("1G"s, util::format_uint_iec(1U << 30)); assert_stdstring_equal( "18446744073709551615"s, util::format_uint_iec(std::numeric_limits::max())); assert_stdstring_equal("1025K"s, - util::format_uint_iec((1u << 20) + (1u << 10))); + util::format_uint_iec((1U << 20) + (1U << 10))); } void test_util_format_duration() { @@ -120,12 +126,12 @@ void test_util_format_duration() { assert_stdstring_equal("1us", util::format_duration(1000)); assert_stdstring_equal("1ms", util::format_duration(1000000)); assert_stdstring_equal("1s", util::format_duration(1000000000)); - assert_stdstring_equal("1m", util::format_duration(60000000000ull)); - assert_stdstring_equal("1h", util::format_duration(3600000000000ull)); + assert_stdstring_equal("1m", util::format_duration(60000000000ULL)); + assert_stdstring_equal("1h", util::format_duration(3600000000000ULL)); assert_stdstring_equal( "18446744073709551615ns", util::format_duration(std::numeric_limits::max())); - assert_stdstring_equal("61s", util::format_duration(61000000000ull)); + assert_stdstring_equal("61s", util::format_duration(61000000000ULL)); } void test_util_parse_uint() { @@ -142,7 +148,7 @@ void test_util_parse_uint() { { auto res = util::parse_uint("18446744073709551615"); assert_true(res.has_value()); - assert_uint64(18446744073709551615ull, ==, *res); + assert_uint64(18446744073709551615ULL, ==, *res); } { auto res = util::parse_uint("18446744073709551616"); @@ -187,7 +193,7 @@ void test_util_parse_uint_iec() { { auto res = util::parse_uint_iec("11G"); assert_true(res.has_value()); - assert_uint64((1ull << 30) * 11, ==, *res); + assert_uint64((1ULL << 30) * 11, ==, *res); } { auto res = util::parse_uint_iec("18446744073709551616"); @@ -273,19 +279,109 @@ void test_util_parse_duration() { } void test_util_normalize_path() { - assert_stdstring_equal("/", util::normalize_path("/")); - assert_stdstring_equal("/", util::normalize_path("//")); - assert_stdstring_equal("/foo", util::normalize_path("/foo")); - assert_stdstring_equal("/foo/bar/", util::normalize_path("/foo/bar/")); - assert_stdstring_equal("/foo/bar/", util::normalize_path("/foo/abc/../bar/")); - assert_stdstring_equal("/foo/bar/", - util::normalize_path("/../foo/abc/../bar/")); - assert_stdstring_equal("/foo/bar/", - util::normalize_path("/./foo/././abc///.././bar/./")); - assert_stdstring_equal("/foo/", util::normalize_path("/foo/.")); - assert_stdstring_equal("/foo/bar", util::normalize_path("/foo/./bar")); - assert_stdstring_equal("/bar", util::normalize_path("/foo/./../bar")); - assert_stdstring_equal("/bar", util::normalize_path("/../../bar")); + { + auto rv = util::normalize_path("/"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/", rv.value()); + } + + { + auto rv = util::normalize_path("//"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/", rv.value()); + } + + { + auto rv = util::normalize_path("/foo"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/foo", rv.value()); + } + + { + auto rv = util::normalize_path("/foo/bar/"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/foo/bar/", rv.value()); + } + + { + auto rv = util::normalize_path("/foo/abc/../bar/"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/foo/bar/", rv.value()); + } + + { + auto rv = util::normalize_path("/../foo/abc/../bar/"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/foo/bar/", rv.value()); + } + + { + auto rv = util::normalize_path("/./foo/././abc///.././bar/./"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/foo/bar/", rv.value()); + } + + { + auto rv = util::normalize_path("/foo/."); + + assert_true(rv.has_value()); + assert_stdstring_equal("/foo/", rv.value()); + } + + { + auto rv = util::normalize_path("/foo/./bar"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/foo/bar", rv.value()); + } + + { + auto rv = util::normalize_path("/foo/./../bar"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/bar", rv.value()); + } + + { + auto rv = util::normalize_path("/../../bar"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/bar", rv.value()); + } + + { + auto rv = util::normalize_path(std::string(1024, '/')); + + assert_true(rv.has_value()); + assert_stdstring_equal("/", rv.value()); + } + + { + auto rv = util::normalize_path(std::string(1025, '/')); + + assert_false(rv); + } + + { + auto rv = util::normalize_path("/.."); + + assert_true(rv.has_value()); + assert_stdstring_equal("/", rv.value()); + } + + { + auto rv = util::normalize_path("/../../index.html"); + + assert_true(rv.has_value()); + assert_stdstring_equal("/index.html", rv.value()); + } } void test_util_hexdump() { @@ -349,7 +445,7 @@ void test_util_hexdump() { }, { .title = "Non-printables", - .data = "\0\a\b\t\n\v\f\r\x7f"sv, + .data = "\0\a\b\t\n\v\f\r\x7F"sv, .dump = "00000000 00 07 08 09 0a 0b 0c 0d 7f " "|.........|\n" "00000009\n"sv, @@ -399,9 +495,9 @@ void test_util_hexdump() { munit_log(MUNIT_LOG_INFO, t.title); auto f = tmpfile(); - auto rv = util::hexdump(f, t.data.data(), t.data.size()); + auto rv = util::hexdump(f, std::span{t.data}); - assert_int(0, ==, rv); + assert_true(rv.has_value()); fseek(f, 0, SEEK_SET); auto nread = fread(buf, 1, sizeof(buf), f); @@ -414,35 +510,35 @@ void test_util_hexdump() { } void test_util_format_hex() { - auto a = std::to_array({0xde, 0xad, 0xbe, 0xef}); + auto a = std::to_array({0xDE, 0xAD, 0xBE, 0xEF}); assert_stdstring_equal("deadbeef"s, util::format_hex(a)); - assert_stdstring_equal("deadbeef"s, util::format_hex(0xdeadbeef)); + assert_stdstring_equal("deadbeef"s, util::format_hex(0xDEADBEEF)); assert_stdstring_equal("beef"s, util::format_hex(a.data() + 2, 2)); std::array buf; assert_stdsv_equal( "00"sv, (std::string_view{std::ranges::begin(buf), - util::format_hex(static_cast(0u), + util::format_hex(static_cast(0U), std::ranges::begin(buf))})); assert_stdsv_equal( "ec"sv, (std::string_view{std::ranges::begin(buf), - util::format_hex(static_cast(0xecu), + util::format_hex(static_cast(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))})); + 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))})); + 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))})); + util::format_hex(0xDEADBEEFBAADF00DU, std::ranges::begin(buf))})); assert_stdsv_equal( "ffffffffffffffff"sv, (std::string_view{std::ranges::begin(buf), @@ -466,7 +562,7 @@ void test_util_format_hex() { } void test_util_decode_hex() { - assert_stdstring_equal("\xde\xad\xbe\xef"s, util::decode_hex("deadbeef"sv)); + assert_stdstring_equal("\xDE\xAD\xBE\xEF"s, util::decode_hex("deadbeef"sv)); assert_stdstring_equal(""s, util::decode_hex(""sv)); } diff --git a/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc b/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc index 1afbaec4502fb9..8918847da1a95f 100644 --- a/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc +++ b/deps/ngtcp2/ngtcp2/examples/util_wolfssl.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -41,50 +42,26 @@ namespace ngtcp2 { namespace util { -int generate_secure_random(std::span data) { +std::expected generate_secure_random(std::span data) { if (wolfSSL_RAND_bytes(data.data(), static_cast(data.size())) != 1) { - return -1; + return std::unexpected{Error::CRYPTO}; } - return 0; -} - -std::optional -read_hpke_private_key_pem(const std::string_view &filename) { return {}; } -int generate_secret(std::span secret) { - std::array rand; - - if (generate_secure_random(rand) != 0) { - return -1; - } - - auto ctx = wolfSSL_EVP_MD_CTX_new(); - if (ctx == nullptr) { - return -1; - } - - auto mdlen = static_cast(secret.size()); - if (!wolfSSL_EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr) || - !wolfSSL_EVP_DigestUpdate(ctx, rand.data(), rand.size()) || - !wolfSSL_EVP_DigestFinal_ex(ctx, secret.data(), &mdlen)) { - wolfSSL_EVP_MD_CTX_free(ctx); - return -1; - } - - wolfSSL_EVP_MD_CTX_free(ctx); - return 0; +std::expected +read_hpke_private_key_pem(std::string_view filename) { + return std::unexpected{Error::NOT_IMPLEMENTED}; } -std::optional> read_pem(const std::string_view &filename, - const std::string_view &name, - const std::string_view &type) { +std::expected, Error> read_pem(std::string_view filename, + std::string_view name, + std::string_view type) { auto f = wolfSSL_BIO_new_file(filename.data(), "r"); if (f == nullptr) { - std::cerr << "Could not open " << name << " file " << filename << std::endl; - return {}; + std::println(stderr, "Could not open {} file {}", name, filename); + return std::unexpected{Error::IO}; } auto f_d = defer([f] { wolfSSL_BIO_free(f); }); @@ -94,8 +71,8 @@ std::optional> read_pem(const std::string_view &filename, long datalen; if (wolfSSL_PEM_read_bio(f, &pem_type, &header, &data, &datalen) != 1) { - std::cerr << "Could not read " << name << " file " << filename << std::endl; - return {}; + std::println(stderr, "Could not read {} file {}", name, filename); + return std::unexpected{Error::IO}; } auto pem_d = defer([pem_type, header, data] { @@ -105,27 +82,28 @@ std::optional> read_pem(const std::string_view &filename, }); if (type != pem_type) { - std::cerr << name << " file " << filename << " contains unexpected type" - << std::endl; - return {}; + std::println(stderr, "{} file {} contains unexpected type", name, filename); + return std::unexpected{Error::IO}; } return {{data, data + datalen}}; } -int write_pem(const std::string_view &filename, const std::string_view &name, - const std::string_view &type, std::span data) { +std::expected write_pem(std::string_view filename, + std::string_view name, + std::string_view type, + std::span data) { auto f = wolfSSL_BIO_new_file(filename.data(), "w"); if (f == nullptr) { - std::cerr << "Could not write " << name << " in " << filename << std::endl; - return -1; + std::println(stderr, "Could not write {} to {}", name, filename); + return std::unexpected{Error::IO}; } wolfSSL_PEM_write_bio(f, type.data(), "", data.data(), static_cast(data.size())); wolfSSL_BIO_free(f); - return 0; + return {}; } const char *crypto_default_ciphers() { diff --git a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h index ba3f7a7e1ae215..c71ff364e3099f 100644 --- a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h +++ b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h @@ -262,7 +262,7 @@ typedef struct ngtcp2_mem { * * :macro:`NGTCP2_PROTO_VER_V1` is the QUIC version 1. */ -#define NGTCP2_PROTO_VER_V1 ((uint32_t)0x00000001u) +#define NGTCP2_PROTO_VER_V1 ((uint32_t)0x00000001U) /** * @macro @@ -270,7 +270,7 @@ typedef struct ngtcp2_mem { * :macro:`NGTCP2_PROTO_VER_V2` is the QUIC version 2. See * :rfc:`9369`. */ -#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6b3343cfu) +#define NGTCP2_PROTO_VER_V2 ((uint32_t)0x6B3343CFU) /** * @macro @@ -294,7 +294,7 @@ typedef struct ngtcp2_mem { * :macro:`NGTCP2_RESERVED_VERSION_MASK` is the bit mask of reserved * version. */ -#define NGTCP2_RESERVED_VERSION_MASK 0x0a0a0a0au +#define NGTCP2_RESERVED_VERSION_MASK 0x0A0A0A0AU /** * @macrosection @@ -377,7 +377,7 @@ typedef struct ngtcp2_mem { * integrity tag of Retry packet. It is used for QUIC v1. */ #define NGTCP2_RETRY_KEY_V1 \ - "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e" + "\xBE\x0C\x69\x0B\x9F\x66\x57\x5A\x1D\x76\x6B\x54\xE3\x68\xC8\x4E" /** * @macro @@ -385,7 +385,7 @@ typedef struct ngtcp2_mem { * :macro:`NGTCP2_RETRY_NONCE_V1` is nonce used when generating * integrity tag of Retry packet. It is used for QUIC v1. */ -#define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb" +#define NGTCP2_RETRY_NONCE_V1 "\x46\x15\x99\xD3\x5D\x63\x2B\xF2\x23\x98\x25\xBB" /** * @macro @@ -395,7 +395,7 @@ typedef struct ngtcp2_mem { * :rfc:`9369`. */ #define NGTCP2_RETRY_KEY_V2 \ - "\x8f\xb4\xb0\x1b\x56\xac\x48\xe2\x60\xfb\xcb\xce\xad\x7c\xcc\x92" + "\x8F\xB4\xB0\x1B\x56\xAC\x48\xE2\x60\xFB\xCB\xCE\xAD\x7C\xCC\x92" /** * @macro @@ -404,7 +404,7 @@ typedef struct ngtcp2_mem { * integrity tag of Retry packet. It is used for QUIC v2. See * :rfc:`9369`. */ -#define NGTCP2_RETRY_NONCE_V2 "\xd8\x69\x69\xbc\x2d\x7c\x6d\x99\x90\xef\xb0\x4a" +#define NGTCP2_RETRY_NONCE_V2 "\xD8\x69\x69\xBC\x2D\x7C\x6D\x99\x90\xEF\xB0\x4A" /** * @macro @@ -812,7 +812,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * * :macro:`NGTCP2_PKT_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_PKT_FLAG_NONE 0x00u +#define NGTCP2_PKT_FLAG_NONE 0x00U /** * @macro @@ -820,7 +820,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * :macro:`NGTCP2_PKT_FLAG_LONG_FORM` indicates the Long header packet * header. */ -#define NGTCP2_PKT_FLAG_LONG_FORM 0x01u +#define NGTCP2_PKT_FLAG_LONG_FORM 0x01U /** * @macro @@ -828,14 +828,14 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { * :macro:`NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR` indicates that Fixed Bit * (aka QUIC bit) is not set. */ -#define NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR 0x02u +#define NGTCP2_PKT_FLAG_FIXED_BIT_CLEAR 0x02U /** * @macro * * :macro:`NGTCP2_PKT_FLAG_KEY_PHASE` indicates Key Phase bit set. */ -#define NGTCP2_PKT_FLAG_KEY_PHASE 0x04u +#define NGTCP2_PKT_FLAG_KEY_PHASE 0x04U /** * @enum @@ -887,7 +887,7 @@ typedef enum ngtcp2_pkt_type { * * :macro:`NGTCP2_NO_ERROR` is QUIC transport error code ``NO_ERROR``. */ -#define NGTCP2_NO_ERROR 0x0u +#define NGTCP2_NO_ERROR 0x0U /** * @macro @@ -895,7 +895,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_INTERNAL_ERROR` is QUIC transport error code * ``INTERNAL_ERROR``. */ -#define NGTCP2_INTERNAL_ERROR 0x1u +#define NGTCP2_INTERNAL_ERROR 0x1U /** * @macro @@ -903,7 +903,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_CONNECTION_REFUSED` is QUIC transport error code * ``CONNECTION_REFUSED``. */ -#define NGTCP2_CONNECTION_REFUSED 0x2u +#define NGTCP2_CONNECTION_REFUSED 0x2U /** * @macro @@ -911,7 +911,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_FLOW_CONTROL_ERROR` is QUIC transport error code * ``FLOW_CONTROL_ERROR``. */ -#define NGTCP2_FLOW_CONTROL_ERROR 0x3u +#define NGTCP2_FLOW_CONTROL_ERROR 0x3U /** * @macro @@ -919,7 +919,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_STREAM_LIMIT_ERROR` is QUIC transport error code * ``STREAM_LIMIT_ERROR``. */ -#define NGTCP2_STREAM_LIMIT_ERROR 0x4u +#define NGTCP2_STREAM_LIMIT_ERROR 0x4U /** * @macro @@ -927,7 +927,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_STREAM_STATE_ERROR` is QUIC transport error code * ``STREAM_STATE_ERROR``. */ -#define NGTCP2_STREAM_STATE_ERROR 0x5u +#define NGTCP2_STREAM_STATE_ERROR 0x5U /** * @macro @@ -935,7 +935,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_FINAL_SIZE_ERROR` is QUIC transport error code * ``FINAL_SIZE_ERROR``. */ -#define NGTCP2_FINAL_SIZE_ERROR 0x6u +#define NGTCP2_FINAL_SIZE_ERROR 0x6U /** * @macro @@ -943,7 +943,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_FRAME_ENCODING_ERROR` is QUIC transport error code * ``FRAME_ENCODING_ERROR``. */ -#define NGTCP2_FRAME_ENCODING_ERROR 0x7u +#define NGTCP2_FRAME_ENCODING_ERROR 0x7U /** * @macro @@ -951,7 +951,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_TRANSPORT_PARAMETER_ERROR` is QUIC transport error * code ``TRANSPORT_PARAMETER_ERROR``. */ -#define NGTCP2_TRANSPORT_PARAMETER_ERROR 0x8u +#define NGTCP2_TRANSPORT_PARAMETER_ERROR 0x8U /** * @macro @@ -959,7 +959,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_CONNECTION_ID_LIMIT_ERROR` is QUIC transport error * code ``CONNECTION_ID_LIMIT_ERROR``. */ -#define NGTCP2_CONNECTION_ID_LIMIT_ERROR 0x9u +#define NGTCP2_CONNECTION_ID_LIMIT_ERROR 0x9U /** * @macro @@ -967,7 +967,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_PROTOCOL_VIOLATION` is QUIC transport error code * ``PROTOCOL_VIOLATION``. */ -#define NGTCP2_PROTOCOL_VIOLATION 0xau +#define NGTCP2_PROTOCOL_VIOLATION 0xAU /** * @macro @@ -975,7 +975,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_INVALID_TOKEN` is QUIC transport error code * ``INVALID_TOKEN``. */ -#define NGTCP2_INVALID_TOKEN 0xbu +#define NGTCP2_INVALID_TOKEN 0xBU /** * @macro @@ -983,7 +983,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_APPLICATION_ERROR` is QUIC transport error code * ``APPLICATION_ERROR``. */ -#define NGTCP2_APPLICATION_ERROR 0xcu +#define NGTCP2_APPLICATION_ERROR 0xCU /** * @macro @@ -991,7 +991,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_CRYPTO_BUFFER_EXCEEDED` is QUIC transport error code * ``CRYPTO_BUFFER_EXCEEDED``. */ -#define NGTCP2_CRYPTO_BUFFER_EXCEEDED 0xdu +#define NGTCP2_CRYPTO_BUFFER_EXCEEDED 0xDU /** * @macro @@ -999,7 +999,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_KEY_UPDATE_ERROR` is QUIC transport error code * ``KEY_UPDATE_ERROR``. */ -#define NGTCP2_KEY_UPDATE_ERROR 0xeu +#define NGTCP2_KEY_UPDATE_ERROR 0xEU /** * @macro @@ -1007,7 +1007,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_AEAD_LIMIT_REACHED` is QUIC transport error code * ``AEAD_LIMIT_REACHED``. */ -#define NGTCP2_AEAD_LIMIT_REACHED 0xfu +#define NGTCP2_AEAD_LIMIT_REACHED 0xFU /** * @macro @@ -1015,7 +1015,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_NO_VIABLE_PATH` is QUIC transport error code * ``NO_VIABLE_PATH``. */ -#define NGTCP2_NO_VIABLE_PATH 0x10u +#define NGTCP2_NO_VIABLE_PATH 0x10U /** * @macro @@ -1023,7 +1023,7 @@ typedef enum ngtcp2_pkt_type { * :macro:`NGTCP2_CRYPTO_ERROR` is QUIC transport error code * ``CRYPTO_ERROR``. */ -#define NGTCP2_CRYPTO_ERROR 0x100u +#define NGTCP2_CRYPTO_ERROR 0x100U /** * @macro @@ -1187,6 +1187,9 @@ typedef struct ngtcp2_pkt_hd { * @struct * * :type:`ngtcp2_pkt_stateless_reset` represents Stateless Reset. + * + * Deprecated since v1.22.0. Use :type:`ngtcp2_pkt_stateless_reset2` + * instead. */ typedef struct ngtcp2_pkt_stateless_reset { /** @@ -1204,6 +1207,40 @@ typedef struct ngtcp2_pkt_stateless_reset { size_t randlen; } ngtcp2_pkt_stateless_reset; +/** + * @struct + * + * :type:`ngtcp2_stateless_reset_token` stores stateless reset token. + * + * This struct has been available since v1.22.0. + */ +typedef struct ngtcp2_stateless_reset_token { + uint8_t data[NGTCP2_STATELESS_RESET_TOKENLEN]; +} ngtcp2_stateless_reset_token; + +/** + * @struct + * + * :type:`ngtcp2_pkt_stateless_reset2` represents Stateless Reset. + * + * This struct has been available since v1.22.0. + */ +typedef struct ngtcp2_pkt_stateless_reset2 { + /** + * :member:`token` contains stateless reset token. + */ + ngtcp2_stateless_reset_token token; + /** + * :member:`rand` points a buffer which contains random bytes + * section. + */ + const uint8_t *rand; + /** + * :member:`randlen` is the number of random bytes. + */ + size_t randlen; +} ngtcp2_pkt_stateless_reset2; + /** * @macrosection * @@ -1250,7 +1287,7 @@ typedef struct ngtcp2_pkt_stateless_reset { * :macro:`NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1` is TLS * extension type of quic_transport_parameters. */ -#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39u +#define NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1 0x39U #ifdef NGTCP2_USE_GENERIC_SOCKADDR # ifndef NGTCP2_AF_INET @@ -1703,14 +1740,14 @@ typedef void (*ngtcp2_printf)(void *user_data, const char *format, ...); * * :macro:`NGTCP2_QLOG_WRITE_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_QLOG_WRITE_FLAG_NONE 0x00u +#define NGTCP2_QLOG_WRITE_FLAG_NONE 0x00U /** * @macro * * :macro:`NGTCP2_QLOG_WRITE_FLAG_FIN` indicates that this is the * final call to :type:`ngtcp2_qlog_write` in the current connection. */ -#define NGTCP2_QLOG_WRITE_FLAG_FIN 0x01u +#define NGTCP2_QLOG_WRITE_FLAG_FIN 0x01U /** * @struct @@ -2444,11 +2481,42 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_decode_hd_short(ngtcp2_pkt_hd *dest, * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` * |randlen| is strictly less than * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`. + * + * Deprecated since v1.22.0. Use `ngtcp2_pkt_write_stateless_reset2` + * instead. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset( uint8_t *dest, size_t destlen, const uint8_t *stateless_reset_token, const uint8_t *rand, size_t randlen); +/** + * @function + * + * `ngtcp2_pkt_write_stateless_reset2` writes Stateless Reset packet + * in the buffer pointed by |dest| whose length is |destlen|. |token| + * must store the Stateless Reset Token. |rand| specifies the random + * octets preceding Stateless Reset Token. The length of |rand| is + * specified by |randlen| which must be at least + * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN` bytes long. + * + * If |randlen| is too long to write them all in the buffer, |rand| is + * written to the buffer as much as possible, and is truncated. + * + * This function returns the number of bytes written to the buffer, or + * one of the following negative error codes: + * + * :macro:`NGTCP2_ERR_NOBUF` + * Buffer is too small. + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * |randlen| is strictly less than + * :macro:`NGTCP2_MIN_STATELESS_RESET_RANDLEN`. + * + * This function has been available since v1.22.0. + */ +NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_stateless_reset2( + uint8_t *dest, size_t destlen, const ngtcp2_stateless_reset_token *token, + const uint8_t *rand, size_t randlen); + /** * @function * @@ -2744,7 +2812,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * * :macro:`NGTCP2_STREAM_DATA_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_STREAM_DATA_FLAG_NONE 0x00u +#define NGTCP2_STREAM_DATA_FLAG_NONE 0x00U /** * @macro @@ -2752,7 +2820,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * :macro:`NGTCP2_STREAM_DATA_FLAG_FIN` indicates that this chunk of * data is final piece of an incoming stream. */ -#define NGTCP2_STREAM_DATA_FLAG_FIN 0x01u +#define NGTCP2_STREAM_DATA_FLAG_FIN 0x01U /** * @macro @@ -2761,7 +2829,7 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * data contains data received in 0-RTT packet, and the handshake has * not completed yet, which means that the data might be replayed. */ -#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02u +#define NGTCP2_STREAM_DATA_FLAG_0RTT 0x02U /** * @functypedef @@ -2816,7 +2884,7 @@ typedef int (*ngtcp2_stream_open)(ngtcp2_conn *conn, int64_t stream_id, * * :macro:`NGTCP2_STREAM_CLOSE_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_STREAM_CLOSE_FLAG_NONE 0x00u +#define NGTCP2_STREAM_CLOSE_FLAG_NONE 0x00U /** * @macro @@ -2824,7 +2892,7 @@ typedef int (*ngtcp2_stream_open)(ngtcp2_conn *conn, int64_t stream_id, * :macro:`NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET` indicates that * app_error_code parameter is set. */ -#define NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET 0x01u +#define NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET 0x01U /** * @functypedef @@ -2905,6 +2973,9 @@ typedef int (*ngtcp2_acked_stream_data_offset)( * The implementation of this callback should return 0 if it succeeds. * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library * call return immediately. + * + * Deprecated since v1.22.0. Use :type:`ngtcp2_recv_stateless_reset2` + * instead. */ typedef int (*ngtcp2_recv_stateless_reset)(ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset *sr, @@ -2969,6 +3040,9 @@ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. + * + * Deprecated since v1.22.0. Use + * :type:`ngtcp2_get_new_connection_id2` instead. */ typedef int (*ngtcp2_get_new_connection_id)(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token, size_t cidlen, @@ -3033,7 +3107,7 @@ typedef int (*ngtcp2_update_key)( * * :macro:`NGTCP2_PATH_VALIDATION_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_PATH_VALIDATION_FLAG_NONE 0x00u +#define NGTCP2_PATH_VALIDATION_FLAG_NONE 0x00U /** * @macro @@ -3042,7 +3116,7 @@ typedef int (*ngtcp2_update_key)( * validation involving server preferred address. This flag is only * set for client. */ -#define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01u +#define NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR 0x01U /** * @macro @@ -3051,7 +3125,7 @@ typedef int (*ngtcp2_update_key)( * server should send NEW_TOKEN frame for the new remote address. * This flag is only set for server. */ -#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02u +#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02U /** * @functypedef @@ -3166,6 +3240,9 @@ typedef enum ngtcp2_connection_id_status_type { * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. + * + * Deprecated since v1.22.0. Use :type:`ngtcp2_connection_id_status2` + * instead. */ typedef int (*ngtcp2_connection_id_status)( ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq, @@ -3221,7 +3298,7 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( * * :macro:`NGTCP2_DATAGRAM_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_DATAGRAM_FLAG_NONE 0x00u +#define NGTCP2_DATAGRAM_FLAG_NONE 0x00U /** * @macro @@ -3230,7 +3307,7 @@ typedef void (*ngtcp2_delete_crypto_cipher_ctx)( * received in 0-RTT packet, and the handshake has not completed yet, * which means that the data might be replayed. */ -#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01u +#define NGTCP2_DATAGRAM_FLAG_0RTT 0x01U /** * @functypedef @@ -3293,6 +3370,9 @@ typedef int (*ngtcp2_lost_datagram)(ngtcp2_conn *conn, uint64_t dgram_id, * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return * immediately. + * + * Deprecated since v1.22.0. Use + * :type:`ngtcp2_get_path_challenge_data2` instead. */ typedef int (*ngtcp2_get_path_challenge_data)(ngtcp2_conn *conn, uint8_t *data, void *user_data); @@ -3364,9 +3444,99 @@ typedef int (*ngtcp2_recv_key)(ngtcp2_conn *conn, ngtcp2_encryption_level level, typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn, void *user_data); +/** + * @functypedef + * + * :type:`ngtcp2_recv_stateless_reset2` is a callback function which + * is called when Stateless Reset packet is received. The stateless + * reset details are given in |sr|. + * + * The implementation of this callback should return 0 if it succeeds. + * Returning :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library + * call return immediately. + * + * This type has been available since v1.22.0 + */ +typedef int (*ngtcp2_recv_stateless_reset2)( + ngtcp2_conn *conn, const ngtcp2_pkt_stateless_reset2 *sr, void *user_data); + +/** + * @functypedef + * + * :type:`ngtcp2_get_new_connection_id2` is a callback function to ask + * an application for new connection ID. Application must generate + * new unused connection ID with the exact |cidlen| bytes, and store + * it in |cid|. It also has to generate a stateless reset token, and + * store it in |token|. + * + * The callback function must return 0 if it succeeds. Returning + * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return + * immediately. + * + * This type has been available since v1.22.0 + */ +typedef int (*ngtcp2_get_new_connection_id2)( + ngtcp2_conn *conn, ngtcp2_cid *cid, ngtcp2_stateless_reset_token *token, + size_t cidlen, void *user_data); + +/** + * @functypedef + * + * :type:`ngtcp2_connection_id_status2` is a callback function which + * is called when the status of Destination Connection ID changes. + * + * |token| is the associated stateless reset token, and it is ``NULL`` + * if no token is present. + * + * |type| is the one of the value defined in + * :type:`ngtcp2_connection_id_status_type`. The new value might be + * added in the future release. + * + * The callback function must return 0 if it succeeds. Returning + * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return + * immediately. + * + * This type has been available since v1.22.0 + */ +typedef int (*ngtcp2_connection_id_status2)( + ngtcp2_conn *conn, ngtcp2_connection_id_status_type type, uint64_t seq, + const ngtcp2_cid *cid, const ngtcp2_stateless_reset_token *token, + void *user_data); + +/** + * @struct + * + * :type:`ngtcp2_path_challenge_data` stores path challenge data. + * + * This type has been available since v1.22.0. + */ +typedef struct ngtcp2_path_challenge_data { + uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; +} ngtcp2_path_challenge_data; + +/** + * @functypedef + * + * :type:`ngtcp2_get_path_challenge_data2` is a callback function to + * ask an application for new data that is sent in PATH_CHALLENGE + * frame. Application must generate new unpredictable, exactly + * :macro:`NGTCP2_PATH_CHALLENGE_DATALEN` bytes of random data, and + * store them into |data|. + * + * The callback function must return 0 if it succeeds. Returning + * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return + * immediately. + * + * This type has been available since v1.22.0. + */ +typedef int (*ngtcp2_get_path_challenge_data2)(ngtcp2_conn *conn, + ngtcp2_path_challenge_data *data, + void *user_data); + #define NGTCP2_CALLBACKS_V1 1 #define NGTCP2_CALLBACKS_V2 2 -#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V2 +#define NGTCP2_CALLBACKS_V3 3 +#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V3 /** * @struct @@ -3453,6 +3623,11 @@ typedef struct ngtcp2_callbacks { * :member:`recv_stateless_reset` is a callback function which is * invoked when Stateless Reset packet is received. This callback * function is optional. + * + * Deprecated since v1.22.0. Use :member:`recv_stateless_reset2` + * instead. If both :member:`recv_stateless_reset` and + * :member:`recv_stateless_reset2` are set, the latter has the + * precedence. */ ngtcp2_recv_stateless_reset recv_stateless_reset; /** @@ -3483,8 +3658,14 @@ typedef struct ngtcp2_callbacks { ngtcp2_rand rand; /** * :member:`get_new_connection_id` is a callback function which is - * invoked when the library needs new connection ID. This callback - * function must be specified. + * invoked when the library needs new connection ID. Either this + * callback function or :member:`get_new_connection_id2` must be + * specified. + * + * Deprecated since v1.22.0. Use :member:`get_new_connection_id2` + * instead. If both :member:`get_new_connection_id` and + * :member:`get_new_connection_id2` are set, the latter has the + * precedence. */ ngtcp2_get_new_connection_id get_new_connection_id; /** @@ -3545,6 +3726,10 @@ typedef struct ngtcp2_callbacks { * when the new Destination Connection ID is activated, or the * activated Destination Connection ID is now deactivated. This * callback function is optional. + * + * Deprecated since v1.22.0. Use :member:`dcid_status2` instead. + * If both :member:`dcid_status` and :member:`dcid_status2` are set, + * the latter has the precedence. */ ngtcp2_connection_id_status dcid_status; /** @@ -3595,6 +3780,9 @@ typedef struct ngtcp2_callbacks { * :member:`get_path_challenge_data` is a callback function which is * invoked when the library needs new data sent along with * PATH_CHALLENGE frame. This callback must be specified. + * + * Deprecated since v1.22.0. Use :member:`get_path_challenge_data2` + * instead. */ ngtcp2_get_path_challenge_data get_path_challenge_data; /** @@ -3638,6 +3826,35 @@ typedef struct ngtcp2_callbacks { * available since v1.14.0. */ ngtcp2_begin_path_validation begin_path_validation; + /* The following fields have been added since NGTCP2_CALLBACKS_V3. */ + /** + * :member:`recv_stateless_reset2` is a callback function which is + * invoked when Stateless Reset packet is received. This callback + * function is optional. This field is available since v1.22.0. + */ + ngtcp2_recv_stateless_reset2 recv_stateless_reset2; + /** + * :member:`get_new_connection_id2` is a callback function which is + * invoked when the library needs new connection ID. This callback + * function must be specified. This field is available since + * v1.22.0. + */ + ngtcp2_get_new_connection_id2 get_new_connection_id2; + /** + * :member:`dcid_status2` is a callback function which is invoked + * when the new Destination Connection ID is activated, or the + * activated Destination Connection ID is now deactivated. This + * callback function is optional. This field is available since + * v1.22.0. + */ + ngtcp2_connection_id_status2 dcid_status2; + /** + * :member:`get_path_challenge_data2` is a callback function which + * is invoked when the library needs new data sent along with + * PATH_CHALLENGE frame. This callback must be specified. This + * field is available since v1.22.0. + */ + ngtcp2_get_path_challenge_data2 get_path_challenge_data2; } ngtcp2_callbacks; /** @@ -3853,6 +4070,21 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_pkt_versioned( ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_tstamp ts); +/** + * @function + * + * `ngtcp2_conn_continue_handshake` resumes handshake interrupted by + * TLS stack routine (e.g., private key operation offloading, + * certificate lookup, etc). + * + * This function returns 0 if it succeeds. In general, this function + * returns the same set of error codes from `ngtcp2_conn_read_pkt`. + * + * This function has been available since v1.22.0. + */ +NGTCP2_EXTERN int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn, + ngtcp2_tstamp ts); + /** * @function * @@ -4512,7 +4744,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, * * :macro:`NGTCP2_WRITE_STREAM_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_WRITE_STREAM_FLAG_NONE 0x00u +#define NGTCP2_WRITE_STREAM_FLAG_NONE 0x00U /** * @macro @@ -4520,7 +4752,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, * :macro:`NGTCP2_WRITE_STREAM_FLAG_MORE` indicates that more data may * come, and should be coalesced into the same packet if possible. */ -#define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01u +#define NGTCP2_WRITE_STREAM_FLAG_MORE 0x01U /** * @macro @@ -4528,7 +4760,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, * :macro:`NGTCP2_WRITE_STREAM_FLAG_FIN` indicates that a passed data * is the final part of a stream. */ -#define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02u +#define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02U /** * @macro @@ -4539,7 +4771,7 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, * finalizing it. PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE * only packets and PMTUD packets are excluded. */ -#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04u +#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04U /** * @function @@ -4724,7 +4956,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_NONE` indicates no flag set. */ -#define NGTCP2_WRITE_DATAGRAM_FLAG_NONE 0x00u +#define NGTCP2_WRITE_DATAGRAM_FLAG_NONE 0x00U /** * @macro @@ -4732,7 +4964,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_MORE` indicates that more data * may come, and should be coalesced into the same packet if possible. */ -#define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01u +#define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01U /** * @macro @@ -4743,7 +4975,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( * finalizing it. PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE * only packets and PMTUD packets are excluded. */ -#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02u +#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02U /** * @function @@ -4980,6 +5212,8 @@ NGTCP2_EXTERN size_t ngtcp2_conn_get_scid(ngtcp2_conn *conn, ngtcp2_cid *dest); * * :type:`ngtcp2_cid_token` is the convenient struct to store * Connection ID, its associated path, and stateless reset token. + * + * Deprecated since v1.22.0. Use :type:`ngtcp2_cid_token2` instead. */ typedef struct ngtcp2_cid_token { /** @@ -5019,10 +5253,65 @@ typedef struct ngtcp2_cid_token { * sizeof(:type:`ngtcp2_cid_token`) * n bytes available, where n is * the return value of `ngtcp2_conn_get_active_dcid` with |dest| == * NULL. + * + * Deprecated since v1.22.0. Use `ngtcp2_conn_get_active_dcid2` + * instead. */ NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest); +/** + * @struct + * + * :type:`ngtcp2_cid_token2` is the convenient struct to store + * Connection ID, its associated path, and stateless reset token. + * + * This type has been available since v1.22.0. + */ +typedef struct ngtcp2_cid_token2 { + /** + * :member:`seq` is the sequence number of this Connection ID. + */ + uint64_t seq; + /** + * :member:`cid` is Connection ID. + */ + ngtcp2_cid cid; + /** + * :member:`ps` is the path which this Connection ID is associated + * with. + */ + ngtcp2_path_storage ps; + /** + * :member:`token` is the stateless reset token for this Connection + * ID. + */ + ngtcp2_stateless_reset_token token; + /** + * :member:`token_present` is nonzero if token contains stateless + * reset token. + */ + uint8_t token_present; +} ngtcp2_cid_token2; + +/** + * @function + * + * `ngtcp2_conn_get_active_dcid2` writes the all active Destination + * Connection IDs and their tokens to |dest|. Before handshake + * completes, this function returns 0. If |dest| is NULL, this + * function does not write anything, and returns the number of + * Destination Connection IDs that would otherwise be written to the + * provided buffer. The buffer pointed by |dest| must have + * sizeof(:type:`ngtcp2_cid_token2`) * n bytes available, where n is + * the return value of `ngtcp2_conn_get_active_dcid2` with |dest| == + * NULL. + * + * This function has been available since v1.22.0. + */ +NGTCP2_EXTERN size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn, + ngtcp2_cid_token2 *dest); + /** * @function * @@ -5553,7 +5842,7 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr, * @function * * `ngtcp2_conn_write_connection_close` writes a packet which contains - * CONNECTION_CLOSE frame(s) (type 0x1c or 0x1d) in the buffer pointed + * CONNECTION_CLOSE frame(s) (type 0x1C or 0x1D) in the buffer pointed * by |dest| whose capacity is |destlen|. * * For client, |destlen| should be at least @@ -5570,10 +5859,10 @@ NGTCP2_EXTERN void ngtcp2_ccerr_set_application_error(ngtcp2_ccerr *ccerr, * * If :member:`ccerr->type ` == * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_TRANSPORT`, this - * function sends CONNECTION_CLOSE (type 0x1c) frame. If + * function sends CONNECTION_CLOSE (type 0x1C) frame. If * :member:`ccerr->type ` == * :enum:`ngtcp2_ccerr_type.NGTCP2_CCERR_TYPE_APPLICATION`, it sends - * CONNECTION_CLOSE (type 0x1d) frame. Otherwise, it does not produce + * CONNECTION_CLOSE (type 0x1D) frame. Otherwise, it does not produce * any data, and returns 0. * * |destlen| could be shorten by some factors (e.g., server side diff --git a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h index ff43c9c8f8c7c0..88e0107a55ac85 100644 --- a/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h +++ b/deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h @@ -36,7 +36,7 @@ * * Version number of the ngtcp2 library release. */ -#define NGTCP2_VERSION "1.21.0" +#define NGTCP2_VERSION "1.22.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 0x011500 +#define NGTCP2_VERSION_NUM 0x011600 #endif /* !defined(NGTCP2_VERSION_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h index 1a591c5ead84ea..026c2cabe8733b 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h @@ -97,16 +97,16 @@ typedef struct ngtcp2_acktr_ack_entry { } ngtcp2_acktr_ack_entry; /* NGTCP2_ACKTR_FLAG_NONE indicates that no flag set. */ -#define NGTCP2_ACKTR_FLAG_NONE 0x00u +#define NGTCP2_ACKTR_FLAG_NONE 0x00U /* NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK indicates that immediate acknowledgement is required. */ -#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01u +#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01U /* NGTCP2_ACKTR_FLAG_ACTIVE_ACK indicates that there are pending protected packet to be acknowledged. */ -#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02u +#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02U /* NGTCP2_ACKTR_FLAG_CANCEL_TIMER is set when ACK delay timer is expired and canceled. */ -#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100u +#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100U ngtcp2_static_ringbuf_def(acks, 32, sizeof(ngtcp2_acktr_ack_entry)) diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h index c2224f85cd9c11..6314b1afc81270 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h @@ -46,14 +46,14 @@ void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src); int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b); /* NGTCP2_ADDR_CMP_FLAG_NONE indicates that no flag set. */ -#define NGTCP2_ADDR_CMP_FLAG_NONE 0x0u +#define NGTCP2_ADDR_CMP_FLAG_NONE 0x0U /* NGTCP2_ADDR_CMP_FLAG_ADDR indicates IP addresses do not match. */ -#define NGTCP2_ADDR_CMP_FLAG_ADDR 0x1u +#define NGTCP2_ADDR_CMP_FLAG_ADDR 0x1U /* NGTCP2_ADDR_CMP_FLAG_PORT indicates ports do not match. */ -#define NGTCP2_ADDR_CMP_FLAG_PORT 0x2u +#define NGTCP2_ADDR_CMP_FLAG_PORT 0x2U /* NGTCP2_ADDR_CMP_FLAG_FAMILY indicates address families do not match. */ -#define NGTCP2_ADDR_CMP_FLAG_FAMILY 0x4u +#define NGTCP2_ADDR_CMP_FLAG_FAMILY 0x4U /* * ngtcp2_addr_cmp compares address and port between |a| and |b|, and diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c index cb865c5cefdf4c..fff7a9ef65bea1 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_balloc.c @@ -30,7 +30,7 @@ void ngtcp2_balloc_init(ngtcp2_balloc *balloc, size_t blklen, const ngtcp2_mem *mem) { - assert((blklen & 0xfu) == 0); + assert((blklen & 0xFU) == 0); balloc->mem = mem; balloc->blklen = blklen; @@ -66,7 +66,7 @@ int ngtcp2_balloc_get(ngtcp2_balloc *balloc, void **pbuf, size_t n) { if (ngtcp2_buf_left(&balloc->buf) < n) { p = ngtcp2_mem_malloc(balloc->mem, - sizeof(ngtcp2_memblock_hd) + 0x8u + balloc->blklen); + sizeof(ngtcp2_memblock_hd) + 0x8U + balloc->blklen); if (p == NULL) { return NGTCP2_ERR_NOMEM; } @@ -76,15 +76,15 @@ int ngtcp2_balloc_get(ngtcp2_balloc *balloc, void **pbuf, size_t n) { balloc->head = hd; ngtcp2_buf_init( &balloc->buf, - (uint8_t *)(((uintptr_t)p + sizeof(ngtcp2_memblock_hd) + 0xfu) & - ~(uintptr_t)0xfu), + (uint8_t *)(((uintptr_t)p + sizeof(ngtcp2_memblock_hd) + 0xFU) & + ~(uintptr_t)0xFU), balloc->blklen); } - assert(((uintptr_t)balloc->buf.last & 0xfu) == 0); + assert(((uintptr_t)balloc->buf.last & 0xFU) == 0); *pbuf = balloc->buf.last; - balloc->buf.last += (n + 0xfu) & ~(uintptr_t)0xfu; + balloc->buf.last += (n + 0xFU) & ~(uintptr_t)0xFU; return 0; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_callbacks.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_callbacks.c index 7e77186772b762..1d65d93d566944 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_callbacks.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_callbacks.c @@ -42,7 +42,7 @@ const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest( return src; } - memset(dest, 0, sizeof(*dest)); + *dest = (ngtcp2_callbacks){0}; callbacks_copy(dest, src, callbacks_version); @@ -63,6 +63,9 @@ size_t ngtcp2_callbackslen_version(int callbacks_version) { switch (callbacks_version) { case NGTCP2_CALLBACKS_VERSION: return sizeof(callbacks); + case NGTCP2_CALLBACKS_V2: + return offsetof(ngtcp2_callbacks, begin_path_validation) + + sizeof(callbacks.begin_path_validation); case NGTCP2_CALLBACKS_V1: return offsetof(ngtcp2_callbacks, tls_early_data_rejected) + sizeof(callbacks.tls_early_data_rejected); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c index 42a4827664912f..4eba2aaca5d316 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c @@ -29,8 +29,9 @@ #include "ngtcp2_path.h" #include "ngtcp2_str.h" +#include "ngtcp2_pkt.h" -void ngtcp2_cid_zero(ngtcp2_cid *cid) { memset(cid, 0, sizeof(*cid)); } +void ngtcp2_cid_zero(ngtcp2_cid *cid) { *cid = (ngtcp2_cid){0}; } void ngtcp2_cid_init(ngtcp2_cid *cid, const uint8_t *data, size_t datalen) { assert(datalen <= NGTCP2_MAX_CIDLEN); @@ -74,12 +75,12 @@ void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) { } void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid, - const uint8_t *token) { + const ngtcp2_stateless_reset_token *token) { dcid->seq = seq; dcid->cid = *cid; if (token) { - memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN); + dcid->token = *token; dcid->flags = NGTCP2_DCID_FLAG_TOKEN_PRESENT; } else { dcid->flags = NGTCP2_DCID_FLAG_NONE; @@ -93,11 +94,12 @@ void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid, dcid->max_udp_payload_size = NGTCP2_MAX_UDP_PAYLOAD_SIZE; } -void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token) { +void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, + const ngtcp2_stateless_reset_token *token) { assert(token); dcid->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT; - memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN); + dcid->token = *token; } void ngtcp2_dcid_set_path(ngtcp2_dcid *dcid, const ngtcp2_path *path) { @@ -106,7 +108,7 @@ void ngtcp2_dcid_set_path(ngtcp2_dcid *dcid, const ngtcp2_path *path) { void ngtcp2_dcid_copy(ngtcp2_dcid *dest, const ngtcp2_dcid *src) { ngtcp2_dcid_init(dest, src->seq, &src->cid, - (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? src->token + (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? &src->token : NULL); ngtcp2_path_copy(&dest->ps.path, &src->ps.path); dest->retired_ts = src->retired_ts; @@ -123,18 +125,19 @@ void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src) { if (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) { dest->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT; - memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN); + dest->token = src->token; } else if (dest->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) { dest->flags &= (uint8_t)~NGTCP2_DCID_FLAG_TOKEN_PRESENT; } } int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq, - const ngtcp2_cid *cid, const uint8_t *token) { + const ngtcp2_cid *cid, + const ngtcp2_stateless_reset_token *token) { if (dcid->seq == seq) { return ngtcp2_cid_eq(&dcid->cid, cid) && (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) && - memcmp(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN) == 0 + ngtcp2_stateless_reset_token_eq(&dcid->token, token) ? 0 : NGTCP2_ERR_PROTO; } @@ -142,12 +145,12 @@ int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq, return !ngtcp2_cid_eq(&dcid->cid, cid) ? 0 : NGTCP2_ERR_PROTO; } -int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid, - const ngtcp2_path *path, - const uint8_t *token) { +int ngtcp2_dcid_verify_stateless_reset_token( + const ngtcp2_dcid *dcid, const ngtcp2_path *path, + const ngtcp2_stateless_reset_token *token) { return ngtcp2_path_eq(&dcid->ps.path, path) && (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) && - ngtcp2_cmemeq(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN) + ngtcp2_cmemeq(dcid->token.data, token->data, sizeof(token->data)) ? 0 : NGTCP2_ERR_INVALID_ARGUMENT; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.h index 9321cfb64e6daf..f4956b0bac0ebe 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.h @@ -35,13 +35,13 @@ #include "ngtcp2_path.h" /* NGTCP2_SCID_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_SCID_FLAG_NONE 0x00u +#define NGTCP2_SCID_FLAG_NONE 0x00U /* NGTCP2_SCID_FLAG_USED indicates that a local endpoint observed that a remote endpoint uses this particular Connection ID. */ -#define NGTCP2_SCID_FLAG_USED 0x01u +#define NGTCP2_SCID_FLAG_USED 0x01U /* NGTCP2_SCID_FLAG_RETIRED indicates that this particular Connection ID is retired. */ -#define NGTCP2_SCID_FLAG_RETIRED 0x02u +#define NGTCP2_SCID_FLAG_RETIRED 0x02U typedef struct ngtcp2_scid { ngtcp2_pq_entry pe; @@ -57,13 +57,13 @@ typedef struct ngtcp2_scid { } ngtcp2_scid; /* NGTCP2_DCID_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_DCID_FLAG_NONE 0x00u +#define NGTCP2_DCID_FLAG_NONE 0x00U /* NGTCP2_DCID_FLAG_PATH_VALIDATED indicates that an associated path has been validated. */ -#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01u +#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01U /* NGTCP2_DCID_FLAG_TOKEN_PRESENT indicates that a stateless reset token is set in token field. */ -#define NGTCP2_DCID_FLAG_TOKEN_PRESENT 0x02u +#define NGTCP2_DCID_FLAG_TOKEN_PRESENT 0x02U typedef struct ngtcp2_dcid { /* seq is the sequence number associated to the Connection ID. */ @@ -93,7 +93,7 @@ typedef struct ngtcp2_dcid { /* token is a stateless reset token received along with this Connection ID. The stateless reset token is tied to the connection, not to the particular Connection ID. */ - uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN]; + ngtcp2_stateless_reset_token token; } ngtcp2_dcid; /* ngtcp2_cid_zero makes |cid| zero-length. */ @@ -123,17 +123,18 @@ void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src); /* * ngtcp2_dcid_init initializes |dcid| with the given parameters. If - * |token| is NULL, the function fills dcid->token with 0. |token| - * must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long. + * |token| is not NULL, the function sets + * NGTCP2_DCID_FLAG_TOKEN_PRESENT flag. */ void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid, - const uint8_t *token); + const ngtcp2_stateless_reset_token *token); /* * ngtcp2_dcid_set_token sets |token| to |dcid|. |token| must not be - * NULL, and must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long. + * NULL. */ -void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token); +void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, + const ngtcp2_stateless_reset_token *token); /* * ngtcp2_dcid_set_path sets |path| to |dcid|. It sets @@ -160,7 +161,8 @@ void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src); * |token|) tuple against |dcid|. */ int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq, - const ngtcp2_cid *cid, const uint8_t *token); + const ngtcp2_cid *cid, + const ngtcp2_stateless_reset_token *token); /* * ngtcp2_dcid_verify_stateless_reset_token verifies stateless reset @@ -172,9 +174,9 @@ int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq, * NGTCP2_ERR_INVALID_ARGUMENT * Tokens do not match; or |dcid| does not contain a token. */ -int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid, - const ngtcp2_path *path, - const uint8_t *token); +int ngtcp2_dcid_verify_stateless_reset_token( + const ngtcp2_dcid *dcid, const ngtcp2_path *path, + const ngtcp2_stateless_reset_token *token); /* TODO It might be performance win if we store congestion state in this entry, and restore it when migrate back to this path. */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c index 29fe7b03911aa3..c470eb05b0648d 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c @@ -255,13 +255,20 @@ static int conn_call_extend_max_local_streams_uni(ngtcp2_conn *conn, } static int conn_call_get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, - uint8_t *token, size_t cidlen) { + ngtcp2_stateless_reset_token *token, + size_t cidlen) { int rv; - assert(conn->callbacks.get_new_connection_id); + if (conn->callbacks.get_new_connection_id2) { + rv = conn->callbacks.get_new_connection_id2(conn, cid, token, cidlen, + conn->user_data); + } else { + assert(conn->callbacks.get_new_connection_id); + + rv = conn->callbacks.get_new_connection_id(conn, cid, token->data, cidlen, + conn->user_data); + } - rv = conn->callbacks.get_new_connection_id(conn, cid, token, cidlen, - conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -424,14 +431,20 @@ static int conn_call_dcid_status(ngtcp2_conn *conn, const ngtcp2_dcid *dcid) { int rv; - if (!conn->callbacks.dcid_status) { + if (conn->callbacks.dcid_status2) { + rv = conn->callbacks.dcid_status2( + conn, type, dcid->seq, &dcid->cid, + (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? &dcid->token : NULL, + conn->user_data); + } else if (conn->callbacks.dcid_status) { + rv = conn->callbacks.dcid_status( + conn, type, dcid->seq, &dcid->cid, + (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token.data : NULL, + conn->user_data); + } else { return 0; } - rv = conn->callbacks.dcid_status( - conn, type, dcid->seq, &dcid->cid, - (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? dcid->token : NULL, - conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -504,12 +517,19 @@ static int conn_call_client_initial(ngtcp2_conn *conn) { return 0; } -static int conn_call_get_path_challenge_data(ngtcp2_conn *conn, uint8_t *data) { +static int conn_call_get_path_challenge_data(ngtcp2_conn *conn, + ngtcp2_path_challenge_data *data) { int rv; - assert(conn->callbacks.get_path_challenge_data); + if (conn->callbacks.get_path_challenge_data2) { + rv = conn->callbacks.get_path_challenge_data2(conn, data, conn->user_data); + } else { + assert(conn->callbacks.get_path_challenge_data); + + rv = conn->callbacks.get_path_challenge_data(conn, data->data, + conn->user_data); + } - rv = conn->callbacks.get_path_challenge_data(conn, data, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -550,14 +570,24 @@ static int conn_call_recv_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd) { static int conn_call_recv_stateless_reset(ngtcp2_conn *conn, - const ngtcp2_pkt_stateless_reset *sr) { + const ngtcp2_pkt_stateless_reset2 *sr) { int rv; + ngtcp2_pkt_stateless_reset legacy_sr; + + if (conn->callbacks.recv_stateless_reset2) { + rv = conn->callbacks.recv_stateless_reset2(conn, sr, conn->user_data); + } else if (conn->callbacks.recv_stateless_reset) { + memcpy(legacy_sr.stateless_reset_token, sr->token.data, + sizeof(legacy_sr.stateless_reset_token)); + legacy_sr.rand = sr->rand; + legacy_sr.randlen = sr->randlen; - if (!conn->callbacks.recv_stateless_reset) { + rv = + conn->callbacks.recv_stateless_reset(conn, &legacy_sr, conn->user_data); + } else { return 0; } - rv = conn->callbacks.recv_stateless_reset(conn, sr, conn->user_data); if (rv != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -840,8 +870,8 @@ static void conn_reset_conn_stat_cc(ngtcp2_conn *conn, */ static void reset_conn_stat_recovery(ngtcp2_conn_stat *cstat) { /* Initializes them with UINT64_MAX. */ - memset(cstat->loss_time, 0xff, sizeof(cstat->loss_time)); - memset(cstat->last_tx_pkt_ts, 0xff, sizeof(cstat->last_tx_pkt_ts)); + memset(cstat->loss_time, 0xFF, sizeof(cstat->loss_time)); + memset(cstat->last_tx_pkt_ts, 0xFF, sizeof(cstat->last_tx_pkt_ts)); } /* @@ -1072,13 +1102,13 @@ static void conn_update_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { conn->callbacks.rand(&r, 1, &conn->local.settings.rand_ctx); - if (1ll << pktns->tx.skip_pkt.exponent > + if (1LL << pktns->tx.skip_pkt.exponent > (NGTCP2_MAX_PKT_NUM - min_gap) / ((int64_t)r + 1)) { pktns->tx.skip_pkt.next_pkt_num = INT64_MAX; return; } - gap = ((int64_t)r + 1) * (1ll << pktns->tx.skip_pkt.exponent++) + min_gap; + gap = ((int64_t)r + 1) * (1LL << pktns->tx.skip_pkt.exponent++) + min_gap; if (pktns->tx.last_pkt_num > NGTCP2_MAX_PKT_NUM - gap) { pktns->tx.skip_pkt.next_pkt_num = INT64_MAX; @@ -1196,11 +1226,12 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, assert(callbacks->hp_mask); assert(server || callbacks->recv_retry); assert(callbacks->rand); - assert(callbacks->get_new_connection_id); + assert(callbacks->get_new_connection_id2 || callbacks->get_new_connection_id); assert(callbacks->update_key); assert(callbacks->delete_crypto_aead_ctx); assert(callbacks->delete_crypto_cipher_ctx); - assert(callbacks->get_path_challenge_data); + assert(callbacks->get_path_challenge_data2 || + callbacks->get_path_challenge_data); assert(!server || !ngtcp2_is_reserved_version(client_chosen_version)); for (i = 0; i < settings->pmtud_probeslen; ++i) { @@ -1860,13 +1891,13 @@ static size_t pktns_select_pkt_numlen(ngtcp2_pktns *pktns) { n = n * 2 - 1; - if (n > 0xffffff) { + if (n > 0xFFFFFF) { return 4; } - if (n > 0xffff) { + if (n > 0xFFFF) { return 3; } - if (n > 0xff) { + if (n > 0xFF) { return 2; } return 1; @@ -1974,6 +2005,16 @@ static int conn_verify_dcid(ngtcp2_conn *conn, int *pnew_cid_used, return 0; } +static int conn_can_send_next_pkt(ngtcp2_conn *conn, size_t left, + uint64_t min_payloadlen) { + /* TODO the next packet type should be taken into account */ + return left >= + /* TODO Assuming that pkt_num is encoded in 1 byte. */ + NGTCP2_MIN_LONG_HEADERLEN + conn->dcid.current.cid.datalen + + conn->oscid.datalen + NGTCP2_PKT_LENGTHLEN - 1 + min_payloadlen + + NGTCP2_MAX_AEAD_OVERHEAD; +} + /* * conn_should_pad_pkt returns nonzero if the packet should be padded. * |type| is the type of packet. |left| is the space left in packet @@ -2020,32 +2061,30 @@ static int conn_should_pad_pkt(ngtcp2_conn *conn, uint8_t type, size_t left, return 1; } } - } else { - assert(type == NGTCP2_PKT_HANDSHAKE); - if (!require_padding) { - return 0; - } + return !conn_can_send_next_pkt(conn, left, min_payloadlen); + } - if (!conn->pktns.crypto.tx.ckm) { - return 1; - } + assert(type == NGTCP2_PKT_HANDSHAKE); - /* We might send Handshake packet even if exceeding CWND. In that - case, we do not write non-probe 1RTT packet. */ - if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) { - return 1; - } + if (!require_padding) { + /* If we have 1RTT key, pad this Handshake packet so that the next + 1RTT packet can be squeezed into the same GSO buffer. */ + return conn->pktns.crypto.tx.ckm && + !conn_can_send_next_pkt(conn, left, NGTCP2_MIN_COALESCED_PAYLOADLEN); + } + + if (!conn->pktns.crypto.tx.ckm) { + return 1; + } - min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN; + /* We might send Handshake packet even if exceeding CWND. In that + case, we do not write non-probe 1RTT packet. */ + if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) { + return 1; } - /* TODO the next packet type should be taken into account */ - return left < - /* TODO Assuming that pkt_num is encoded in 1 byte. */ - NGTCP2_MIN_LONG_HEADERLEN + conn->dcid.current.cid.datalen + - conn->oscid.datalen + NGTCP2_PKT_LENGTHLEN - 1 + min_payloadlen + - NGTCP2_MAX_AEAD_OVERHEAD; + return !conn_can_send_next_pkt(conn, left, NGTCP2_MIN_COALESCED_PAYLOADLEN); } static void conn_restart_timer_on_write(ngtcp2_conn *conn, ngtcp2_tstamp ts) { @@ -2888,7 +2927,7 @@ static void conn_discard_early_key(ngtcp2_conn *conn) { conn_call_delete_crypto_aead_ctx(conn, &conn->early.ckm->aead_ctx); conn_call_delete_crypto_cipher_ctx(conn, &conn->early.hp_ctx); - memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx)); + conn->early.hp_ctx = (ngtcp2_crypto_cipher_ctx){0}; ngtcp2_crypto_km_del(conn->early.ckm, conn->mem); conn->early.ckm = NULL; @@ -3205,58 +3244,59 @@ static size_t conn_required_num_new_connection_id(ngtcp2_conn *conn) { static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { size_t i, need = conn_required_num_new_connection_id(conn); size_t cidlen = conn->oscid.datalen; - ngtcp2_cid cid; - uint64_t seq; int rv; - uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN]; ngtcp2_frame_chain *nfrc; ngtcp2_pktns *pktns = &conn->pktns; ngtcp2_scid *scid; ngtcp2_ksl_it it; for (i = 0; i < need; ++i) { - rv = conn_call_get_new_connection_id(conn, &cid, token, cidlen); + rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); if (rv != 0) { return rv; } - if (cid.datalen != cidlen) { - return NGTCP2_ERR_CALLBACK_FAILURE; + nfrc->fr.new_connection_id.type = NGTCP2_FRAME_NEW_CONNECTION_ID; + nfrc->fr.new_connection_id.seq = ++conn->scid.last_seq; + nfrc->fr.new_connection_id.retire_prior_to = 0; + + rv = conn_call_get_new_connection_id(conn, &nfrc->fr.new_connection_id.cid, + &nfrc->fr.new_connection_id.token, + cidlen); + if (rv != 0) { + goto fail; + } + + if (nfrc->fr.new_connection_id.cid.datalen != cidlen) { + rv = NGTCP2_ERR_CALLBACK_FAILURE; + goto fail; } /* Assert uniqueness */ - it = ngtcp2_ksl_lower_bound(&conn->scid.set, &cid); + it = + ngtcp2_ksl_lower_bound(&conn->scid.set, &nfrc->fr.new_connection_id.cid); if (!ngtcp2_ksl_it_end(&it) && - ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it), &cid)) { - return NGTCP2_ERR_CALLBACK_FAILURE; + ngtcp2_cid_eq(ngtcp2_ksl_it_key(&it), + &nfrc->fr.new_connection_id.cid)) { + rv = NGTCP2_ERR_CALLBACK_FAILURE; + goto fail; } - seq = ++conn->scid.last_seq; - scid = ngtcp2_mem_malloc(conn->mem, sizeof(*scid)); if (scid == NULL) { - return NGTCP2_ERR_NOMEM; + rv = NGTCP2_ERR_NOMEM; + goto fail; } - ngtcp2_scid_init(scid, seq, &cid); + ngtcp2_scid_init(scid, nfrc->fr.new_connection_id.seq, + &nfrc->fr.new_connection_id.cid); rv = ngtcp2_ksl_insert(&conn->scid.set, NULL, &scid->cid, scid); if (rv != 0) { ngtcp2_mem_free(conn->mem, scid); - return rv; - } - - rv = ngtcp2_frame_chain_objalloc_new(&nfrc, &conn->frc_objalloc); - if (rv != 0) { - return rv; + goto fail; } - nfrc->fr.new_connection_id.type = NGTCP2_FRAME_NEW_CONNECTION_ID; - nfrc->fr.new_connection_id.seq = seq; - nfrc->fr.new_connection_id.retire_prior_to = 0; - nfrc->fr.new_connection_id.cid = cid; - memcpy(nfrc->fr.new_connection_id.stateless_reset_token, token, - sizeof(token)); nfrc->next = pktns->tx.frq; pktns->tx.frq = nfrc; @@ -3266,6 +3306,11 @@ static int conn_enqueue_new_connection_id(ngtcp2_conn *conn) { } return 0; + +fail: + ngtcp2_frame_chain_objalloc_del(nfrc, &conn->frc_objalloc, conn->mem); + + return rv; } static int dcidtr_on_deactivate(const ngtcp2_dcid *dcid, void *user_data) { @@ -3605,9 +3650,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, /* PATH_RESPONSE is bound to the path that the corresponding PATH_CHALLENGE is received. */ if (ngtcp2_path_eq(&conn->dcid.current.ps.path, &pcent->ps.path)) { - lfr.path_response.type = NGTCP2_FRAME_PATH_RESPONSE; - memcpy(lfr.path_response.data, pcent->data, - sizeof(lfr.path_response.data)); + lfr.path_response = (ngtcp2_path_response){ + .type = NGTCP2_FRAME_PATH_RESPONSE, + .data = pcent->data, + }; rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &lfr); if (rv != 0) { @@ -5121,7 +5167,7 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, return 0; } - rv = conn_call_get_path_challenge_data(conn, lfr.path_challenge.data); + rv = conn_call_get_path_challenge_data(conn, &lfr.path_challenge.data); if (rv != 0) { return rv; } @@ -5153,7 +5199,7 @@ static ngtcp2_ssize conn_write_path_challenge(ngtcp2_conn *conn, flags = NGTCP2_PV_ENTRY_FLAG_NONE; } - ngtcp2_pv_add_entry(pv, lfr.path_challenge.data, expiry, flags, ts); + ngtcp2_pv_add_entry(pv, &lfr.path_challenge.data, expiry, flags, ts); nwrite = ngtcp2_conn_write_single_frame_pkt( conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE, @@ -5259,8 +5305,10 @@ static ngtcp2_ssize conn_write_path_response(ngtcp2_conn *conn, } } - lfr.path_response.type = NGTCP2_FRAME_PATH_RESPONSE; - memcpy(lfr.path_response.data, pcent->data, sizeof(lfr.path_response.data)); + lfr.path_response = (ngtcp2_path_response){ + .type = NGTCP2_FRAME_PATH_RESPONSE, + .data = pcent->data, + }; nwrite = ngtcp2_conn_write_single_frame_pkt( conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE, @@ -5877,9 +5925,9 @@ decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, const ngtcp2_crypto_cipher *hp, } if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) { - dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0f)); + dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x0F)); } else { - dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1f)); + dest[0] = (uint8_t)(dest[0] ^ (mask[0] & 0x1F)); if (dest[0] & NGTCP2_SHORT_KEY_PHASE_BIT) { hd->flags |= NGTCP2_PKT_FLAG_KEY_PHASE; } @@ -5994,7 +6042,7 @@ static void conn_recv_path_challenge(ngtcp2_conn *conn, const ngtcp2_path *path, } ent = ngtcp2_ringbuf_push_front(&conn->rx.path_challenge.rb); - ngtcp2_path_challenge_entry_init(ent, path, fr->data); + ngtcp2_path_challenge_entry_init(ent, path, &fr->data); } /* @@ -6064,7 +6112,7 @@ static int conn_recv_path_response(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, return 0; } - rv = ngtcp2_pv_validate(pv, &ent_flags, fr->data); + rv = ngtcp2_pv_validate(pv, &ent_flags, &fr->data); if (rv != 0) { assert(!ngtcp2_err_is_fatal(rv)); @@ -6947,6 +6995,10 @@ static ngtcp2_ssize conn_recv_handshake_cpkt(ngtcp2_conn *conn, const uint8_t *origpkt = pkt; uint32_t version; + if (pktlen == 0) { + return 0; + } + if (ngtcp2_path_eq(&conn->dcid.current.ps.path, path)) { conn->dcid.current.bytes_recv += dgramlen; } @@ -7882,9 +7934,8 @@ static int conn_recv_stop_sending(ngtcp2_conn *conn, */ static int check_stateless_reset(const ngtcp2_dcid *dcid, const ngtcp2_path *path, - const ngtcp2_pkt_stateless_reset *sr) { - return ngtcp2_dcid_verify_stateless_reset_token( - dcid, path, sr->stateless_reset_token) == 0; + const ngtcp2_pkt_stateless_reset2 *sr) { + return ngtcp2_dcid_verify_stateless_reset_token(dcid, path, &sr->token) == 0; } /* @@ -7908,7 +7959,7 @@ static int conn_on_stateless_reset(ngtcp2_conn *conn, const ngtcp2_path *path, const uint8_t *payload, size_t payloadlen) { int rv; ngtcp2_pv *pv = conn->pv; - ngtcp2_pkt_stateless_reset sr; + ngtcp2_pkt_stateless_reset2 sr; rv = ngtcp2_pkt_decode_stateless_reset(&sr, payload, payloadlen); if (rv != 0) { @@ -7919,8 +7970,7 @@ static int conn_on_stateless_reset(ngtcp2_conn *conn, const ngtcp2_path *path, (!pv || (!check_stateless_reset(&pv->dcid, path, &sr) && (!(pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) || !check_stateless_reset(&pv->fallback_dcid, path, &sr))))) { - rv = ngtcp2_dcidtr_verify_stateless_reset(&conn->dcid.dtr, path, - sr.stateless_reset_token); + rv = ngtcp2_dcidtr_verify_stateless_reset(&conn->dcid.dtr, path, &sr.token); if (rv != 0) { return rv; } @@ -8000,7 +8050,7 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn, } rv = ngtcp2_dcid_verify_uniqueness(&conn->dcid.current, fr->seq, &fr->cid, - fr->stateless_reset_token); + &fr->token); if (rv != 0) { return rv; } @@ -8009,8 +8059,8 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn, } if (pv) { - rv = ngtcp2_dcid_verify_uniqueness(&pv->dcid, fr->seq, &fr->cid, - fr->stateless_reset_token); + rv = + ngtcp2_dcid_verify_uniqueness(&pv->dcid, fr->seq, &fr->cid, &fr->token); if (rv != 0) { return rv; } @@ -8019,8 +8069,8 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn, } } - rv = ngtcp2_dcidtr_verify_token_uniqueness( - &conn->dcid.dtr, &found, fr->seq, &fr->cid, fr->stateless_reset_token); + rv = ngtcp2_dcidtr_verify_token_uniqueness(&conn->dcid.dtr, &found, fr->seq, + &fr->cid, &fr->token); if (rv != 0) { return rv; } @@ -8098,8 +8148,7 @@ static int conn_recv_new_connection_id(ngtcp2_conn *conn, return 0; } - ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, fr->seq, &fr->cid, - fr->stateless_reset_token); + ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, fr->seq, &fr->cid, &fr->token); return 0; } @@ -10305,6 +10354,49 @@ int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, return conn_recv_cpkt(conn, path, pi, pkt, pktlen, ts); } +int ngtcp2_conn_continue_handshake(ngtcp2_conn *conn, ngtcp2_tstamp ts) { + int rv; + ngtcp2_encryption_level encryption_level; + uint64_t offset; + + conn_update_timestamp(conn, ts); + + switch (conn->state) { + case NGTCP2_CS_CLIENT_INITIAL: + case NGTCP2_CS_CLIENT_WAIT_HANDSHAKE: + case NGTCP2_CS_SERVER_INITIAL: + case NGTCP2_CS_SERVER_WAIT_HANDSHAKE: + /* Most of the handshake interruption happens in Initial + encryption level, but this might not be the case depending on + the TLS stack and its functionality and where interruption + occurs. After all, we do not need to support all kinds of + interruptions. */ + if (conn->in_pktns) { + encryption_level = NGTCP2_ENCRYPTION_LEVEL_INITIAL; + offset = ngtcp2_strm_rx_offset(&conn->in_pktns->crypto.strm); + } else if (conn->hs_pktns) { + encryption_level = NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE; + offset = ngtcp2_strm_rx_offset(&conn->hs_pktns->crypto.strm); + } else { + return 0; + } + + rv = conn_call_recv_crypto_data(conn, encryption_level, offset, NULL, 0); + if (rv != 0) { + return rv; + } + + return (int)conn_read_handshake(conn, /* path = */ NULL, /* pi = */ NULL, + /* pkt = */ NULL, 0, ts); + case NGTCP2_CS_CLOSING: + return NGTCP2_ERR_CLOSING; + case NGTCP2_CS_DRAINING: + return NGTCP2_ERR_DRAINING; + default: + return 0; + } +} + /* * conn_check_pkt_num_exhausted returns nonzero if packet number is * exhausted in at least one of packet number space. @@ -10406,6 +10498,7 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, size_t origlen = destlen; uint64_t pending_early_datalen; ngtcp2_preferred_addr *paddr; + ngtcp2_stateless_reset_token token; switch (conn->state) { case NGTCP2_CS_CLIENT_INITIAL: @@ -10533,8 +10626,8 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, assert(!ngtcp2_dcidtr_unused_full(&conn->dcid.dtr)); paddr = &conn->remote.transport_params->preferred_addr; - ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, 1, &paddr->cid, - paddr->stateless_reset_token); + memcpy(token.data, paddr->stateless_reset_token, sizeof(token.data)); + ngtcp2_dcidtr_push_unused(&conn->dcid.dtr, 1, &paddr->cid, &token); rv = ngtcp2_gaptr_push(&conn->dcid.seqgap, 1, 1); if (rv != 0) { @@ -10542,12 +10635,12 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, } } - if (conn->remote.transport_params->stateless_reset_token_present) { - assert(conn->dcid.current.seq == 0); + if (conn->remote.transport_params->stateless_reset_token_present && + conn->dcid.current.seq == 0) { assert(!(conn->dcid.current.flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT)); - ngtcp2_dcid_set_token( - &conn->dcid.current, - conn->remote.transport_params->stateless_reset_token); + memcpy(token.data, conn->remote.transport_params->stateless_reset_token, + sizeof(token.data)); + ngtcp2_dcid_set_token(&conn->dcid.current, &token); } rv = conn_call_activate_dcid(conn, &conn->dcid.current); @@ -10923,8 +11016,7 @@ int ngtcp2_conn_install_rx_handshake_key( if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; - - memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx)); + pktns->crypto.rx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0}; return rv; } @@ -10971,8 +11063,7 @@ int ngtcp2_conn_install_tx_handshake_key( to them. */ ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; - - memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx)); + pktns->crypto.tx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0}; return rv; } @@ -11005,8 +11096,7 @@ int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn, if (rv != 0) { ngtcp2_crypto_km_del(conn->early.ckm, conn->mem); conn->early.ckm = NULL; - - memset(&conn->early.hp_ctx, 0, sizeof(conn->early.hp_ctx)); + conn->early.hp_ctx = (ngtcp2_crypto_cipher_ctx){0}; return rv; } @@ -11053,8 +11143,7 @@ int ngtcp2_conn_install_rx_key(ngtcp2_conn *conn, const uint8_t *secret, if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem); pktns->crypto.rx.ckm = NULL; - - memset(&pktns->crypto.rx.hp_ctx, 0, sizeof(pktns->crypto.rx.hp_ctx)); + pktns->crypto.rx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0}; return rv; } @@ -11099,8 +11188,7 @@ int ngtcp2_conn_install_tx_key(ngtcp2_conn *conn, const uint8_t *secret, if (rv != 0) { ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem); pktns->crypto.tx.ckm = NULL; - - memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx)); + pktns->crypto.tx.hp_ctx = (ngtcp2_crypto_cipher_ctx){0}; return rv; } @@ -13485,20 +13573,46 @@ static size_t conn_get_num_active_dcid(ngtcp2_conn *conn) { return n; } -static void copy_dcid_to_cid_token(ngtcp2_cid_token *dest, +size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) { + ngtcp2_cid_token2 cid_tokens[/* current */ 1 + /* pv */ 2 + + NGTCP2_DCIDTR_MAX_RETIRED_DCID_SIZE]; + size_t n, i; + + if (!dest) { + return ngtcp2_conn_get_active_dcid2(conn, NULL); + } + + n = ngtcp2_conn_get_active_dcid2(conn, cid_tokens); + + for (i = 0; i < n; ++i) { + dest[i].seq = cid_tokens[i].seq; + dest[i].cid = cid_tokens[i].cid; + ngtcp2_path_storage_init2(&dest[i].ps, &cid_tokens[i].ps.path); + dest[i].token_present = cid_tokens[i].token_present; + + if (dest[i].token_present) { + memcpy(dest[i].token, cid_tokens[i].token.data, sizeof(dest[i].token)); + } + } + + return n; +} + +static void copy_dcid_to_cid_token(ngtcp2_cid_token2 *dest, const ngtcp2_dcid *src) { dest->seq = src->seq; dest->cid = src->cid; ngtcp2_path_storage_init2(&dest->ps, &src->ps.path); if ((dest->token_present = (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) != 0)) { - memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN); + dest->token = src->token; } } -size_t ngtcp2_conn_get_active_dcid(ngtcp2_conn *conn, ngtcp2_cid_token *dest) { +size_t ngtcp2_conn_get_active_dcid2(ngtcp2_conn *conn, + ngtcp2_cid_token2 *dest) { ngtcp2_pv *pv = conn->pv; - ngtcp2_cid_token *orig = dest; + ngtcp2_cid_token2 *orig = dest; ngtcp2_dcid *dcid; size_t len, i; @@ -14068,9 +14182,9 @@ ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path, void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, const ngtcp2_path *path, - const uint8_t *data) { + const ngtcp2_path_challenge_data *data) { ngtcp2_path_storage_init2(&pcent->ps, path); - memcpy(pcent->data, data, sizeof(pcent->data)); + pcent->data = *data; } /* The functions prefixed with ngtcp2_pkt_ are usually put inside diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h index a6f7616ee0c7d6..47175736d422c7 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h @@ -94,35 +94,35 @@ typedef enum { #define NGTCP2_CCERR_MAX_REASONLEN 1024 /* NGTCP2_WRITE_PKT_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_WRITE_PKT_FLAG_NONE 0x00u +#define NGTCP2_WRITE_PKT_FLAG_NONE 0x00U /* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING indicates that packet other than Initial packet should be padded so that UDP datagram payload is at least NGTCP2_MAX_UDP_PAYLOAD_SIZE bytes. Initial packet might be padded based on QUIC requirement regardless of this flag. */ -#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING 0x01u +#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING 0x01U /* NGTCP2_WRITE_PKT_FLAG_MORE indicates that more frames might come and it should be encoded into the current packet. */ -#define NGTCP2_WRITE_PKT_FLAG_MORE 0x02u +#define NGTCP2_WRITE_PKT_FLAG_MORE 0x02U /* NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL is just like NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING, but it requests to add padding to the full UDP datagram payload size. */ -#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04u +#define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04U /* NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY adds padding to the QUIC packet as much as possible if the packet is not empty. */ -#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08u +#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08U typedef struct ngtcp2_path_challenge_entry { ngtcp2_path_storage ps; - uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; + ngtcp2_path_challenge_data data; } ngtcp2_path_challenge_entry; void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, const ngtcp2_path *path, - const uint8_t *data); + const ngtcp2_path_challenge_data *data); /* NGTCP2_CONN_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_CONN_FLAG_NONE 0x00u +#define NGTCP2_CONN_FLAG_NONE 0x00U /* NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED is set when TLS stack declares that TLS handshake has completed. The condition of this declaration varies between TLS implementations and this flag does @@ -130,69 +130,69 @@ void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, implementations declare TLS handshake completion as server when they write off Server Finished and before deriving application rx secret. */ -#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01u +#define NGTCP2_CONN_FLAG_TLS_HANDSHAKE_COMPLETED 0x01U /* NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED is set when the first Initial packet has successfully been processed. */ -#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02u +#define NGTCP2_CONN_FLAG_INITIAL_PKT_PROCESSED 0x02U /* NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED is set if transport parameters are received. */ -#define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04u +#define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04U /* NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED is set when a local transport parameters are applied. */ -#define NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED 0x08u +#define NGTCP2_CONN_FLAG_LOCAL_TRANSPORT_PARAMS_COMMITTED 0x08U /* NGTCP2_CONN_FLAG_RECV_RETRY is set when a client receives Retry packet. */ -#define NGTCP2_CONN_FLAG_RECV_RETRY 0x10u +#define NGTCP2_CONN_FLAG_RECV_RETRY 0x10U /* NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED is set when 0-RTT packet is rejected by a peer. */ -#define NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED 0x20u +#define NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED 0x20U /* NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED is set when the expired keep-alive timer has been cancelled. */ -#define NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED 0x40u +#define NGTCP2_CONN_FLAG_KEEP_ALIVE_CANCELLED 0x40U /* NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED is set when an endpoint confirmed completion of handshake. */ -#define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80u +#define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80U /* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set when the library transitions its state to "post handshake". */ -#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100u +#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x0100U /* NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT is set when the early handshake retransmission has done when server receives overlapping Initial crypto data. */ -#define NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT 0x0200u +#define NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT 0x0200U /* NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT indicates that the local endpoint sends a QUIC packet without Fixed Bit set if a remote endpoint supports Greasing QUIC Bit extension. */ -#define NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT 0x0400u +#define NGTCP2_CONN_FLAG_CLEAR_FIXED_BIT 0x0400U /* NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED is set when key update is not confirmed by the local endpoint. That is, it has not received ACK frame which acknowledges packet which is encrypted with new key. */ -#define NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED 0x0800u +#define NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED 0x0800U /* NGTCP2_CONN_FLAG_PPE_PENDING is set when NGTCP2_WRITE_STREAM_FLAG_MORE is used and the intermediate state of ngtcp2_ppe is stored in pkt struct of ngtcp2_conn. */ -#define NGTCP2_CONN_FLAG_PPE_PENDING 0x1000u +#define NGTCP2_CONN_FLAG_PPE_PENDING 0x1000U /* NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE is set when idle timer should be restarted on next write. */ -#define NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE 0x2000u +#define NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE 0x2000U /* NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED indicates that server as peer verified client address. This flag is only used by client. */ -#define NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED 0x4000u +#define NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED 0x4000U /* NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED indicates that an early key is installed. conn->early.ckm cannot be used for this purpose because it might be discarded when a certain condition is met. */ -#define NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED 0x8000u +#define NGTCP2_CONN_FLAG_EARLY_KEY_INSTALLED 0x8000U /* NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR is set when the local endpoint has initiated key update. */ -#define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000u +#define NGTCP2_CONN_FLAG_KEY_UPDATE_INITIATOR 0x10000U /* NGTCP2_CONN_FLAG_AGGREGATE_PKTS is set when ngtcp2_conn_writev_stream is called inside the callback invoked by ngtcp2_conn_write_aggregate_pkt. */ -#define NGTCP2_CONN_FLAG_AGGREGATE_PKTS 0x20000u +#define NGTCP2_CONN_FLAG_AGGREGATE_PKTS 0x20000U /* NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO, if set, crumbles an Initial CRYPTO frame into pieces as a countermeasure against Deep Packet Inspection. */ -#define NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO 0x40000u +#define NGTCP2_CONN_FLAG_CRUMBLE_INITIAL_CRYPTO 0x40000U typedef struct ngtcp2_pktns { struct { @@ -943,7 +943,7 @@ ngtcp2_conn_server_negotiate_version(ngtcp2_conn *conn, * @function * * `ngtcp2_conn_write_connection_close_pkt` writes a packet which - * contains a CONNECTION_CLOSE frame (type 0x1c) in the buffer pointed + * contains a CONNECTION_CLOSE frame (type 0x1C) in the buffer pointed * by |dest| whose capacity is |datalen|. * * If |path| is not ``NULL``, this function stores the network path @@ -985,7 +985,7 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt( * @function * * `ngtcp2_conn_write_application_close_pkt` writes a packet which - * contains a CONNECTION_CLOSE frame (type 0x1d) in the buffer pointed + * contains a CONNECTION_CLOSE frame (type 0x1D) in the buffer pointed * by |dest| whose capacity is |datalen|. * * If |path| is not ``NULL``, this function stores the network path @@ -998,7 +998,7 @@ ngtcp2_ssize ngtcp2_conn_write_connection_close_pkt( * if it succeeds. The metadata includes ECN markings. * * If handshake has not been confirmed yet, CONNECTION_CLOSE (type - * 0x1c) with error code :macro:`NGTCP2_APPLICATION_ERROR` is written + * 0x1C) with error code :macro:`NGTCP2_APPLICATION_ERROR` is written * instead. * * This function must not be called from inside the callback diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c index 7b2e02e5b10f5d..a0cef0c8643a6e 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c @@ -74,21 +74,21 @@ static const uint8_t *get_uvarint(uint64_t *dest, const uint8_t *p) { case 1: memcpy(&n16, p, 2); n16 = ngtcp2_ntohs(n16); - n16 &= 0x3fff; + n16 &= 0x3FFF; *dest = n16; return p + 2; case 2: memcpy(&n32, p, 4); n32 = ngtcp2_ntohl(n32); - n32 &= 0x3fffffff; + n32 &= 0x3FFFFFFF; *dest = n32; return p + 4; case 3: memcpy(&n64, p, 8); n64 = ngtcp2_ntohl64(n64); - n64 &= 0x3fffffffffffffff; + n64 &= 0x3FFFFFFFFFFFFFFF; *dest = n64; return p + 8; @@ -168,7 +168,7 @@ uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n) { } assert(n < 4611686018427387904ULL); rv = ngtcp2_put_uint64be(p, n); - *p |= 0xc0; + *p |= 0xC0; return rv; } @@ -200,7 +200,7 @@ uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len) { } size_t ngtcp2_get_uvarintlen(const uint8_t *p) { - return (size_t)(1u << (*p >> 6)); + return (size_t)(1U << (*p >> 6)); } size_t ngtcp2_put_uvarintlen(uint64_t n) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h index ca6d494846f324..c1e786b5fc7b36 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h @@ -42,10 +42,10 @@ #define NGTCP2_MAX_AEAD_OVERHEAD 16 /* NGTCP2_CRYPTO_KM_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00u +#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00U /* NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE is set if key phase bit is set. */ -#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01u +#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01U typedef struct ngtcp2_crypto_km { ngtcp2_vec secret; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c index 170b9f803cccec..a312398bbfaf97 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c @@ -157,9 +157,9 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest, return 0; } -int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr, - const ngtcp2_path *path, - const uint8_t *token) { +int ngtcp2_dcidtr_verify_stateless_reset( + const ngtcp2_dcidtr *dtr, const ngtcp2_path *path, + const ngtcp2_stateless_reset_token *token) { const ngtcp2_dcid *dcid; const ngtcp2_ringbuf *rb = &dtr->bound.rb; size_t i, len = ngtcp2_ringbuf_len(rb); @@ -176,7 +176,7 @@ int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr, static int verify_token_uniqueness(const ngtcp2_ringbuf *rb, int *pfound, uint64_t seq, const ngtcp2_cid *cid, - const uint8_t *token) { + const ngtcp2_stateless_reset_token *token) { const ngtcp2_dcid *dcid; size_t i, len = ngtcp2_ringbuf_len(rb); int rv; @@ -196,9 +196,9 @@ static int verify_token_uniqueness(const ngtcp2_ringbuf *rb, int *pfound, return 0; } -int ngtcp2_dcidtr_verify_token_uniqueness(const ngtcp2_dcidtr *dtr, int *pfound, - uint64_t seq, const ngtcp2_cid *cid, - const uint8_t *token) { +int ngtcp2_dcidtr_verify_token_uniqueness( + const ngtcp2_dcidtr *dtr, int *pfound, uint64_t seq, const ngtcp2_cid *cid, + const ngtcp2_stateless_reset_token *token) { int rv; rv = verify_token_uniqueness(&dtr->bound.rb, pfound, seq, cid, token); @@ -406,7 +406,8 @@ ngtcp2_tstamp ngtcp2_dcidtr_earliest_retired_ts(const ngtcp2_dcidtr *dtr) { } void ngtcp2_dcidtr_push_unused(ngtcp2_dcidtr *dtr, uint64_t seq, - const ngtcp2_cid *cid, const uint8_t *token) { + const ngtcp2_cid *cid, + const ngtcp2_stateless_reset_token *token) { ngtcp2_dcid *dcid = ngtcp2_ringbuf_push_back(&dtr->unused.rb); ngtcp2_dcid_init(dcid, seq, cid, token); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h index 63043427bc0900..945ed12bae145f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h @@ -154,9 +154,9 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest, * There is no Destination Connection ID that matches the given * |path| and |token|. */ -int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr, - const ngtcp2_path *path, - const uint8_t *token); +int ngtcp2_dcidtr_verify_stateless_reset( + const ngtcp2_dcidtr *dtr, const ngtcp2_path *path, + const ngtcp2_stateless_reset_token *token); /* * ngtcp2_dcidtr_verify_token_uniqueness verifies that the uniqueness @@ -180,9 +180,9 @@ int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr, * The given combination of values does not satisfy the above * conditions. */ -int ngtcp2_dcidtr_verify_token_uniqueness(const ngtcp2_dcidtr *dtr, int *pfound, - uint64_t seq, const ngtcp2_cid *cid, - const uint8_t *token); +int ngtcp2_dcidtr_verify_token_uniqueness( + const ngtcp2_dcidtr *dtr, int *pfound, uint64_t seq, const ngtcp2_cid *cid, + const ngtcp2_stateless_reset_token *token); /* * ngtcp2_dcidtr_retire_inactive_dcid_prior_to retires inactive @@ -273,7 +273,8 @@ ngtcp2_tstamp ngtcp2_dcidtr_earliest_retired_ts(const ngtcp2_dcidtr *dtr); * buffer space is full, the earliest ngtcp2_dcid is removed. */ void ngtcp2_dcidtr_push_unused(ngtcp2_dcidtr *dtr, uint64_t seq, - const ngtcp2_cid *cid, const uint8_t *token); + const ngtcp2_cid *cid, + const ngtcp2_stateless_reset_token *token); /* * ngtcp2_dcidtr_pop_unused_cid_token removes an unused Destination diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h index 5342b9fa7b1692..c73100dbcbaa4f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_frame_chain.h @@ -36,10 +36,10 @@ /* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u +#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00U /* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information which a frame carries has been acknowledged. */ -#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u +#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01U /* * ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c index be3c9e182b5d06..80000f42f9b834 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c @@ -55,12 +55,12 @@ void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, assert(keylen >= sizeof(uint64_t)); - aligned_keylen = (keylen + 0x7u) & ~0x7u; + aligned_keylen = (keylen + 0x7U) & ~0x7U; assert(aligned_keylen <= UINT16_MAX); ngtcp2_objalloc_init(&ksl->blkalloc, - (ksl_blklen(aligned_keylen) + 0xfu) & ~(uintptr_t)0xfu, + (ksl_blklen(aligned_keylen) + 0xFU) & ~(uintptr_t)0xFU, mem); ksl->root = NULL; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c index 39fd6969a5e3f6..191c64430b5b28 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c @@ -47,7 +47,7 @@ void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid, log->scid[0] = '\0'; } log->log_printf = log_printf; - log->events = 0xff; + log->events = 0xFF; log->ts = log->last_ts = ts; log->user_data = user_data; } @@ -134,7 +134,7 @@ static const char *strerrorcode(uint64_t error_code) { case NGTCP2_VERSION_NEGOTIATION_ERROR: return "VERSION_NEGOTIATION_ERROR"; default: - if (0x100u <= error_code && error_code <= 0x1ffu) { + if (0x100U <= error_code && error_code <= 0x1FFU) { return "CRYPTO_ERROR"; } return "(unknown)"; @@ -328,7 +328,7 @@ static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_new_connection_id *fr, const char *dir) { - char buf[sizeof(fr->stateless_reset_token) * 2 + 1]; + char buf[sizeof(fr->token.data) * 2 + 1]; char cid[sizeof(fr->cid.data) * 2 + 1]; ngtcp2_log_infof_raw( @@ -339,8 +339,7 @@ static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq, ngtcp2_encode_hex_cstr(cid, fr->cid.data, fr->cid.datalen), fr->retire_prior_to, - ngtcp2_encode_hex_cstr(buf, fr->stateless_reset_token, - sizeof(fr->stateless_reset_token))); + ngtcp2_encode_hex_cstr(buf, fr->token.data, sizeof(fr->token.data))); } static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -357,25 +356,25 @@ static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, static void log_fr_path_challenge(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_path_challenge *fr, const char *dir) { - char buf[sizeof(fr->data) * 2 + 1]; + char buf[sizeof(fr->data.data) * 2 + 1]; - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 - ") data=0x%s", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, - ngtcp2_encode_hex_cstr(buf, fr->data, sizeof(fr->data))); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_FRM, + NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s", + NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, + ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data))); } static void log_fr_path_response(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const ngtcp2_path_response *fr, const char *dir) { - char buf[sizeof(fr->data) * 2 + 1]; + char buf[sizeof(fr->data.data) * 2 + 1]; - ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM, - NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 - ") data=0x%s", - NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, - ngtcp2_encode_hex_cstr(buf, fr->data, sizeof(fr->data))); + ngtcp2_log_infof_raw( + log, NGTCP2_LOG_EVENT_FRM, + NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s", + NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, + ngtcp2_encode_hex_cstr(buf, fr->data.data, sizeof(fr->data.data))); } static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, @@ -542,8 +541,8 @@ void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, } } -void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) { - char buf[sizeof(sr->stateless_reset_token) * 2 + 1]; +void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset2 *sr) { + char buf[sizeof(sr->token.data) * 2 + 1]; ngtcp2_pkt_hd shd; ngtcp2_pkt_hd *hd = &shd; @@ -558,14 +557,13 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) { ngtcp2_log_infof_raw( log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " token=0x%s randlen=%zu", NGTCP2_LOG_PKT_HD_FIELDS("rx"), - ngtcp2_encode_hex_cstr(buf, sr->stateless_reset_token, - sizeof(sr->stateless_reset_token)), + ngtcp2_encode_hex_cstr(buf, sr->token.data, sizeof(sr->token.data)), sr->randlen); } void ngtcp2_log_remote_tp(ngtcp2_log *log, const ngtcp2_transport_params *params) { - char token[NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1]; + char token[sizeof(params->stateless_reset_token) * 2 + 1]; char addr[16 * 2 + 7 + 1]; char cid[NGTCP2_MAX_CIDLEN * 2 + 1]; size_t i; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h index 02726bc19ded6f..b8bccb9d09ebca 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h @@ -107,7 +107,7 @@ void ngtcp2_log_tx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd, const uint32_t *sv, size_t nsv); -void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr); +void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset2 *sr); void ngtcp2_log_remote_tp(ngtcp2_log *log, const ngtcp2_transport_params *params); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c index 6b332f6b58dbd8..3ad4b9f1ef0591 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c @@ -77,10 +77,10 @@ int ngtcp2_map_each(const ngtcp2_map *map, int (*func)(void *data, void *ptr), /* Hasher from https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs to maximize the output's sensitivity to all input bits. */ -#define NGTCP2_MAP_HASHER 0xf1357aea2e62a9c5ull +#define NGTCP2_MAP_HASHER 0xF1357AEA2E62A9C5ULL /* 64-bit Fibonacci hashing constant, Golden Ratio constant, to get the high bits with the good distribution. */ -#define NGTCP2_MAP_FIBO 0x9e3779b97f4a7c15ull +#define NGTCP2_MAP_FIBO 0x9E3779B97F4A7C15ULL static size_t map_index(const ngtcp2_map *map, ngtcp2_map_key_type key) { key += map->seed; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h index 103a2fb2d80714..35a807f9fed29f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_net.h @@ -97,9 +97,9 @@ STIN uint32_t ngtcp2_htonl(uint32_t hostlong) { uint32_t res; unsigned char *p = (unsigned char *)&res; *p++ = (unsigned char)(hostlong >> 24); - *p++ = (hostlong >> 16) & 0xffu; - *p++ = (hostlong >> 8) & 0xffu; - *p = hostlong & 0xffu; + *p++ = (hostlong >> 16) & 0xFFU; + *p++ = (hostlong >> 8) & 0xFFU; + *p = hostlong & 0xFFU; return res; } @@ -107,7 +107,7 @@ STIN uint16_t ngtcp2_htons(uint16_t hostshort) { uint16_t res; unsigned char *p = (unsigned char *)&res; *p++ = (unsigned char)(hostshort >> 8); - *p = hostshort & 0xffu; + *p = hostshort & 0xFFU; return res; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h index cf23de7b2b7f20..4b6df53857a5b8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_objalloc.h @@ -69,7 +69,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); inline static void ngtcp2_objalloc_##NAME##_init( \ ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \ ngtcp2_objalloc_init( \ - objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \ + objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem); \ } \ \ TYPE *ngtcp2_objalloc_##NAME##_get(ngtcp2_objalloc *objalloc); \ @@ -123,7 +123,7 @@ void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc); inline static void ngtcp2_objalloc_##NAME##_init( \ ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \ ngtcp2_objalloc_init( \ - objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \ + objalloc, ((sizeof(TYPE) + 0xFU) & ~(uintptr_t)0xFU) * nmemb, mem); \ } \ \ inline static TYPE *ngtcp2_objalloc_##NAME##_get( \ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pcg.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pcg.c index c8490467e43614..ddaf94a779ab36 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pcg.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pcg.c @@ -70,8 +70,8 @@ static uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) { } static uint32_t pcg_output_xsh_rr_64_32(uint64_t state) { - return pcg_rotr_32((uint32_t)(((state >> 18u) ^ state) >> 27u), - (unsigned int)(state >> 59u)); + return pcg_rotr_32((uint32_t)(((state >> 18U) ^ state) >> 27U), + (unsigned int)(state >> 59U)); } uint32_t ngtcp2_pcg32_rand(ngtcp2_pcg32 *pcg) { diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c index a63913f8af797a..f86e65118df7d8 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c @@ -565,7 +565,7 @@ ngtcp2_ssize ngtcp2_frame_decoder_decode(ngtcp2_frame_decoder *frd, return ngtcp2_pkt_decode_stream_frame(&dest->stream, payload, payloadlen); } - /* For frame types > 0xff, use ngtcp2_get_uvarintlen and + /* For frame types > 0xFF, use ngtcp2_get_uvarintlen and ngtcp2_get_uvarint to get a frame type, and then switch over it. Verify that payloadlen >= ngtcp2_get_uvarintlen(payload) before calling ngtcp2_get_uvarint(payload). */ @@ -1208,8 +1208,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_new_connection_id_frame( ++p; ngtcp2_cid_init(&dest->cid, p, cil); p += cil; - p = ngtcp2_get_bytes(dest->stateless_reset_token, p, - NGTCP2_STATELESS_RESET_TOKENLEN); + p = ngtcp2_get_bytes(dest->token.data, p, sizeof(dest->token.data)); assert((size_t)(p - payload) == len); @@ -1268,7 +1267,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_challenge_frame(ngtcp2_path_challenge *dest, p = payload + 1; dest->type = NGTCP2_FRAME_PATH_CHALLENGE; - ngtcp2_cpymem(dest->data, p, sizeof(dest->data)); + ngtcp2_cpymem(dest->data.data, p, sizeof(dest->data.data)); p += sizeof(dest->data); assert((size_t)(p - payload) == len); @@ -1289,7 +1288,7 @@ ngtcp2_ssize ngtcp2_pkt_decode_path_response_frame(ngtcp2_path_response *dest, p = payload + 1; dest->type = NGTCP2_FRAME_PATH_RESPONSE; - ngtcp2_cpymem(dest->data, p, sizeof(dest->data)); + ngtcp2_cpymem(dest->data.data, p, sizeof(dest->data.data)); p += sizeof(dest->data); assert((size_t)(p - payload) == len); @@ -1883,7 +1882,7 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, const ngtcp2_new_connection_id *fr) { size_t len = 1 + ngtcp2_put_uvarintlen(fr->seq) + ngtcp2_put_uvarintlen(fr->retire_prior_to) + 1 + - fr->cid.datalen + NGTCP2_STATELESS_RESET_TOKENLEN; + fr->cid.datalen + sizeof(fr->token.data); uint8_t *p; if (outlen < len) { @@ -1897,8 +1896,7 @@ ngtcp2_pkt_encode_new_connection_id_frame(uint8_t *out, size_t outlen, p = ngtcp2_put_uvarint(p, fr->retire_prior_to); *p++ = (uint8_t)fr->cid.datalen; p = ngtcp2_cpymem(p, fr->cid.data, fr->cid.datalen); - p = ngtcp2_cpymem(p, fr->stateless_reset_token, - NGTCP2_STATELESS_RESET_TOKENLEN); + p = ngtcp2_cpymem(p, fr->token.data, sizeof(fr->token.data)); assert((size_t)(p - out) == len); @@ -1940,7 +1938,7 @@ ngtcp2_pkt_encode_path_challenge_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_PATH_CHALLENGE; - p = ngtcp2_cpymem(p, fr->data, sizeof(fr->data)); + p = ngtcp2_cpymem(p, fr->data.data, sizeof(fr->data.data)); assert((size_t)(p - out) == len); @@ -1960,7 +1958,7 @@ ngtcp2_pkt_encode_path_response_frame(uint8_t *out, size_t outlen, p = out; *p++ = NGTCP2_FRAME_PATH_RESPONSE; - p = ngtcp2_cpymem(p, fr->data, sizeof(fr->data)); + p = ngtcp2_cpymem(p, fr->data.data, sizeof(fr->data.data)); assert((size_t)(p - out) == len); @@ -2116,7 +2114,7 @@ ngtcp2_ssize ngtcp2_pkt_write_version_negotiation( p = dest; - *p++ = 0xc0 | unused_random; + *p++ = 0xC0 | unused_random; p = ngtcp2_put_uint32be(p, 0); *p++ = (uint8_t)dcidlen; @@ -2153,20 +2151,20 @@ size_t ngtcp2_pkt_decode_version_negotiation(uint32_t *dest, return payloadlen / sizeof(uint32_t); } -int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset *sr, +int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset2 *sr, const uint8_t *payload, size_t payloadlen) { const uint8_t *p = payload; if (payloadlen < - NGTCP2_MIN_STATELESS_RESET_RANDLEN + NGTCP2_STATELESS_RESET_TOKENLEN) { + NGTCP2_MIN_STATELESS_RESET_RANDLEN + sizeof(sr->token.data)) { return NGTCP2_ERR_INVALID_ARGUMENT; } sr->rand = p; - sr->randlen = payloadlen - NGTCP2_STATELESS_RESET_TOKENLEN; + sr->randlen = payloadlen - sizeof(sr->token.data); p += sr->randlen; - memcpy(sr->stateless_reset_token, p, NGTCP2_STATELESS_RESET_TOKENLEN); + memcpy(sr->token.data, p, sizeof(sr->token.data)); return 0; } @@ -2245,10 +2243,21 @@ ngtcp2_ssize ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen, const uint8_t *stateless_reset_token, const uint8_t *rand, size_t randlen) { + ngtcp2_stateless_reset_token token; + + memcpy(token.data, stateless_reset_token, sizeof(token.data)); + + return ngtcp2_pkt_write_stateless_reset2(dest, destlen, &token, rand, + randlen); +} + +ngtcp2_ssize +ngtcp2_pkt_write_stateless_reset2(uint8_t *dest, size_t destlen, + const ngtcp2_stateless_reset_token *token, + const uint8_t *rand, size_t randlen) { uint8_t *p; - if (destlen < - NGTCP2_MIN_STATELESS_RESET_RANDLEN + NGTCP2_STATELESS_RESET_TOKENLEN) { + if (destlen < NGTCP2_MIN_STATELESS_RESET_RANDLEN + sizeof(token->data)) { return NGTCP2_ERR_NOBUF; } @@ -2258,11 +2267,11 @@ ngtcp2_pkt_write_stateless_reset(uint8_t *dest, size_t destlen, p = dest; - randlen = ngtcp2_min_size(destlen - NGTCP2_STATELESS_RESET_TOKENLEN, randlen); + randlen = ngtcp2_min_size(destlen - sizeof(token->data), randlen); p = ngtcp2_cpymem(p, rand, randlen); - p = ngtcp2_cpymem(p, stateless_reset_token, NGTCP2_STATELESS_RESET_TOKENLEN); - *dest = (uint8_t)((*dest & 0x7fu) | 0x40u); + p = ngtcp2_cpymem(p, token->data, sizeof(token->data)); + *dest = (uint8_t)((*dest & 0x3FU) | 0x40U); return p - dest; } @@ -2356,7 +2365,7 @@ ngtcp2_ssize ngtcp2_pkt_encode_pseudo_retry( return NGTCP2_ERR_NOBUF; } - *p &= 0xf0; + *p &= 0xF0; *p |= unused; p += nwrite; @@ -2430,7 +2439,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, left -= n; if (left > 8 + 1073741823 && len > 1073741823) { - len = ngtcp2_min_uint64(len, 4611686018427387903lu); + len = ngtcp2_min_uint64(len, 4611686018427387903UL); return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 8)); } @@ -2461,7 +2470,7 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { if (left > 8 + 1073741823 && len > 1073741823) { #if SIZE_MAX == UINT64_MAX - len = ngtcp2_min_size(len, 4611686018427387903lu); + len = ngtcp2_min_size(len, 4611686018427387903UL); #endif /* SIZE_MAX == UINT64_MAX */ return ngtcp2_min_size(len, left - 8); } @@ -2869,3 +2878,8 @@ size_t ngtcp2_pkt_remove_vec_partial(ngtcp2_vec *removed_data, ngtcp2_vec *data, return datacnt + 1; } + +int ngtcp2_stateless_reset_token_eq(const ngtcp2_stateless_reset_token *a, + const ngtcp2_stateless_reset_token *b) { + return memcmp(a->data, b->data, sizeof(a->data)) == 0; +} diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h index abf13693b916e7..bfdb065b74ca91 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.h @@ -38,14 +38,14 @@ /* Long header specific macros */ #define NGTCP2_LONG_TYPE_MASK 0x30 -#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0c +#define NGTCP2_LONG_RESERVED_BIT_MASK 0x0C /* Short header specific macros */ #define NGTCP2_SHORT_RESERVED_BIT_MASK 0x18 #define NGTCP2_SHORT_KEY_PHASE_BIT 0x04 /* NGTCP2_SR_TYPE is a Type field of Stateless Reset. */ -#define NGTCP2_SR_TYPE 0x1f +#define NGTCP2_SR_TYPE 0x1F /* NGTCP2_MIN_LONG_HEADERLEN is the minimum length of long header. That is (1|1|TT|RR|PP)<1> + VERSION<4> + DCIL<1> + SCIL<1> + @@ -78,23 +78,23 @@ /* NGTCP2_MAX_SERVER_STREAM_ID_BIDI is the maximum bidirectional server stream ID. */ -#define NGTCP2_MAX_SERVER_STREAM_ID_BIDI ((int64_t)0x3ffffffffffffffdll) +#define NGTCP2_MAX_SERVER_STREAM_ID_BIDI ((int64_t)0x3FFFFFFFFFFFFFFDLL) /* NGTCP2_MAX_CLIENT_STREAM_ID_BIDI is the maximum bidirectional client stream ID. */ -#define NGTCP2_MAX_CLIENT_STREAM_ID_BIDI ((int64_t)0x3ffffffffffffffcll) +#define NGTCP2_MAX_CLIENT_STREAM_ID_BIDI ((int64_t)0x3FFFFFFFFFFFFFFCLL) /* NGTCP2_MAX_SERVER_STREAM_ID_UNI is the maximum unidirectional server stream ID. */ -#define NGTCP2_MAX_SERVER_STREAM_ID_UNI ((int64_t)0x3fffffffffffffffll) +#define NGTCP2_MAX_SERVER_STREAM_ID_UNI ((int64_t)0x3FFFFFFFFFFFFFFFLL) /* NGTCP2_MAX_CLIENT_STREAM_ID_UNI is the maximum unidirectional client stream ID. */ -#define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3ffffffffffffffell) +#define NGTCP2_MAX_CLIENT_STREAM_ID_UNI ((int64_t)0x3FFFFFFFFFFFFFFELL) /* NGTCP2_MAX_NUM_ACK_RANGES is the maximum number of Additional ACK ranges which this library can create, or decode. */ #define NGTCP2_MAX_ACK_RANGES 32 /* NGTCP2_MAX_PKT_NUM is the maximum packet number. */ -#define NGTCP2_MAX_PKT_NUM ((int64_t)((1ll << 62) - 1)) +#define NGTCP2_MAX_PKT_NUM ((int64_t)((1LL << 62) - 1)) /* NGTCP2_MIN_PKT_EXPANDLEN is the minimum packet size expansion to hide/trigger Stateless Reset. */ @@ -172,11 +172,11 @@ typedef struct ngtcp2_pkt_retry { #define NGTCP2_FRAME_STREAMS_BLOCKED_UNI 0x17 #define NGTCP2_FRAME_NEW_CONNECTION_ID 0x18 #define NGTCP2_FRAME_RETIRE_CONNECTION_ID 0x19 -#define NGTCP2_FRAME_PATH_CHALLENGE 0x1a -#define NGTCP2_FRAME_PATH_RESPONSE 0x1b -#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1c -#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1d -#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1e +#define NGTCP2_FRAME_PATH_CHALLENGE 0x1A +#define NGTCP2_FRAME_PATH_RESPONSE 0x1B +#define NGTCP2_FRAME_CONNECTION_CLOSE 0x1C +#define NGTCP2_FRAME_CONNECTION_CLOSE_APP 0x1D +#define NGTCP2_FRAME_HANDSHAKE_DONE 0x1E #define NGTCP2_FRAME_DATAGRAM 0x30 #define NGTCP2_FRAME_DATAGRAM_LEN 0x31 @@ -300,7 +300,7 @@ typedef struct ngtcp2_new_connection_id { uint64_t seq; uint64_t retire_prior_to; ngtcp2_cid cid; - uint8_t stateless_reset_token[NGTCP2_STATELESS_RESET_TOKENLEN]; + ngtcp2_stateless_reset_token token; } ngtcp2_new_connection_id; typedef struct ngtcp2_stop_sending { @@ -311,12 +311,12 @@ typedef struct ngtcp2_stop_sending { typedef struct ngtcp2_path_challenge { uint64_t type; - uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; + ngtcp2_path_challenge_data data; } ngtcp2_path_challenge; typedef struct ngtcp2_path_response { uint64_t type; - uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; + ngtcp2_path_challenge_data data; } ngtcp2_path_response; typedef struct ngtcp2_new_token { @@ -514,7 +514,7 @@ size_t ngtcp2_pkt_decode_version_negotiation(uint32_t *dest, * NGTCP2_ERR_INVALID_ARGUMENT * Payloadlen is too short. */ -int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset *sr, +int ngtcp2_pkt_decode_stateless_reset(ngtcp2_pkt_stateless_reset2 *sr, const uint8_t *payload, size_t payloadlen); @@ -1323,4 +1323,11 @@ size_t ngtcp2_pkt_remove_vec_partial(ngtcp2_vec *removed_data, ngtcp2_vec *data, size_t datacnt, uint64_t *offsets, ngtcp2_pcg32 *pcg, const ngtcp2_vec *part); +/* + * ngtcp2_stateless_reset_token_eq returns nonzero if |a| and |b| + * share the same token. + */ +int ngtcp2_stateless_reset_token_eq(const ngtcp2_stateless_reset_token *a, + const ngtcp2_stateless_reset_token *b); + #endif /* !defined(NGTCP2_PKT_H) */ diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c index 4d193125ae8e89..3054732db047e6 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_ppe.c @@ -154,9 +154,9 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { p = buf->begin; if (*p & NGTCP2_HEADER_FORM_BIT) { - *p = (uint8_t)(*p ^ (mask[0] & 0x0f)); + *p = (uint8_t)(*p ^ (mask[0] & 0x0F)); } else { - *p = (uint8_t)(*p ^ (mask[0] & 0x1f)); + *p = (uint8_t)(*p ^ (mask[0] & 0x1F)); } p = buf->begin + ppe->pkt_num_offset; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c index 471f84c76440fe..972c27f395a28d 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.c @@ -31,12 +31,16 @@ #include "ngtcp2_log.h" #include "ngtcp2_macro.h" #include "ngtcp2_addr.h" +#include "ngtcp2_str.h" -void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data, +void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, + const ngtcp2_path_challenge_data *data, ngtcp2_tstamp expiry, uint8_t flags) { - memcpy(pvent->data, data, sizeof(pvent->data)); - pvent->expiry = expiry; - pvent->flags = flags; + *pvent = (ngtcp2_pv_entry){ + .expiry = expiry, + .flags = flags, + .data = *data, + }; } int ngtcp2_pv_new(ngtcp2_pv **ppv, const ngtcp2_dcid *dcid, @@ -70,7 +74,7 @@ void ngtcp2_pv_del(ngtcp2_pv *pv) { ngtcp2_mem_free(pv->mem, pv); } -void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data, +void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const ngtcp2_path_challenge_data *data, ngtcp2_tstamp expiry, uint8_t flags, ngtcp2_tstamp ts) { ngtcp2_pv_entry *ent; @@ -88,7 +92,8 @@ void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data, --pv->probe_pkt_left; } -int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data) { +int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, + const ngtcp2_path_challenge_data *data) { size_t len = ngtcp2_ringbuf_len(&pv->ents.rb); size_t i; ngtcp2_pv_entry *ent; @@ -99,7 +104,7 @@ int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data) { for (i = 0; i < len; ++i) { ent = ngtcp2_ringbuf_get(&pv->ents.rb, i); - if (memcmp(ent->data, data, sizeof(ent->data)) == 0) { + if (ngtcp2_cmemeq(ent->data.data, data->data, sizeof(ent->data.data))) { *pflags = ent->flags; ngtcp2_log_info(pv->log, NGTCP2_LOG_EVENT_PTV, "path has been validated"); return 0; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h index b62ab204b216a5..28bdf722b2047f 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_pv.h @@ -46,10 +46,10 @@ typedef struct ngtcp2_log ngtcp2_log; typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; /* NGTCP2_PV_ENTRY_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_PV_ENTRY_FLAG_NONE 0x00u +#define NGTCP2_PV_ENTRY_FLAG_NONE 0x00U /* NGTCP2_PV_ENTRY_FLAG_UNDERSIZED indicates that UDP datagram which contains PATH_CHALLENGE is undersized (< 1200 bytes) */ -#define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01u +#define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01U typedef struct ngtcp2_pv_entry { /* expiry is the timestamp when this PATH_CHALLENGE expires. */ @@ -57,30 +57,31 @@ typedef struct ngtcp2_pv_entry { /* flags is zero or more of NGTCP2_PV_ENTRY_FLAG_*. */ uint8_t flags; /* data is a byte string included in PATH_CHALLENGE. */ - uint8_t data[NGTCP2_PATH_CHALLENGE_DATALEN]; + ngtcp2_path_challenge_data data; } ngtcp2_pv_entry; -void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data, +void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, + const ngtcp2_path_challenge_data *data, ngtcp2_tstamp expiry, uint8_t flags); /* NGTCP2_PV_FLAG_NONE indicates no flag is set. */ -#define NGTCP2_PV_FLAG_NONE 0x00u +#define NGTCP2_PV_FLAG_NONE 0x00U /* NGTCP2_PV_FLAG_DONT_CARE indicates that the outcome of path validation should be ignored entirely. */ -#define NGTCP2_PV_FLAG_DONT_CARE 0x01u +#define NGTCP2_PV_FLAG_DONT_CARE 0x01U /* NGTCP2_PV_FLAG_CANCEL_TIMER indicates that the expiry timer is cancelled. */ -#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02u +#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02U /* NGTCP2_PV_FLAG_FALLBACK_PRESENT indicates that a fallback Destination Connection ID and PTO are available in ngtcp2_pv. If path validation fails, then fallback to them. If path validation succeeds, the fallback Destination Connection ID is retired if it is not zero length, and does not equal to the current Destination Connection ID. */ -#define NGTCP2_PV_FLAG_FALLBACK_PRESENT 0x04u +#define NGTCP2_PV_FLAG_FALLBACK_PRESENT 0x04U /* NGTCP2_PV_FLAG_PREFERRED_ADDR indicates that client is migrating to server's preferred address. This flag is only used by client. */ -#define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10u +#define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10U typedef struct ngtcp2_pv ngtcp2_pv; @@ -141,7 +142,7 @@ void ngtcp2_pv_del(ngtcp2_pv *pv); * ngtcp2_pv_add_entry adds new entry with |data|. |expiry| is the * expiry time of the entry. */ -void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data, +void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const ngtcp2_path_challenge_data *data, ngtcp2_tstamp expiry, uint8_t flags, ngtcp2_tstamp ts); /* @@ -164,7 +165,8 @@ int ngtcp2_pv_full(ngtcp2_pv *pv); * NGTCP2_ERR_INVALID_ARGUMENT * |pv| does not have an entry which has |data| and |path| */ -int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data); +int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, + const ngtcp2_path_challenge_data *data); /* * ngtcp2_pv_handle_entry_expiry checks expiry of existing entries. diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c index c10e2ff6700451..ed08eb1b5ac2b4 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.c @@ -194,7 +194,7 @@ void ngtcp2_qlog_start(ngtcp2_qlog *qlog, const ngtcp2_cid *odcid, int server) { } p = write_verbatim( - p, "\x1e{\"qlog_format\":\"JSON-SEQ\",\"qlog_version\":\"0.3\","); + p, "\x1E{\"qlog_format\":\"JSON-SEQ\",\"qlog_version\":\"0.3\","); p = write_trace(p, server, odcid); p = write_verbatim(p, "}\n"); @@ -547,8 +547,7 @@ write_new_connection_id_frame(uint8_t *p, const ngtcp2_new_connection_id *fr) { *p++ = ','; p = write_pair_cid(p, "connection_id", &fr->cid); p = write_verbatim(p, ",\"stateless_reset_token\":{"); - p = write_pair_hex(p, "data", fr->stateless_reset_token, - sizeof(fr->stateless_reset_token)); + p = write_pair_hex(p, "data", fr->token.data, sizeof(fr->token.data)); *p++ = '}'; *p++ = '}'; @@ -578,7 +577,7 @@ static uint8_t *write_path_challenge_frame(uint8_t *p, #define NGTCP2_QLOG_PATH_CHALLENGE_FRAME_OVERHEAD 57 p = write_verbatim(p, "{\"frame_type\":\"path_challenge\","); - p = write_pair_hex(p, "data", fr->data, sizeof(fr->data)); + p = write_pair_hex(p, "data", fr->data.data, sizeof(fr->data.data)); *p++ = '}'; return p; @@ -592,7 +591,7 @@ static uint8_t *write_path_response_frame(uint8_t *p, #define NGTCP2_QLOG_PATH_RESPONSE_FRAME_OVERHEAD 56 p = write_verbatim(p, "{\"frame_type\":\"path_response\","); - p = write_pair_hex(p, "data", fr->data, sizeof(fr->data)); + p = write_pair_hex(p, "data", fr->data.data, sizeof(fr->data.data)); *p++ = '}'; return p; @@ -662,7 +661,7 @@ static void qlog_pkt_write_start(ngtcp2_qlog *qlog, int sent) { ngtcp2_buf_reset(&qlog->buf); p = qlog->buf.last; - *p++ = '\x1e'; + *p++ = '\x1E'; *p++ = '{'; p = qlog_write_time(qlog, p); p = write_verbatim(p, ",\"name\":"); @@ -913,7 +912,7 @@ void ngtcp2_qlog_parameters_set_transport_params( return; } - *p++ = '\x1e'; + *p++ = '\x1E'; *p++ = '{'; p = qlog_write_time(qlog, p); p = write_verbatim( @@ -1029,7 +1028,7 @@ void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog, return; } - *p++ = '\x1e'; + *p++ = '\x1E'; *p++ = '{'; p = qlog_write_time(qlog, p); p = write_verbatim(p, ",\"name\":\"recovery:metrics_updated\",\"data\":{"); @@ -1068,7 +1067,7 @@ void ngtcp2_qlog_pkt_lost(ngtcp2_qlog *qlog, ngtcp2_rtb_entry *ent) { return; } - *p++ = '\x1e'; + *p++ = '\x1E'; *p++ = '{'; p = qlog_write_time(qlog, p); p = write_verbatim( @@ -1096,7 +1095,7 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf)); - *buf.last++ = '\x1e'; + *buf.last++ = '\x1E'; *buf.last++ = '{'; buf.last = qlog_write_time(qlog, buf.last); buf.last = write_verbatim( @@ -1118,7 +1117,7 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, } void ngtcp2_qlog_stateless_reset_pkt_received( - ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr) { + ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset2 *sr) { uint8_t buf[256]; uint8_t *p = buf; @@ -1126,7 +1125,7 @@ void ngtcp2_qlog_stateless_reset_pkt_received( return; } - *p++ = '\x1e'; + *p++ = '\x1E'; *p++ = '{'; p = qlog_write_time(qlog, p); p = write_verbatim( @@ -1135,8 +1134,8 @@ void ngtcp2_qlog_stateless_reset_pkt_received( .type = NGTCP2_PKT_STATELESS_RESET, }); *p++ = ','; - p = write_pair_hex(p, "stateless_reset_token", sr->stateless_reset_token, - NGTCP2_STATELESS_RESET_TOKENLEN); + p = write_pair_hex(p, "stateless_reset_token", sr->token.data, + sizeof(sr->token.data)); p = write_verbatim(p, "}}\n"); qlog->write(qlog->user_data, NGTCP2_QLOG_WRITE_FLAG_NONE, buf, @@ -1158,7 +1157,7 @@ void ngtcp2_qlog_version_negotiation_pkt_received(ngtcp2_qlog *qlog, ngtcp2_buf_init(&buf, rawbuf, sizeof(rawbuf)); - *buf.last++ = '\x1e'; + *buf.last++ = '\x1E'; *buf.last++ = '{'; buf.last = qlog_write_time(qlog, buf.last); buf.last = write_verbatim( diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.h index d2a5f1038c0f42..17668a50233f4d 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_qlog.h @@ -147,7 +147,7 @@ void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd, * event for a received Stateless Reset packet. */ void ngtcp2_qlog_stateless_reset_pkt_received( - ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr); + ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset2 *sr); /* * ngtcp2_qlog_version_negotiation_pkt_received writes packet_received diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c index 88ec585e69d185..67aaa0493028f9 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c @@ -200,10 +200,10 @@ static size_t rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, } /* NGTCP2_RECLAIM_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_RECLAIM_FLAG_NONE 0x00u +#define NGTCP2_RECLAIM_FLAG_NONE 0x00U /* NGTCP2_RECLAIM_FLAG_ON_LOSS indicates that frames are reclaimed because of the packet loss.*/ -#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01u +#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01U /* * rtb_reclaim_frame copies and queues frames included in |ent| for diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h index 14684a458a60e6..62bcb381fa15bb 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.h @@ -48,41 +48,41 @@ typedef struct ngtcp2_conn_stat ngtcp2_conn_stat; typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; /* NGTCP2_RTB_ENTRY_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00u +#define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00U /* NGTCP2_RTB_ENTRY_FLAG_PROBE indicates that the entry includes a probe packet. */ -#define NGTCP2_RTB_ENTRY_FLAG_PROBE 0x01u +#define NGTCP2_RTB_ENTRY_FLAG_PROBE 0x01U /* NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE indicates that the entry includes a frame which must be retransmitted until it is acknowledged. In most cases, this flag is used along with NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING and NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING. */ -#define NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE 0x02u +#define NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE 0x02U /* NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING indicates that the entry elicits acknowledgement. */ -#define NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING 0x04u +#define NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING 0x04U /* NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED indicates that the packet has been reclaimed on PTO. It is not marked lost yet and still consumes congestion window. */ -#define NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED 0x08u +#define NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED 0x08U /* NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED indicates that the entry has been marked lost and, optionally, scheduled to retransmit. */ -#define NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED 0x10u +#define NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED 0x10U /* NGTCP2_RTB_ENTRY_FLAG_ECN indicates that the entry is included in a UDP datagram with ECN marking. */ -#define NGTCP2_RTB_ENTRY_FLAG_ECN 0x20u +#define NGTCP2_RTB_ENTRY_FLAG_ECN 0x20U /* NGTCP2_RTB_ENTRY_FLAG_DATAGRAM indicates that the entry includes DATAGRAM frame. */ -#define NGTCP2_RTB_ENTRY_FLAG_DATAGRAM 0x40u +#define NGTCP2_RTB_ENTRY_FLAG_DATAGRAM 0x40U /* NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE indicates that the entry includes a PMTUD probe packet. */ -#define NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE 0x80u +#define NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE 0x80U /* NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING indicates that the entry includes a packet which elicits PTO probe packets. */ -#define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100u +#define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100U /* NGTCP2_RTB_ENTRY_FLAG_SKIP indicates that the entry has the skipped packet number. */ -#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200u +#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200U typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c index 1ae0f10d91787a..2726571a504070 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_str.c @@ -50,7 +50,7 @@ uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) { for (i = 0; i < len; ++i) { *dest++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4]; - *dest++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xf]; + *dest++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xF]; } return dest; @@ -72,7 +72,7 @@ char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data, for (i = 0; i < len; ++i) { c = data[i]; - if (0x20 <= c && c <= 0x7e) { + if (0x20 <= c && c <= 0x7E) { *p++ = (char)c; } else { *p++ = '.'; @@ -116,7 +116,7 @@ static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) { break; } - d &= 0xf; + d &= 0xF; if (d) { *p++ = LOWER_XDIGITS[d]; @@ -133,7 +133,7 @@ static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) { for (; i < len; ++i) { d = data[i]; *p++ = LOWER_XDIGITS[d >> 4]; - *p++ = LOWER_XDIGITS[d & 0xf]; + *p++ = LOWER_XDIGITS[d & 0xF]; } return p; @@ -235,7 +235,7 @@ static int countl_zero(uint64_t x) { }; int n = 0; - if (x >= 1ull << 32) { + if (x >= 1ULL << 32) { x >>= 32; n += 32; } @@ -263,25 +263,25 @@ static int countl_zero(uint64_t x) { */ static size_t count_digit(uint64_t x) { static const uint64_t count_digit_tbl[] = { - 9ull, - 99ull, - 999ull, - 9999ull, - 99999ull, - 999999ull, - 9999999ull, - 99999999ull, - 999999999ull, - 9999999999ull, - 99999999999ull, - 999999999999ull, - 9999999999999ull, - 99999999999999ull, - 999999999999999ull, - 9999999999999999ull, - 99999999999999999ull, - 999999999999999999ull, - 9999999999999999999ull, + 9ULL, + 99ULL, + 999ULL, + 9999ULL, + 99999ULL, + 999999ULL, + 9999999ULL, + 99999999ULL, + 999999999ULL, + 9999999999ULL, + 99999999999ULL, + 999999999999ULL, + 9999999999999ULL, + 99999999999999ULL, + 999999999999999ULL, + 9999999999999999ULL, + 99999999999999999ULL, + 999999999999999999ULL, + 9999999999999999999ULL, }; size_t y = (size_t)(19 * (63 - countl_zero(x | 1)) >> 6); diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h index fb86bd1c23d6e5..0d5d8a63a62c62 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_strm.h @@ -41,54 +41,54 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; /* NGTCP2_STRM_FLAG_NONE indicates that no flag is set. */ -#define NGTCP2_STRM_FLAG_NONE 0x00u +#define NGTCP2_STRM_FLAG_NONE 0x00U /* NGTCP2_STRM_FLAG_SHUT_RD indicates that further reception of stream data is not allowed. */ -#define NGTCP2_STRM_FLAG_SHUT_RD 0x01u +#define NGTCP2_STRM_FLAG_SHUT_RD 0x01U /* NGTCP2_STRM_FLAG_SHUT_WR indicates that further transmission of stream data is not allowed. */ -#define NGTCP2_STRM_FLAG_SHUT_WR 0x02u +#define NGTCP2_STRM_FLAG_SHUT_WR 0x02U #define NGTCP2_STRM_FLAG_SHUT_RDWR \ (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_SHUT_WR) /* NGTCP2_STRM_FLAG_RESET_STREAM indicates that RESET_STREAM is sent from the local endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is also set. */ -#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04u +#define NGTCP2_STRM_FLAG_RESET_STREAM 0x04U /* NGTCP2_STRM_FLAG_RESET_STREAM_RECVED indicates that RESET_STREAM is received from the remote endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_RD is also set. */ -#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08u +#define NGTCP2_STRM_FLAG_RESET_STREAM_RECVED 0x08U /* NGTCP2_STRM_FLAG_STOP_SENDING indicates that STOP_SENDING is sent from the local endpoint. */ -#define NGTCP2_STRM_FLAG_STOP_SENDING 0x10u +#define NGTCP2_STRM_FLAG_STOP_SENDING 0x10U /* NGTCP2_STRM_FLAG_RESET_STREAM_ACKED indicates that the outgoing RESET_STREAM is acknowledged by peer. */ -#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20u +#define NGTCP2_STRM_FLAG_RESET_STREAM_ACKED 0x20U /* NGTCP2_STRM_FLAG_FIN_ACKED indicates that a STREAM with FIN bit set is acknowledged by a remote endpoint. */ -#define NGTCP2_STRM_FLAG_FIN_ACKED 0x40u +#define NGTCP2_STRM_FLAG_FIN_ACKED 0x40U /* NGTCP2_STRM_FLAG_ANY_ACKED indicates that any portion of stream data, including 0 length segment, is acknowledged. */ -#define NGTCP2_STRM_FLAG_ANY_ACKED 0x80u +#define NGTCP2_STRM_FLAG_ANY_ACKED 0x80U /* NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET indicates that app_error_code field is set. This resolves the ambiguity that the initial app_error_code value 0 might be a proper application error code. In this case, without this flag, we are unable to distinguish assigned value from unassigned one. */ -#define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100u +#define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100U /* NGTCP2_STRM_FLAG_SEND_STOP_SENDING is set when STOP_SENDING frame should be sent. */ -#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200u +#define NGTCP2_STRM_FLAG_SEND_STOP_SENDING 0x200U /* NGTCP2_STRM_FLAG_SEND_RESET_STREAM is set when RESET_STREAM frame should be sent. */ -#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400u +#define NGTCP2_STRM_FLAG_SEND_RESET_STREAM 0x400U /* NGTCP2_STRM_FLAG_STOP_SENDING_RECVED indicates that STOP_SENDING is received from the remote endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is also set. */ -#define NGTCP2_STRM_FLAG_STOP_SENDING_RECVED 0x800u +#define NGTCP2_STRM_FLAG_STOP_SENDING_RECVED 0x800U /* NGTCP2_STRM_FLAG_ANY_SENT indicates that any STREAM frame, including empty one, has been sent. */ -#define NGTCP2_STRM_FLAG_ANY_SENT 0x1000u +#define NGTCP2_STRM_FLAG_ANY_SENT 0x1000U typedef struct ngtcp2_strm ngtcp2_strm; diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c index d652ece4e07a88..5d378176e16289 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.c @@ -150,8 +150,8 @@ ngtcp2_ssize ngtcp2_transport_params_encode_versioned( if (params->stateless_reset_token_present) { len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) + - ngtcp2_put_uvarintlen(NGTCP2_STATELESS_RESET_TOKENLEN) + - NGTCP2_STATELESS_RESET_TOKENLEN; + ngtcp2_put_uvarintlen(sizeof(params->stateless_reset_token)) + + sizeof(params->stateless_reset_token); } if (params->preferred_addr_present) { @@ -160,7 +160,7 @@ ngtcp2_ssize ngtcp2_transport_params_encode_versioned( preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ + 16 /* ipv6Address */ + 2 /* ipv6Port */ + 1 + params->preferred_addr.cid.datalen /* CID */ + - NGTCP2_STATELESS_RESET_TOKENLEN; + sizeof(params->preferred_addr.stateless_reset_token); len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) + ngtcp2_put_uvarintlen(preferred_addrlen) + preferred_addrlen; } @@ -626,7 +626,8 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version, } len = 4 /* ipv4Address */ + 2 /* ipv4Port */ + 16 /* ipv6Address */ + 2 /* ipv6Port */ - + 1 /* cid length */ + NGTCP2_STATELESS_RESET_TOKENLEN; + + 1 /* cid length */ + + sizeof(params->preferred_addr.stateless_reset_token); if (valuelen < len) { return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM; } diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h index c077f06a9dd717..d98d034b3c28be 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_transport_params.h @@ -45,16 +45,16 @@ typedef uint64_t ngtcp2_transport_param_id; #define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI 0x07 #define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI 0x08 #define NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI 0x09 -#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0a -#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0b -#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0c -#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0d -#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0e -#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0f +#define NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT 0x0A +#define NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY 0x0B +#define NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION 0x0C +#define NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS 0x0D +#define NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT 0x0E +#define NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID 0x0F #define NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID 0x10 /* https://datatracker.ietf.org/doc/html/rfc9221 */ #define NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE 0x20 -#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2ab2 +#define NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT 0x2AB2 /* https://datatracker.ietf.org/doc/html/rfc9368 */ #define NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION 0x11 diff --git a/deps/ngtcp2/ngtcp2/lib/ngtcp2_window_filter.c b/deps/ngtcp2/ngtcp2/lib/ngtcp2_window_filter.c index 39f3d408a741ba..707cd570799e46 100644 --- a/deps/ngtcp2/ngtcp2/lib/ngtcp2_window_filter.c +++ b/deps/ngtcp2/ngtcp2/lib/ngtcp2_window_filter.c @@ -39,7 +39,7 @@ void ngtcp2_window_filter_init(ngtcp2_window_filter *wf, uint64_t window_length) { wf->window_length = window_length; - memset(wf->estimates, 0xff, sizeof(wf->estimates)); + memset(wf->estimates, 0xFF, sizeof(wf->estimates)); } void ngtcp2_window_filter_update(ngtcp2_window_filter *wf, uint64_t new_sample,