deps: update ngtcp2 to 1.14.0

Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/59249
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
James M Snell 2025-07-27 13:32:27 -07:00
parent 0e754fa5d1
commit dceb1fca40
39 changed files with 2582 additions and 731 deletions

View file

@ -36,6 +36,9 @@ $ cp -R lib/* ../node/deps/ngtcp2/ngtcp2/lib/
$ cp -R crypto/* ../node/deps/ngtcp2/ngtcp2/crypto/
```
Be sure to also update the `ngtcp2.gyp` file to reflect any changes in
the source files or include directories.
### Updating nghttp3
To update nghttp3, replace `v0.7.0` with the desired git tag:
@ -47,3 +50,6 @@ $ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ cp -R lib/* ../node/deps/ngtcp2/nghttp3/lib/
```
Be sure to also update the `ngtcp2.gyp` file to reflect any changes in
the source files or include directories.

View file

@ -9,12 +9,13 @@
'ngtcp2/lib/ngtcp2_balloc.c',
'ngtcp2/lib/ngtcp2_bbr.c',
'ngtcp2/lib/ngtcp2_buf.c',
'ngtcp2/lib/ngtcp2_callbacks.c',
'ngtcp2/lib/ngtcp2_cc.c',
'ngtcp2/lib/ngtcp2_cid.c',
'ngtcp2/lib/ngtcp2_conn.c',
'ngtcp2/lib/ngtcp2_conv.c',
'ngtcp2/lib/ngtcp2_dcidtr.c',
'ngtcp2/lib/ngtcp2_crypto.c',
'ngtcp2/lib/ngtcp2_dcidtr.c',
'ngtcp2/lib/ngtcp2_err.c',
'ngtcp2/lib/ngtcp2_frame_chain.c',
'ngtcp2/lib/ngtcp2_gaptr.c',
@ -47,8 +48,8 @@
'ngtcp2/lib/ngtcp2_window_filter.c',
'ngtcp2/crypto/shared.c'
],
'ngtcp2_sources_quictls': [
#'ngtcp2/crypto/quictls/quictls.c'
'ngtcp2_sources_ossl': [
'ngtcp2/crypto/ossl/ossl.c'
],
'ngtcp2_sources_boringssl': [
'ngtcp2/crypto/boringssl/boringssl.c'
@ -142,7 +143,7 @@
},
'sources': [
'<@(ngtcp2_sources)',
'<@(ngtcp2_sources_quictls)',
'<@(ngtcp2_sources_ossl)',
]
},
{

View file

@ -69,6 +69,13 @@ extern "C" {
*/
#define NGTCP2_CRYPTO_ERR_VERIFY_TOKEN -203
/**
* @macro
*
* :macro:`NGTCP2_CRYPTO_ERR_NOMEM` indicates out of memory.
*/
#define NGTCP2_CRYPTO_ERR_NOMEM -501
/**
* @function
*

View file

@ -0,0 +1,198 @@
/*
* ngtcp2
*
* Copyright (c) 2025 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_CRYPTO_OSSL_H
#define NGTCP2_CRYPTO_OSSL_H
#include <ngtcp2/ngtcp2.h>
#include <openssl/ssl.h>
#ifdef __cplusplus
extern "C" {
#endif /* defined(__cplusplus) */
/**
* @macrosection
*
* ossl specific error codes
*/
/**
* @macro
*
* :macro:`NGTCP2_CRYPTO_OSSL_ERR_TLS_WANT_X509_LOOKUP` is the error
* code which indicates that TLS handshake routine is interrupted by
* X509 certificate lookup. See :macro:`SSL_ERROR_WANT_X509_LOOKUP`
* error description from `SSL_do_handshake`.
*/
#define NGTCP2_CRYPTO_OSSL_ERR_TLS_WANT_X509_LOOKUP -10001
/**
* @macro
*
* :macro:`NGTCP2_CRYPTO_OSSL_ERR_TLS_WANT_CLIENT_HELLO_CB` is the
* error code which indicates that TLS handshake routine is
* interrupted by client hello callback. See
* :macro:`SSL_ERROR_WANT_CLIENT_HELLO_CB` error description from
* `SSL_do_handshake`.
*/
#define NGTCP2_CRYPTO_OSSL_ERR_TLS_WANT_CLIENT_HELLO_CB -10002
/**
* @function
*
* `ngtcp2_crypto_ossl_from_ossl_encryption_level` translates
* |ossl_level| to :type:`ngtcp2_encryption_level`. This function is
* only available for ossl backend.
*/
NGTCP2_EXTERN ngtcp2_encryption_level
ngtcp2_crypto_ossl_from_ossl_encryption_level(uint32_t ossl_level);
/**
* @function
*
* `ngtcp2_crypto_ossl_from_ngtcp2_encryption_level` translates
* |encryption_level| to OpenSSL encryption level. This function is
* only available for ossl backend.
*/
NGTCP2_EXTERN uint32_t ngtcp2_crypto_ossl_from_ngtcp2_encryption_level(
ngtcp2_encryption_level encryption_level);
/**
* @struct
*
* :type:`ngtcp2_crypto_ossl_ctx` contains per-connection state, and
* must be set to `ngtcp2_conn_set_tls_native_handle`.
*/
typedef struct ngtcp2_crypto_ossl_ctx ngtcp2_crypto_ossl_ctx;
/**
* @function
*
* `ngtcp2_crypto_ossl_ctx_new` creates new
* :type:`ngtcp2_crypto_ossl_ctx` object, and sets it to |*pctx| if it
* succeeds.
*
* |ssl| is set to |*pctx|. It may be NULL, and in that case, call
* `ngtcp2_crypto_ossl_ctx_set_ssl` later to set ``SSL`` object.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :enum:`NGTCP2_CRYPTO_ERR_NOMEM`
* Out of memory
*/
NGTCP2_EXTERN int ngtcp2_crypto_ossl_ctx_new(ngtcp2_crypto_ossl_ctx **pctx,
SSL *ssl);
/**
* @function
*
* `ngtcp2_crypto_ossl_ctx_del` frees resources allocated for |ctx|.
* It also frees memory pointed by |ctx|.
*/
NGTCP2_EXTERN void ngtcp2_crypto_ossl_ctx_del(ngtcp2_crypto_ossl_ctx *ctx);
/**
* @function
*
* `ngtcp2_crypto_ossl_ctx_set_ssl` sets |ssl| to |ctx|. This
* function must be called after ``SSL`` object is created.
*/
NGTCP2_EXTERN void ngtcp2_crypto_ossl_ctx_set_ssl(ngtcp2_crypto_ossl_ctx *ctx,
SSL *ssl);
/**
* @function
*
* `ngtcp2_crypto_ossl_ctx_get_ssl` returns ``SSL`` object set to
* |ctx|. If the object has not been set, this function returns NULL.
*/
NGTCP2_EXTERN SSL *ngtcp2_crypto_ossl_ctx_get_ssl(ngtcp2_crypto_ossl_ctx *ctx);
/**
* @function
*
* `ngtcp2_crypto_ossl_init` initializes libngtcp2_crypto_ossl
* library. This initialization is optional. It is highly
* recommended to call this function before any use of
* libngtcp2_crypto library API to workaround the performance
* regression.
*
* This function returns 0 if it succeeds, or -1.
*/
NGTCP2_EXTERN int ngtcp2_crypto_ossl_init(void);
/**
* @function
*
* `ngtcp2_crypto_ossl_configure_server_session` configures |ssl| for
* server side QUIC connection. It performs the following
* modifications:
*
* - Register callbacks via ``SSL_set_quic_tls_cbs``
*
* Application must set a pointer to :type:`ngtcp2_crypto_conn_ref` to
* SSL object by calling SSL_set_app_data, and
* :type:`ngtcp2_crypto_conn_ref` object must have
* :member:`ngtcp2_crypto_conn_ref.get_conn` field assigned to get
* :type:`ngtcp2_conn`.
*
* Application must call ``SSL_set_app_data(ssl, NULL)`` before
* calling ``SSL_free(ssl)`` if you cannot make `ngtcp2_conn` object
* alive until ``SSL_free`` is called.
*
* It returns 0 if it succeeds, or -1.
*/
NGTCP2_EXTERN int ngtcp2_crypto_ossl_configure_server_session(SSL *ssl);
/**
* @function
*
* `ngtcp2_crypto_ossl_configure_client_session` configures |ssl| for
* client side QUIC connection. It performs the following
* modifications:
*
* - Register callbacks via ``SSL_set_quic_tls_cbs``
*
* Application must set a pointer to :type:`ngtcp2_crypto_conn_ref` to
* SSL object by calling SSL_set_app_data, and
* :type:`ngtcp2_crypto_conn_ref` object must have
* :member:`ngtcp2_crypto_conn_ref.get_conn` field assigned to get
* :type:`ngtcp2_conn`.
*
* Application must call ``SSL_set_app_data(ssl, NULL)`` before
* calling ``SSL_free(ssl)`` if you cannot make `ngtcp2_conn` object
* alive until ``SSL_free`` is called.
*
* It returns 0 if it succeeds, or -1.
*/
NGTCP2_EXTERN int ngtcp2_crypto_ossl_configure_client_session(SSL *ssl);
#ifdef __cplusplus
}
#endif /* defined(__cplusplus) */
#endif /* !defined(NGTCP2_CRYPTO_OSSL_H) */

View file

@ -37,7 +37,7 @@ extern "C" {
* @struct
*
* :type:`ngtcp2_crypto_picotls_ctx` contains per-connection state of
* Picotls objects and must be an object to bet set to
* Picotls object, and must be set to
* `ngtcp2_conn_set_tls_native_handle`.
*/
typedef struct ngtcp2_crypto_picotls_ctx {

1191
deps/ngtcp2/ngtcp2/crypto/ossl/ossl.c vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -214,18 +214,10 @@ typedef struct ngtcp2_mem {
/**
* @macro
*
* :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1
* second.
* :macro:`NGTCP2_NANOSECONDS` is a count of tick which corresponds to
* 1 nanosecond.
*/
#define NGTCP2_SECONDS ((ngtcp2_duration)1000000000ULL)
/**
* @macro
*
* :macro:`NGTCP2_MILLISECONDS` is a count of tick which corresponds
* to 1 millisecond.
*/
#define NGTCP2_MILLISECONDS ((ngtcp2_duration)1000000ULL)
#define NGTCP2_NANOSECONDS ((ngtcp2_duration)1ULL)
/**
* @macro
@ -233,15 +225,31 @@ typedef struct ngtcp2_mem {
* :macro:`NGTCP2_MICROSECONDS` is a count of tick which corresponds
* to 1 microsecond.
*/
#define NGTCP2_MICROSECONDS ((ngtcp2_duration)1000ULL)
#define NGTCP2_MICROSECONDS ((ngtcp2_duration)(1000ULL * NGTCP2_NANOSECONDS))
/**
* @macro
*
* :macro:`NGTCP2_NANOSECONDS` is a count of tick which corresponds to
* 1 nanosecond.
* :macro:`NGTCP2_MILLISECONDS` is a count of tick which corresponds
* to 1 millisecond.
*/
#define NGTCP2_NANOSECONDS ((ngtcp2_duration)1ULL)
#define NGTCP2_MILLISECONDS ((ngtcp2_duration)(1000ULL * NGTCP2_MICROSECONDS))
/**
* @macro
*
* :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1
* second.
*/
#define NGTCP2_SECONDS ((ngtcp2_duration)(1000ULL * NGTCP2_MILLISECONDS))
/**
* @macro
*
* :macro:`NGTCP2_MINUTES` is a count of tick which corresponds to 1
* minute.
*/
#define NGTCP2_MINUTES ((ngtcp2_duration)(60ULL * NGTCP2_SECONDS))
/**
* @macrosection
@ -2858,7 +2866,8 @@ typedef int (*ngtcp2_extend_max_stream_data)(ngtcp2_conn *conn,
* :type:`ngtcp2_rand` is a callback function to get random data of
* length |destlen|. Application must fill random |destlen| bytes to
* the buffer pointed by |dest|. The generated data is used only in
* non-cryptographic context.
* non-cryptographic context. But it is strongly recommended to use a
* secure random number generator.
*/
typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen,
const ngtcp2_rand_ctx *rand_ctx);
@ -2962,6 +2971,28 @@ typedef int (*ngtcp2_update_key)(
*/
#define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02u
/**
* @functypedef
*
* :type:`ngtcp2_begin_path_validation` is a callback function which
* is called when the path validation has started. |flags| is zero or
* more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_*
* <NGTCP2_PATH_VALIDATION_FLAG_NONE>`. |path| is the path that is
* being validated. |fallback_path|, if not NULL, is the path that is
* used when this validation fails.
*
* Currently, the flags may only contain
* :macro:`NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR`.
*
* The callback function must return 0 if it succeeds. Returning
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
* immediately.
*/
typedef int (*ngtcp2_begin_path_validation)(ngtcp2_conn *conn, uint32_t flags,
const ngtcp2_path *path,
const ngtcp2_path *fallback_path,
void *user_data);
/**
* @functypedef
*
@ -3253,7 +3284,8 @@ typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn,
void *user_data);
#define NGTCP2_CALLBACKS_V1 1
#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V1
#define NGTCP2_CALLBACKS_V2 2
#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V2
/**
* @struct
@ -3518,6 +3550,13 @@ typedef struct ngtcp2_callbacks {
* is only used by client.
*/
ngtcp2_tls_early_data_rejected tls_early_data_rejected;
/* The following fields have been added since NGTCP2_CALLBACKS_V2. */
/**
* :member:`begin_path_validation` is a callback function which is
* invoked when a path validation has started. This field is
* available since v1.14.0.
*/
ngtcp2_begin_path_validation begin_path_validation;
} ngtcp2_callbacks;
/**
@ -4398,6 +4437,17 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn,
*/
#define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02u
/**
* @macro
*
* :macro:`NGTCP2_WRITE_STREAM_FLAG_PADDING` indicates that a
* non-empty 0 RTT or 1 RTT ack-eliciting packet is padded to the
* minimum length of a sending path MTU or a given packet buffer when
* finalizing it. PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE
* only packets and PMTUD packets are excluded.
*/
#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04u
/**
* @function
*
@ -4522,6 +4572,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned(
* include, call this function with |stream_id| as -1 to stop
* coalescing and write a packet.
*
* If :macro:`NGTCP2_WRITE_STREAM_FLAG_PADDING` is set in |flags| when
* finalizing a non-empty 0 RTT or 1 RTT ack-eliciting packet, the
* packet is padded to the minimum length of a sending path MTU or a
* given packet buffer.
*
* This function returns 0 if it cannot write any frame because buffer
* is too small, or packet is congestion limited. Application should
* keep reading and wait for congestion window to grow.
@ -4586,6 +4641,17 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned(
*/
#define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01u
/**
* @macro
*
* :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_PADDING` indicates that a
* non-empty 0 RTT or 1 RTT ack-eliciting packet is padded to the
* minimum length of a sending path MTU or a given packet buffer when
* finalizing it. PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE
* only packets and PMTUD packets are excluded.
*/
#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02u
/**
* @function
*
@ -4667,6 +4733,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_datagram_versioned(
* (or `ngtcp2_conn_writev_stream`) until it returns a positive number
* (which indicates a complete packet is ready).
*
* If :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_PADDING` is set in |flags|
* when finalizing a non-empty 0 RTT or 1 RTT ack-eliciting packet,
* the packet is padded to the minimum length of a sending path MTU or
* a given packet buffer.
*
* This function returns the number of bytes written in |dest| if it
* succeeds, or one of the following negative error codes:
*

View file

@ -36,7 +36,7 @@
*
* Version number of the ngtcp2 library release.
*/
#define NGTCP2_VERSION "1.11.0"
#define NGTCP2_VERSION "1.14.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 0x010b00
#define NGTCP2_VERSION_NUM 0x010e00
#endif /* !defined(NGTCP2_VERSION_H) */

View file

@ -69,7 +69,7 @@ static void bbr_on_transmit(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr);
static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr);
static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr);
static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr);
@ -157,8 +157,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
const ngtcp2_cc_ack *ack,
ngtcp2_tstamp ts);
static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
@ -168,15 +167,16 @@ static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr,
static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat);
static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr,
static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat);
static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr,
static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack);
static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack);
static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
@ -189,23 +189,19 @@ static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr,
static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat);
static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static int is_inflight_too_high(const ngtcp2_rs *rs);
static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr);
static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_rs *rs, ngtcp2_tstamp ts);
ngtcp2_tstamp ts);
static void bbr_note_loss(ngtcp2_cc_bbr *bbr);
static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr,
const ngtcp2_rs *rs,
static uint64_t
bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
const ngtcp2_cc_pkt *pkt);
static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack,
@ -292,7 +288,7 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
bbr->full_bw_reached = 0;
bbr_reset_congestion_signals(bbr);
bbr_reset_lower_bounds(bbr);
bbr_reset_shortterm_model(bbr);
bbr_init_round_counting(bbr);
bbr_reset_full_bw(bbr);
bbr_init_pacing_rate(bbr, cstat);
@ -326,7 +322,7 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
bbr->bw_probe_up_rounds = 0;
bbr->bw_probe_up_acks = 0;
bbr->inflight_hi = UINT64_MAX;
bbr->inflight_longterm = UINT64_MAX;
bbr->probe_rtt_expired = 0;
bbr->probe_rtt_min_delay = UINT64_MAX;
@ -348,9 +344,9 @@ static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) {
bbr->inflight_latest = 0;
}
static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) {
bbr->bw_lo = UINT64_MAX;
bbr->inflight_lo = UINT64_MAX;
static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr) {
bbr->bw_shortterm = UINT64_MAX;
bbr->inflight_shortterm = UINT64_MAX;
}
static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr) {
@ -367,7 +363,7 @@ static void bbr_reset_full_bw(ngtcp2_cc_bbr *bbr) {
static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat) {
if (bbr->full_bw_now || bbr->rst->rs.is_app_limited) {
if (bbr->full_bw_now || !bbr->round_start || bbr->rst->rs.is_app_limited) {
return;
}
@ -378,10 +374,6 @@ static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr,
return;
}
if (!bbr->round_start) {
return;
}
++bbr->full_bw_count;
bbr->full_bw_now = bbr->full_bw_count >= 3;
@ -399,36 +391,38 @@ static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) {
if (bbr->full_bw_reached || bbr->loss_events_in_round <= 6 ||
(bbr->in_loss_recovery &&
bbr->round_count <= bbr->round_count_at_recovery) ||
!is_inflight_too_high(&bbr->rst->rs)) {
!bbr_is_inflight_too_high(bbr)) {
return;
}
bbr->full_bw_reached = 1;
bbr->inflight_hi = ngtcp2_max_uint64(bbr_bdp_multiple(bbr, bbr->cwnd_gain_h),
bbr->inflight_latest);
bbr->inflight_longterm = ngtcp2_max_uint64(
bbr_bdp_multiple(bbr, bbr->cwnd_gain_h), bbr->inflight_latest);
}
static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
cstat->pacing_interval =
(cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
: cstat->smoothed_rtt) *
cstat->pacing_interval_m =
((cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
: cstat->smoothed_rtt)
<< 10) *
100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd;
}
static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
uint64_t pacing_gain_h) {
ngtcp2_duration interval;
uint64_t interval_m;
if (bbr->bw == 0) {
return;
}
interval = NGTCP2_SECONDS * 100 * 100 / pacing_gain_h / bbr->bw /
interval_m = (NGTCP2_SECONDS << 10) * 100 * 100 / pacing_gain_h / bbr->bw /
(100 - NGTCP2_BBR_PACING_MARGIN_PERCENT);
interval_m = ngtcp2_max_uint64(interval_m, 1);
if (bbr->full_bw_reached || interval < cstat->pacing_interval) {
cstat->pacing_interval = interval;
if (bbr->full_bw_reached || interval_m < cstat->pacing_interval_m) {
cstat->pacing_interval_m = interval_m;
}
}
@ -546,25 +540,26 @@ static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
}
static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
if (bbr->bw_lo == UINT64_MAX) {
bbr->bw_lo = bbr->max_bw;
if (bbr->bw_shortterm == UINT64_MAX) {
bbr->bw_shortterm = bbr->max_bw;
}
if (bbr->inflight_lo == UINT64_MAX) {
bbr->inflight_lo = cstat->cwnd;
if (bbr->inflight_shortterm == UINT64_MAX) {
bbr->inflight_shortterm = cstat->cwnd;
}
}
static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr) {
bbr->bw_lo = ngtcp2_max_uint64(
bbr->bw_latest, bbr->bw_lo * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM);
bbr->inflight_lo = ngtcp2_max_uint64(
bbr->bw_shortterm = ngtcp2_max_uint64(
bbr->bw_latest,
bbr->bw_shortterm * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM);
bbr->inflight_shortterm = ngtcp2_max_uint64(
bbr->inflight_latest,
bbr->inflight_lo * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM);
bbr->inflight_shortterm * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM);
}
static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr) {
bbr->bw = ngtcp2_min_uint64(bbr->max_bw, bbr->bw_lo);
bbr->bw = ngtcp2_min_uint64(bbr->max_bw, bbr->bw_shortterm);
}
static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
@ -712,7 +707,7 @@ static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr) {
ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
"bbr start ProbeBW_REFILL");
bbr_reset_lower_bounds(bbr);
bbr_reset_shortterm_model(bbr);
bbr->bw_probe_up_rounds = 0;
bbr->bw_probe_up_acks = 0;
@ -738,7 +733,7 @@ static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
bbr->pacing_gain_h = 125;
bbr->cwnd_gain_h = 225;
bbr_raise_inflight_hi_slope(bbr, cstat);
bbr_raise_inflight_longterm_slope(bbr, cstat);
}
static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
@ -749,7 +744,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
return;
}
bbr_adapt_upper_bounds(bbr, cstat, ack, ts);
bbr_adapt_longterm_model(bbr, cstat, ack);
if (!bbr_is_in_probe_bw_state(bbr)) {
return;
@ -761,7 +756,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
return;
}
if (bbr_is_time_to_cruise(bbr, cstat, ts)) {
if (bbr_is_time_to_cruise(bbr, cstat)) {
bbr_start_probe_bw_cruise(bbr);
}
@ -790,30 +785,22 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
}
}
static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
(void)ts;
static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
uint64_t inflight = ngtcp2_min_uint64(bbr_inflight_with_headroom(bbr, cstat),
bbr_inflight(bbr, cstat, 100));
if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) {
return 0;
}
if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) {
return 1;
}
return 0;
return cstat->bytes_in_flight <= inflight;
}
static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
if (bbr->rst->is_cwnd_limited && cstat->cwnd >= bbr->inflight_hi) {
if (bbr->rst->is_cwnd_limited && cstat->cwnd >= bbr->inflight_longterm) {
bbr_reset_full_bw(bbr);
bbr->full_bw = cstat->delivery_rate_sec;
} else if (bbr->full_bw_now) {
return 1;
}
return 0;
}
return bbr->full_bw_now;
}
static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr,
@ -826,23 +813,24 @@ static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat) {
uint64_t headroom;
uint64_t mpcwnd;
if (bbr->inflight_hi == UINT64_MAX) {
if (bbr->inflight_longterm == UINT64_MAX) {
return UINT64_MAX;
}
headroom = ngtcp2_max_uint64(cstat->max_tx_udp_payload_size,
bbr->inflight_hi * NGTCP2_BBR_HEADROOM_NUMER /
headroom =
ngtcp2_max_uint64(cstat->max_tx_udp_payload_size,
bbr->inflight_longterm * NGTCP2_BBR_HEADROOM_NUMER /
NGTCP2_BBR_HEADROOM_DENOM);
mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size);
if (bbr->inflight_hi > headroom) {
return ngtcp2_max_uint64(bbr->inflight_hi - headroom, mpcwnd);
if (bbr->inflight_longterm > headroom) {
return ngtcp2_max_uint64(bbr->inflight_longterm - headroom, mpcwnd);
}
return mpcwnd;
}
static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr,
static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat) {
uint64_t growth_this_round = cstat->max_tx_udp_payload_size
<< bbr->bw_probe_up_rounds;
@ -851,12 +839,12 @@ static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr,
bbr->probe_up_cnt = ngtcp2_max_uint64(cstat->cwnd / growth_this_round, 1);
}
static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr,
static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack) {
uint64_t delta;
if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_hi) {
if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_longterm) {
return;
}
@ -867,16 +855,17 @@ static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr,
bbr->probe_up_cnt * cstat->max_tx_udp_payload_size) {
delta = bbr->bw_probe_up_acks / bbr->probe_up_cnt;
bbr->bw_probe_up_acks -= delta * bbr->probe_up_cnt;
bbr->inflight_hi += delta;
bbr->inflight_longterm += delta;
}
if (bbr->round_start) {
bbr_raise_inflight_hi_slope(bbr, cstat);
bbr_raise_inflight_longterm_slope(bbr, cstat);
}
}
static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack) {
if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING &&
bbr->round_start) {
bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK;
@ -889,17 +878,17 @@ static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
}
}
if (!bbr_check_inflight_too_high(bbr, cstat, ts)) {
if (bbr->inflight_hi == UINT64_MAX) {
if (!bbr_is_inflight_too_high(bbr)) {
if (bbr->inflight_longterm == UINT64_MAX) {
return;
}
if (bbr->rst->rs.tx_in_flight > bbr->inflight_hi) {
bbr->inflight_hi = bbr->rst->rs.tx_in_flight;
if (bbr->rst->rs.tx_in_flight > bbr->inflight_longterm) {
bbr->inflight_longterm = bbr->rst->rs.tx_in_flight;
}
if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) {
bbr_probe_inflight_hi_upward(bbr, cstat, ack);
bbr_probe_inflight_longterm_upward(bbr, cstat, ack);
}
}
}
@ -921,7 +910,7 @@ static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr) {
bbr->rand(&rand, 1, &bbr->rand_ctx);
bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256);
bbr->rounds_since_bw_probe = (uint64_t)(rand / 128);
bbr->rand(&rand, 1, &bbr->rand_ctx);
@ -941,33 +930,21 @@ static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr,
return ngtcp2_min_uint64(bbr->bdp, cstat->cwnd);
}
static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
if (is_inflight_too_high(&bbr->rst->rs)) {
if (bbr->bw_probe_samples) {
bbr_handle_inflight_too_high(bbr, cstat, &bbr->rst->rs, ts);
}
return 1;
}
return 0;
}
static int is_inflight_too_high(const ngtcp2_rs *rs) {
static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr) {
const ngtcp2_rs *rs = &bbr->rst->rs;
return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM >
rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER;
}
static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_rs *rs,
ngtcp2_tstamp ts) {
const ngtcp2_rs *rs = &bbr->rst->rs;
bbr->bw_probe_samples = 0;
if (!rs->is_app_limited) {
bbr->inflight_hi = ngtcp2_max_uint64(
bbr->inflight_longterm = ngtcp2_max_uint64(
rs->tx_in_flight, bbr_target_inflight(bbr, cstat) *
NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM);
}
@ -987,7 +964,7 @@ static void bbr_note_loss(ngtcp2_cc_bbr *bbr) {
static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
ngtcp2_rs rs = {0};
ngtcp2_rs *rs = &bbr->rst->rs;
bbr_note_loss(bbr);
@ -995,22 +972,22 @@ static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
return;
}
rs.tx_in_flight = pkt->tx_in_flight;
/* bbr->rst->lost is not incremented for pkt yet */
assert(bbr->rst->lost + pkt->pktlen >= pkt->lost);
rs.lost = bbr->rst->lost + pkt->pktlen - pkt->lost;
rs.is_app_limited = pkt->is_app_limited;
rs->tx_in_flight = pkt->tx_in_flight;
assert(bbr->rst->lost >= pkt->lost);
rs->lost = bbr->rst->lost - pkt->lost;
rs->is_app_limited = pkt->is_app_limited;
if (is_inflight_too_high(&rs)) {
rs.tx_in_flight = bbr_inflight_hi_from_lost_packet(bbr, &rs, pkt);
if (bbr_is_inflight_too_high(bbr)) {
rs->tx_in_flight = bbr_inflight_longterm_from_lost_packet(bbr, pkt);
bbr_handle_inflight_too_high(bbr, cstat, &rs, ts);
bbr_handle_inflight_too_high(bbr, cstat, ts);
}
}
static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr,
const ngtcp2_rs *rs,
static uint64_t
bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr,
const ngtcp2_cc_pkt *pkt) {
ngtcp2_rs *rs = &bbr->rst->rs;
uint64_t inflight_prev, lost_prev, lost_prefix;
(void)bbr;
@ -1136,7 +1113,7 @@ static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
}
static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) {
bbr_reset_lower_bounds(bbr);
bbr_reset_shortterm_model(bbr);
if (bbr->full_bw_reached) {
bbr_start_probe_bw_down(bbr, ts);
@ -1204,9 +1181,6 @@ static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat) {
uint64_t inflight;
/* Not documented */
/* bbr_update_aggregation_budget(bbr); */
inflight = bbr_bdp_multiple(bbr, bbr->cwnd_gain_h) + bbr->extra_acked;
bbr->max_inflight = bbr_quantization_budget(bbr, cstat, inflight);
}
@ -1244,12 +1218,9 @@ static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr,
static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat) {
uint64_t probe_rtt_cwnd;
if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) {
probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat);
cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, probe_rtt_cwnd);
cstat->cwnd =
ngtcp2_min_uint64(cstat->cwnd, bbr_probe_rtt_cwnd(bbr, cstat));
}
}
@ -1281,13 +1252,13 @@ static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr,
if (bbr_is_in_probe_bw_state(bbr) &&
bbr->state != NGTCP2_BBR_STATE_PROBE_BW_CRUISE) {
cap = bbr->inflight_hi;
cap = bbr->inflight_longterm;
} else if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT ||
bbr->state == NGTCP2_BBR_STATE_PROBE_BW_CRUISE) {
cap = bbr_inflight_with_headroom(bbr, cstat);
}
cap = ngtcp2_min_uint64(cap, bbr->inflight_lo);
cap = ngtcp2_min_uint64(cap, bbr->inflight_shortterm);
cap = ngtcp2_max_uint64(cap, mpcwnd);
cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, cap);
@ -1297,10 +1268,9 @@ static void bbr_set_send_quantum(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
size_t send_quantum = 64 * 1024;
(void)bbr;
if (cstat->pacing_interval) {
send_quantum = ngtcp2_min_size(
send_quantum, (size_t)(NGTCP2_MILLISECONDS / cstat->pacing_interval));
}
send_quantum =
ngtcp2_min_size(send_quantum, (size_t)((NGTCP2_MILLISECONDS << 10) /
cstat->pacing_interval_m));
cstat->send_quantum =
ngtcp2_max_size(send_quantum, 2 * cstat->max_tx_udp_payload_size);
@ -1420,21 +1390,23 @@ void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log,
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
const ngtcp2_rand_ctx *rand_ctx) {
memset(bbr, 0, sizeof(*bbr));
bbr->cc.log = log;
bbr->cc.on_pkt_lost = bbr_cc_on_pkt_lost;
bbr->cc.congestion_event = bbr_cc_congestion_event;
bbr->cc.on_spurious_congestion = bbr_cc_on_spurious_congestion;
bbr->cc.on_persistent_congestion = bbr_cc_on_persistent_congestion;
bbr->cc.on_ack_recv = bbr_cc_on_ack_recv;
bbr->cc.on_pkt_sent = bbr_cc_on_pkt_sent;
bbr->cc.reset = bbr_cc_reset;
bbr->rst = rst;
bbr->rand = rand;
bbr->rand_ctx = *rand_ctx;
bbr->initial_cwnd = cstat->cwnd;
*bbr = (ngtcp2_cc_bbr){
.cc =
{
.log = log,
.on_pkt_lost = bbr_cc_on_pkt_lost,
.congestion_event = bbr_cc_congestion_event,
.on_spurious_congestion = bbr_cc_on_spurious_congestion,
.on_persistent_congestion = bbr_cc_on_persistent_congestion,
.on_ack_recv = bbr_cc_on_ack_recv,
.on_pkt_sent = bbr_cc_on_pkt_sent,
.reset = bbr_cc_reset,
},
.rst = rst,
.rand = rand,
.rand_ctx = *rand_ctx,
.initial_cwnd = cstat->cwnd,
};
bbr_on_init(bbr, cstat, initial_ts);
}

View file

@ -86,8 +86,8 @@ typedef struct ngtcp2_cc_bbr {
uint64_t inflight_latest;
/* Lower bounds */
uint64_t bw_lo;
uint64_t inflight_lo;
uint64_t bw_shortterm;
uint64_t inflight_shortterm;
/* Round counting */
uint64_t next_round_delivered;
@ -123,7 +123,7 @@ typedef struct ngtcp2_cc_bbr {
int bw_probe_samples;
size_t bw_probe_up_rounds;
uint64_t bw_probe_up_acks;
uint64_t inflight_hi;
uint64_t inflight_longterm;
int probe_rtt_expired;
ngtcp2_duration probe_rtt_min_delay;
ngtcp2_tstamp probe_rtt_min_stamp;

View file

@ -62,13 +62,17 @@ void ngtcp2_buf_reset(ngtcp2_buf *buf);
* written to the underlying buffer. In other words, it returns
* buf->end - buf->last.
*/
#define ngtcp2_buf_left(BUF) (size_t)((BUF)->end - (BUF)->last)
static inline size_t ngtcp2_buf_left(const ngtcp2_buf *buf) {
return (size_t)(buf->end - buf->last);
}
/*
* ngtcp2_buf_len returns the number of bytes left to read. In other
* words, it returns buf->last - buf->pos.
*/
#define ngtcp2_buf_len(BUF) (size_t)((BUF)->last - (BUF)->pos)
static inline size_t ngtcp2_buf_len(const ngtcp2_buf *buf) {
return (size_t)(buf->last - buf->pos);
}
/*
* ngtcp2_buf_cap returns the capacity of the buffer. In other words,

View file

@ -0,0 +1,72 @@
/*
* ngtcp2
*
* Copyright (c) 2025 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_callbacks.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_unreachable.h"
static void callbacks_copy(ngtcp2_callbacks *dest, const ngtcp2_callbacks *src,
int callbacks_version) {
assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
memcpy(dest, src, ngtcp2_callbackslen_version(callbacks_version));
}
const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src) {
if (callbacks_version == NGTCP2_CALLBACKS_VERSION) {
return src;
}
memset(dest, 0, sizeof(*dest));
callbacks_copy(dest, src, callbacks_version);
return dest;
}
void ngtcp2_callbacks_convert_to_old(int callbacks_version,
ngtcp2_callbacks *dest,
const ngtcp2_callbacks *src) {
assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
callbacks_copy(dest, src, callbacks_version);
}
size_t ngtcp2_callbackslen_version(int callbacks_version) {
ngtcp2_callbacks callbacks;
switch (callbacks_version) {
case NGTCP2_CALLBACKS_VERSION:
return sizeof(callbacks);
case NGTCP2_CALLBACKS_V1:
return offsetof(ngtcp2_callbacks, tls_early_data_rejected) +
sizeof(callbacks.tls_early_data_rejected);
default:
ngtcp2_unreachable();
}
}

View file

@ -0,0 +1,73 @@
/*
* ngtcp2
*
* Copyright (c) 2025 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_CALLBACKS_H
#define NGTCP2_CALLBACKS_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* defined(HAVE_CONFIG_H) */
#include <ngtcp2/ngtcp2.h>
/*
* ngtcp2_callbacks_convert_to_latest converts |src| of version
* |callbacks_version| to the latest version NGTCP2_CALLBACKS_VERSION.
*
* |dest| must point to the latest version. |src| may be the older
* version, and if so, it may have fewer fields. Accessing those
* fields causes undefined behavior.
*
* If |callbacks_version| == NGTCP2_CALLBACKS_VERSION, no conversion
* is made, and |src| is returned. Otherwise, first |dest| is
* zero-initialized, and then all valid fields in |src| are copied
* into |dest|. Finally, |dest| is returned.
*/
const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src);
/*
* ngtcp2_callbacks_convert_to_old converts |src| of the latest
* version to |dest| of version |callbacks_version|.
*
* |callbacks_version| must not be the latest version
* NGTCP2_CALLBACKS_VERSION.
*
* |dest| points to the older version, and it may have fewer fields.
* Accessing those fields causes undefined behavior.
*
* This function copies all valid fields in version
* |callbacks_version| from |src| to |dest|.
*/
void ngtcp2_callbacks_convert_to_old(int callbacks_version,
ngtcp2_callbacks *dest,
const ngtcp2_callbacks *src);
/*
* ngtcp2_callbackslen_version returns the effective length of
* ngtcp2_callbacks at the version |callbacks_version|.
*/
size_t ngtcp2_callbackslen_version(int callbacks_version);
#endif /* !defined(NGTCP2_CALLBACKS_H) */

View file

@ -59,14 +59,16 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
static void reno_cc_reset(ngtcp2_cc_reno *reno) { reno->pending_add = 0; }
void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) {
memset(reno, 0, sizeof(*reno));
reno->cc.log = log;
reno->cc.on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked;
reno->cc.congestion_event = ngtcp2_cc_reno_cc_congestion_event;
reno->cc.on_persistent_congestion =
ngtcp2_cc_reno_cc_on_persistent_congestion;
reno->cc.reset = ngtcp2_cc_reno_cc_reset;
*reno = (ngtcp2_cc_reno){
.cc =
{
.log = log,
.on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked,
.congestion_event = ngtcp2_cc_reno_cc_congestion_event,
.on_persistent_congestion = ngtcp2_cc_reno_cc_on_persistent_congestion,
.reset = ngtcp2_cc_reno_cc_reset,
},
};
reno_cc_reset(reno);
}
@ -148,11 +150,10 @@ void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
static void cubic_vars_reset(ngtcp2_cubic_vars *v) {
v->cwnd_prior = 0;
v->w_max = 0;
v->k = 0;
v->k_m = 0;
v->epoch_start = UINT64_MAX;
v->w_est = 0;
v->state = NGTCP2_CUBIC_STATE_INITIAL;
v->app_limited_start_ts = UINT64_MAX;
v->app_limited_duration = 0;
v->pending_bytes_delivered = 0;
@ -177,17 +178,18 @@ static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) {
void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log,
ngtcp2_rst *rst) {
memset(cubic, 0, sizeof(*cubic));
cubic->cc.log = log;
cubic->cc.on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv;
cubic->cc.congestion_event = ngtcp2_cc_cubic_cc_congestion_event;
cubic->cc.on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion;
cubic->cc.on_persistent_congestion =
ngtcp2_cc_cubic_cc_on_persistent_congestion;
cubic->cc.reset = ngtcp2_cc_cubic_cc_reset;
cubic->rst = rst;
*cubic = (ngtcp2_cc_cubic){
.cc =
{
.log = log,
.on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv,
.congestion_event = ngtcp2_cc_cubic_cc_congestion_event,
.on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion,
.on_persistent_congestion = ngtcp2_cc_cubic_cc_on_persistent_congestion,
.reset = ngtcp2_cc_cubic_cc_reset,
},
.rst = rst,
};
cubic_cc_reset(cubic);
}
@ -228,28 +230,42 @@ static uint64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic,
const ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_duration t = ts - cubic->current.epoch_start;
uint64_t tx_m = (t << 10) / NGTCP2_SECONDS;
int neg = tx_m < cubic->current.k_m;
uint64_t time_delta_m;
uint64_t delta;
uint64_t tx = (t << 10) / NGTCP2_SECONDS;
uint64_t kx = (cubic->current.k << 10) / NGTCP2_SECONDS;
uint64_t time_delta;
if (tx < kx) {
return UINT64_MAX;
/* Avoid signed bit-shift */
if (neg) {
time_delta_m = cubic->current.k_m - tx_m;
} else {
time_delta_m = tx_m - cubic->current.k_m;
}
time_delta = tx - kx;
time_delta_m = ngtcp2_min_uint64(time_delta_m, 3600 << 10);
delta = cstat->max_tx_udp_payload_size *
((((time_delta * time_delta) >> 10) * time_delta) >> 10) * 4 / 10;
delta = ((((time_delta_m * time_delta_m) >> 10) * time_delta_m) >> 10) *
cstat->max_tx_udp_payload_size * 4 / 10;
delta >>= 10;
return cubic->current.w_max + (delta >> 10);
if (neg) {
if (cubic->current.w_max < delta) {
/* Negative w_cubic is not interesting. */
return 0;
}
return cubic->current.w_max - delta;
}
return cubic->current.w_max + delta;
}
void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack,
ngtcp2_tstamp ts) {
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
uint64_t w_cubic, w_cubic_next, target, m;
uint64_t w_cubic, w_cubic_next;
uint64_t target, m;
ngtcp2_duration rtt_thresh;
int round_start;
int is_app_limited =
@ -259,24 +275,8 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
return;
}
if (cubic->current.state == NGTCP2_CUBIC_STATE_CONGESTION_AVOIDANCE) {
if (is_app_limited) {
if (cubic->current.app_limited_start_ts == UINT64_MAX) {
cubic->current.app_limited_start_ts = ts;
}
return;
}
if (cubic->current.app_limited_start_ts != UINT64_MAX) {
cubic->current.app_limited_duration +=
ts - cubic->current.app_limited_start_ts;
cubic->current.app_limited_start_ts = UINT64_MAX;
}
} else if (is_app_limited) {
return;
}
if (cstat->cwnd < cstat->ssthresh) {
/* slow-start */
round_start = ack->pkt_delivered >= cubic->next_round_delivered;
if (round_start) {
cubic->next_round_delivered = cubic->rst->delivered;
@ -284,8 +284,7 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
cubic->rst->is_cwnd_limited = 0;
}
if (cstat->cwnd < cstat->ssthresh) {
/* slow-start */
if (!is_app_limited) {
if (cubic->hs.css_round) {
cstat->cwnd += ack->bytes_delivered / NGTCP2_HS_CSS_GROWTH_DIVISOR;
} else {
@ -295,6 +294,7 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
"%" PRIu64 " bytes acked, slow start cwnd=%" PRIu64,
ack->bytes_delivered, cstat->cwnd);
}
if (round_start) {
cubic->hs.last_round_min_rtt = cubic->hs.current_round_min_rtt;
@ -321,7 +321,11 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
"HyStart++ exit slow start");
cubic->current.epoch_start = ts;
cubic->current.w_max = cstat->cwnd;
cstat->ssthresh = cstat->cwnd;
cubic->current.cwnd_prior = cstat->cwnd;
cubic->current.w_est = cstat->cwnd;
}
return;
@ -347,20 +351,18 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
}
/* congestion avoidance */
if (is_app_limited) {
if (cubic->current.app_limited_start_ts == UINT64_MAX) {
cubic->current.app_limited_start_ts = ts;
}
switch (cubic->current.state) {
case NGTCP2_CUBIC_STATE_INITIAL:
m = cstat->max_tx_udp_payload_size * ack->bytes_delivered +
cubic->current.pending_bytes_delivered;
cstat->cwnd += m / cstat->cwnd;
cubic->current.pending_bytes_delivered = m % cstat->cwnd;
return;
case NGTCP2_CUBIC_STATE_RECOVERY:
cubic->current.state = NGTCP2_CUBIC_STATE_CONGESTION_AVOIDANCE;
cubic->current.epoch_start = ts;
break;
default:
break;
}
if (cubic->current.app_limited_start_ts != UINT64_MAX) {
cubic->current.app_limited_duration +=
ts - cubic->current.app_limited_start_ts;
cubic->current.app_limited_start_ts = UINT64_MAX;
}
w_cubic = cubic_cc_compute_w_cubic(cubic, cstat,
@ -369,7 +371,7 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
cubic, cstat,
ts - cubic->current.app_limited_duration + cstat->smoothed_rtt);
if (w_cubic_next == UINT64_MAX || w_cubic_next < cstat->cwnd) {
if (w_cubic_next < cstat->cwnd) {
target = cstat->cwnd;
} else if (2 * w_cubic_next > 3 * cstat->cwnd) {
target = cstat->cwnd * 3 / 2;
@ -387,19 +389,19 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
cubic->current.w_est += m / cstat->cwnd;
}
if (w_cubic == UINT64_MAX || cubic->current.w_est > w_cubic) {
if (cubic->current.w_est > w_cubic) {
cstat->cwnd = cubic->current.w_est;
} else {
m = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size +
cubic->current.pending_bytes_delivered;
cstat->cwnd += m / cstat->cwnd;
cubic->current.pending_bytes_delivered = m % cstat->cwnd;
cstat->cwnd += m / cstat->cwnd;
}
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
"%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
" k=%" PRIi64 " target=%" PRIu64 " w_est=%" PRIu64,
ack->bytes_delivered, cstat->cwnd, cubic->current.k, target,
" k_m=%" PRIu64 " target=%" PRIu64 " w_est=%" PRIu64,
ack->bytes_delivered, cstat->cwnd, cubic->current.k_m, target,
cubic->current.w_est);
}
@ -409,6 +411,7 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
uint64_t flight_size;
uint64_t cwnd_delta;
if (in_congestion_recovery(cstat, sent_ts)) {
return;
@ -422,8 +425,7 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
cstat->congestion_recovery_start_ts = ts;
cubic->current.state = NGTCP2_CUBIC_STATE_RECOVERY;
cubic->current.epoch_start = UINT64_MAX;
cubic->current.epoch_start = ts;
cubic->current.app_limited_start_ts = UINT64_MAX;
cubic->current.app_limited_duration = 0;
cubic->current.pending_bytes_delivered = 0;
@ -435,13 +437,16 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
cubic->current.w_max = cstat->cwnd;
}
cubic->current.w_max =
ngtcp2_max_uint64(cubic->current.w_max, 2 * cstat->max_tx_udp_payload_size);
cstat->ssthresh = cstat->cwnd * 7 / 10;
if (cubic->rst->rs.delivered * 2 < cstat->cwnd) {
flight_size = cstat->bytes_in_flight + bytes_lost;
cstat->ssthresh = ngtcp2_min_uint64(
cstat->ssthresh,
ngtcp2_max_uint64(cubic->rst->rs.delivered, flight_size) * 7 / 10);
ngtcp2_max_uint64(cubic->rst->rs.delivered, flight_size));
}
cstat->ssthresh =
@ -452,15 +457,12 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
cubic->current.w_est = cstat->cwnd;
if (cstat->cwnd < cubic->current.w_max) {
cubic->current.k =
ngtcp2_cbrt(((cubic->current.w_max - cstat->cwnd) << 10) * 10 / 4 /
cstat->max_tx_udp_payload_size) *
NGTCP2_SECONDS;
cubic->current.k >>= 10;
} else {
cubic->current.k = 0;
}
assert(cubic->current.w_max >= cstat->cwnd);
cwnd_delta = cubic->current.w_max - cstat->cwnd;
cubic->current.k_m =
ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 / cstat->max_tx_udp_payload_size);
ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
"reduce cwnd because of packet loss cwnd=%" PRIu64,

View file

@ -326,27 +326,14 @@ void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
typedef enum ngtcp2_cubic_state {
/* NGTCP2_CUBIC_STATE_INITIAL is the state where CUBIC is in slow
start phase, or congestion avoidance phase before congestion
events occur. */
NGTCP2_CUBIC_STATE_INITIAL,
/* NGTCP2_CUBIC_STATE_RECOVERY is the state that a connection is in
recovery period. */
NGTCP2_CUBIC_STATE_RECOVERY,
/* NGTCP2_CUBIC_STATE_CONGESTION_AVOIDANCE is the state where CUBIC
is in congestion avoidance phase after recovery period ends. */
NGTCP2_CUBIC_STATE_CONGESTION_AVOIDANCE,
} ngtcp2_cubic_state;
typedef struct ngtcp2_cubic_vars {
uint64_t cwnd_prior;
uint64_t w_max;
ngtcp2_duration k;
/* CUBIC K with 10 bits extra precision. */
uint64_t k_m;
ngtcp2_tstamp epoch_start;
uint64_t w_est;
ngtcp2_cubic_state state;
/* app_limited_start_ts is the timestamp where app limited period
started. */
ngtcp2_tstamp app_limited_start_ts;

View file

@ -149,3 +149,9 @@ int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
? 0
: NGTCP2_ERR_INVALID_ARGUMENT;
}
void ngtcp2_dcid_apply_validated_path(ngtcp2_dcid *dcid,
const ngtcp2_path_history_entry *ent) {
dcid->flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED;
dcid->max_udp_payload_size = ent->max_udp_payload_size;
}

View file

@ -176,4 +176,24 @@ int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
const ngtcp2_path *path,
const uint8_t *token);
/* TODO It might be performance win if we store congestion state in
this entry, and restore it when migrate back to this path. */
typedef struct ngtcp2_path_history_entry {
/* ps contains path. */
ngtcp2_path_storage ps;
/* max_udp_payload_size is the maximum size of UDP datagram payload
that is allowed to be sent to this path. */
size_t max_udp_payload_size;
/* ts is the timestamp when this entry is added to the path history.
It happens when a local endpoint migrates to the another path. */
ngtcp2_tstamp ts;
} ngtcp2_path_history_entry;
/*
* ngtcp2_dcid_apply_validated_path applies the defaults from |ent|
* which contains the validated path and its stored configurations.
*/
void ngtcp2_dcid_apply_validated_path(ngtcp2_dcid *dcid,
const ngtcp2_path_history_entry *ent);
#endif /* !defined(NGTCP2_CID_H) */

File diff suppressed because it is too large Load diff

View file

@ -110,6 +110,9 @@ typedef enum {
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
/* 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
/*
* ngtcp2_max_frame is defined so that it covers the largest ACK
@ -203,6 +206,13 @@ typedef struct ngtcp2_pktns {
/* last_pkt_num is the packet number which the local endpoint sent
last time.*/
int64_t last_pkt_num;
struct {
/* next_pkt_num is the next packet number to skip. */
int64_t next_pkt_num;
/* exponent makes gap of skipping packets spread
exponentially. */
int64_t exponent;
} skip_pkt;
ngtcp2_frame_chain *frq;
/* non_ack_pkt_start_ts is the timestamp since the local endpoint
starts sending continuous non ACK-eliciting packets. */
@ -308,6 +318,8 @@ typedef struct ngtcp2_early_transport_params {
ngtcp2_static_ringbuf_def(path_challenge, 4,
sizeof(ngtcp2_path_challenge_entry))
ngtcp2_static_ringbuf_def(path_history, 4, sizeof(ngtcp2_path_history_entry))
ngtcp2_objalloc_decl(strm, ngtcp2_strm, oplent)
struct ngtcp2_conn {
@ -625,6 +637,10 @@ struct ngtcp2_conn {
ngtcp2_cc_cubic cubic;
ngtcp2_cc_bbr bbr;
};
/* path_history remembers the paths that have been validated
successfully. The path is added to this history when a local
endpoint migrates to the another path. */
ngtcp2_static_ringbuf_path_history path_history;
const ngtcp2_mem *mem;
/* idle_ts is the time instant when idle timer started. */
ngtcp2_tstamp idle_ts;
@ -801,7 +817,8 @@ ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn);
ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
int pkt_info_version, ngtcp2_pkt_info *pi,
uint8_t *dest, size_t destlen,
ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts);
uint8_t wflags, ngtcp2_vmsg *vmsg,
ngtcp2_tstamp ts);
/*
* ngtcp2_conn_write_single_frame_pkt writes a packet which contains
@ -1094,4 +1111,11 @@ void ngtcp2_conn_discard_initial_state(ngtcp2_conn *conn, ngtcp2_tstamp ts);
*/
void ngtcp2_conn_discard_handshake_state(ngtcp2_conn *conn, ngtcp2_tstamp ts);
void ngtcp2_conn_add_path_history(ngtcp2_conn *conn, const ngtcp2_dcid *dcid,
ngtcp2_tstamp ts);
const ngtcp2_path_history_entry *
ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path,
ngtcp2_tstamp ts);
#endif /* !defined(NGTCP2_CONN_H) */

View file

@ -116,13 +116,13 @@ typedef struct ngtcp2_conn_stat {
*/
uint64_t delivery_rate_sec;
/**
* :member:`pacing_interval` is the inverse of pacing rate, which is
* the current packet sending rate computed by a congestion
* :member:`pacing_interval_m` is the inverse of pacing rate, which
* is the current packet sending rate computed by a congestion
* controller. 0 if a congestion controller does not set pacing
* interval. Even if this value is set to 0, the library paces
* packets.
* packets. The unit of this value is 1/1024 of nanoseconds.
*/
ngtcp2_duration pacing_interval;
uint64_t pacing_interval_m;
/**
* :member:`send_quantum` is the maximum size of a data aggregate
* scheduled and transmitted together.

View file

@ -157,10 +157,11 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest,
return 0;
}
static int verify_stateless_reset(const ngtcp2_ringbuf *rb,
int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
const ngtcp2_path *path,
const uint8_t *token) {
const ngtcp2_dcid *dcid;
const ngtcp2_ringbuf *rb = &dtr->bound.rb;
size_t i, len = ngtcp2_ringbuf_len(rb);
for (i = 0; i < len; ++i) {
@ -173,19 +174,6 @@ static int verify_stateless_reset(const ngtcp2_ringbuf *rb,
return NGTCP2_ERR_INVALID_ARGUMENT;
}
int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr,
const ngtcp2_path *path,
const uint8_t *token) {
int rv;
rv = verify_stateless_reset(&dtr->retired.rb, path, token);
if (rv == 0) {
return 0;
}
return verify_stateless_reset(&dtr->bound.rb, path, token);
}
static int verify_token_uniqueness(const ngtcp2_ringbuf *rb, int *pfound,
uint64_t seq, const ngtcp2_cid *cid,
const uint8_t *token) {

View file

@ -340,4 +340,4 @@ int ngtcp2_dcidtr_unused_empty(const ngtcp2_dcidtr *dtr);
*/
int ngtcp2_dcidtr_bound_full(const ngtcp2_dcidtr *dtr);
#endif /* NGTCP2_DCIDTR_H */
#endif /* !defined(NGTCP2_DCIDTR_H) */

View file

@ -292,8 +292,11 @@ void ngtcp2_ksl_clear(ngtcp2_ksl *ksl);
/*
* ngtcp2_ksl_nth_node returns the |n|th node under |blk|.
*/
#define ngtcp2_ksl_nth_node(KSL, BLK, N) \
((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
static inline ngtcp2_ksl_node *ngtcp2_ksl_nth_node(const ngtcp2_ksl *ksl,
const ngtcp2_ksl_blk *blk,
size_t n) {
return (ngtcp2_ksl_node *)(void *)(blk->nodes + ksl->nodelen * n);
}
#ifndef WIN32
/*
@ -315,18 +318,21 @@ void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
* |it| points to. It is undefined to call this function when
* ngtcp2_ksl_it_end(it) returns nonzero.
*/
#define ngtcp2_ksl_it_get(IT) \
ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data
static inline void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it) {
return ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->data;
}
/*
* ngtcp2_ksl_it_next advances the iterator by one. It is undefined
* if this function is called when ngtcp2_ksl_it_end(it) returns
* nonzero.
*/
#define ngtcp2_ksl_it_next(IT) \
(++(IT)->i == (IT)->blk->n && (IT)->blk->next \
? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \
: 0)
static inline void ngtcp2_ksl_it_next(ngtcp2_ksl_it *it) {
if (++it->i == it->blk->n && it->blk->next) {
it->blk = it->blk->next;
it->i = 0;
}
}
/*
* ngtcp2_ksl_it_prev moves backward the iterator by one. It is
@ -339,8 +345,9 @@ void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it);
* ngtcp2_ksl_it_end returns nonzero if |it| points to the one beyond
* the last node.
*/
#define ngtcp2_ksl_it_end(IT) \
((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
static inline int ngtcp2_ksl_it_end(const ngtcp2_ksl_it *it) {
return it->blk->n == it->i && it->blk->next == NULL;
}
/*
* ngtcp2_ksl_it_begin returns nonzero if |it| points to the first
@ -354,8 +361,9 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it);
* It is undefined to call this function when ngtcp2_ksl_it_end(it)
* returns nonzero.
*/
#define ngtcp2_ksl_it_key(IT) \
((ngtcp2_ksl_key *)ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
static inline ngtcp2_ksl_key *ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it) {
return (ngtcp2_ksl_key *)ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->key;
}
/*
* ngtcp2_ksl_range_compar is an implementation of ngtcp2_ksl_compar.

View file

@ -594,9 +594,9 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) {
return;
}
memset(&shd, 0, sizeof(shd));
shd.type = NGTCP2_PKT_STATELESS_RESET;
shd = (ngtcp2_pkt_hd){
.type = NGTCP2_PKT_STATELESS_RESET,
};
log->log_printf(
log->user_data, (NGTCP2_LOG_PKT " token=0x%s randlen=%zu"),

View file

@ -33,10 +33,11 @@
#define NGTCP2_INITIAL_HASHBITS 4
void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem) {
map->mem = mem;
map->hashbits = 0;
map->table = NULL;
map->seed = seed;
map->size = 0;
}
@ -77,8 +78,14 @@ int ngtcp2_map_each(const ngtcp2_map *map, int (*func)(void *data, void *ptr),
return 0;
}
static size_t hash(ngtcp2_map_key_type key, size_t bits) {
return (size_t)((key * 11400714819323198485llu) >> (64 - bits));
static size_t map_hash(const ngtcp2_map *map, ngtcp2_map_key_type key) {
/* hasher from
https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
We do not perform finalization here because we use top bits
anyway. */
key += map->seed;
key *= 0xf1357aea2e62a9c5ull;
return (size_t)((key * 11400714819323198485llu) >> (64 - map->hashbits));
}
static void map_bucket_swap(ngtcp2_map_bucket *a, ngtcp2_map_bucket *b) {
@ -109,28 +116,28 @@ void ngtcp2_map_print_distance(const ngtcp2_map *map) {
continue;
}
idx = hash(bkt->key, map->hashbits);
idx = map_hash(map, bkt->key);
fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl);
map_hash(map, bkt->key), bkt->key, idx, bkt->psl);
}
}
#endif /* !defined(WIN32) */
static int insert(ngtcp2_map_bucket *table, size_t hashbits,
ngtcp2_map_key_type key, void *data) {
size_t idx = hash(key, hashbits);
static int map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
size_t idx = map_hash(map, key);
ngtcp2_map_bucket b = {
.key = key,
.data = data,
};
ngtcp2_map_bucket *bkt;
size_t mask = (1u << hashbits) - 1;
size_t mask = (1u << map->hashbits) - 1;
for (;;) {
bkt = &table[idx];
bkt = &map->table[idx];
if (bkt->data == NULL) {
*bkt = b;
++map->size;
return 0;
}
@ -151,15 +158,19 @@ static int insert(ngtcp2_map_bucket *table, size_t hashbits,
static int map_resize(ngtcp2_map *map, size_t new_hashbits) {
size_t i;
ngtcp2_map_bucket *new_table;
ngtcp2_map_bucket *bkt;
size_t tablelen;
int rv;
ngtcp2_map new_map = {
.table = ngtcp2_mem_calloc(map->mem, 1u << new_hashbits,
sizeof(ngtcp2_map_bucket)),
.mem = map->mem,
.seed = map->seed,
.hashbits = new_hashbits,
};
(void)rv;
new_table =
ngtcp2_mem_calloc(map->mem, 1u << new_hashbits, sizeof(ngtcp2_map_bucket));
if (new_table == NULL) {
if (new_map.table == NULL) {
return NGTCP2_ERR_NOMEM;
}
@ -172,15 +183,15 @@ static int map_resize(ngtcp2_map *map, size_t new_hashbits) {
continue;
}
rv = insert(new_table, new_hashbits, bkt->key, bkt->data);
rv = map_insert(&new_map, bkt->key, bkt->data);
assert(0 == rv);
}
}
ngtcp2_mem_free(map->mem, map->table);
map->table = new_map.table;
map->hashbits = new_hashbits;
map->table = new_table;
return 0;
}
@ -190,10 +201,10 @@ int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
assert(data);
/* Load factor is 0.75 */
/* Load factor is 7/8 */
/* Under the very initial condition, that is map->size == 0 and
map->hashbits == 0, 4 > 3 still holds nicely. */
if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) {
map->hashbits == 0, 8 > 7 still holds nicely. */
if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) {
if (map->hashbits) {
rv = map_resize(map, map->hashbits + 1);
if (rv != 0) {
@ -207,13 +218,11 @@ int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
}
}
rv = insert(map->table, map->hashbits, key, data);
rv = map_insert(map, key, data);
if (rv != 0) {
return rv;
}
++map->size;
return 0;
}
@ -227,7 +236,7 @@ void *ngtcp2_map_find(const ngtcp2_map *map, ngtcp2_map_key_type key) {
return NULL;
}
idx = hash(key, map->hashbits);
idx = map_hash(map, key);
mask = (1u << map->hashbits) - 1;
for (;;) {
@ -256,7 +265,7 @@ int ngtcp2_map_remove(ngtcp2_map *map, ngtcp2_map_key_type key) {
return NGTCP2_ERR_INVALID_ARGUMENT;
}
idx = hash(key, map->hashbits);
idx = map_hash(map, key);
mask = (1u << map->hashbits) - 1;
for (;;) {

View file

@ -47,6 +47,7 @@ typedef struct ngtcp2_map_bucket {
typedef struct ngtcp2_map {
ngtcp2_map_bucket *table;
const ngtcp2_mem *mem;
uint64_t seed;
size_t size;
size_t hashbits;
} ngtcp2_map;
@ -54,7 +55,7 @@ typedef struct ngtcp2_map {
/*
* ngtcp2_map_init initializes the map |map|.
*/
void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem);
void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem);
/*
* ngtcp2_map_free deallocates any resources allocated for |map|. The

View file

@ -304,11 +304,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt,
}
ngtcp2_get_uvarint(&vi, p);
#if SIZE_MAX > UINT32_MAX
#if SIZE_MAX < UINT64_MAX
if (vi > SIZE_MAX) {
return NGTCP2_ERR_INVALID_ARGUMENT;
}
#endif /* SIZE_MAX > UINT32_MAX */
#endif /* SIZE_MAX < UINT64_MAX */
longlen = (size_t)vi;
}
@ -2080,8 +2080,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_datagram_frame(uint8_t *out, size_t outlen,
}
for (i = 0; i < fr->datacnt; ++i) {
assert(fr->data[i].len);
assert(fr->data[i].base);
if (fr->data[i].len == 0) {
continue;
}
p = ngtcp2_cpymem(p, fr->data[i].base, fr->data[i].len);
}
@ -2421,9 +2423,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset,
left -= n;
if (left > 8 + 1073741823 && len > 1073741823) {
#if SIZE_MAX > UINT32_MAX
len = ngtcp2_min_uint64(len, 4611686018427387903lu);
#endif /* SIZE_MAX > UINT32_MAX */
return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 8));
}
@ -2453,9 +2453,9 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) {
left -= n;
if (left > 8 + 1073741823 && len > 1073741823) {
#if SIZE_MAX > UINT32_MAX
#if SIZE_MAX == UINT64_MAX
len = ngtcp2_min_size(len, 4611686018427387903lu);
#endif /* SIZE_MAX > UINT32_MAX */
#endif /* SIZE_MAX == UINT64_MAX */
return ngtcp2_min_size(len, left - 8);
}

View file

@ -137,6 +137,13 @@
v2. */
#define NGTCP2_PKT_TYPE_RETRY_V2 0x0
/* NGTCP2_MIN_STREAM_DATALEN is the minimum length of STREAM frame to
avoid too small frame. It is not always enforced for various
reasons. For example, due to flow control, we might have fewer
bytes available to send. Therefore, it is only applied when the
length of data to send is larger than this limit. */
#define NGTCP2_MIN_STREAM_DATALEN 256
typedef struct ngtcp2_pkt_retry {
ngtcp2_cid odcid;
uint8_t *token;

View file

@ -47,9 +47,10 @@ void ngtcp2_ppe_init(ngtcp2_ppe *ppe, uint8_t *out, size_t outlen,
int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) {
ngtcp2_ssize rv;
ngtcp2_buf *buf = &ppe->buf;
size_t buf_left = ngtcp2_buf_left(buf);
ngtcp2_crypto_cc *cc = ppe->cc;
if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) {
if (buf_left <= cc->aead.max_overhead) {
return NGTCP2_ERR_NOBUF;
}
@ -62,13 +63,13 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) {
ppe->pkt_num_offset = ppe->len_offset + NGTCP2_PKT_LENGTHLEN;
rv = ngtcp2_pkt_encode_hd_long(
buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd);
rv = ngtcp2_pkt_encode_hd_long(buf->last, buf_left - cc->aead.max_overhead,
hd);
} else {
ppe->pkt_num_offset = 1 + hd->dcid.datalen;
rv = ngtcp2_pkt_encode_hd_short(
buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd);
rv = ngtcp2_pkt_encode_hd_short(buf->last, buf_left - cc->aead.max_overhead,
hd);
}
if (rv < 0) {
@ -87,14 +88,14 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) {
int ngtcp2_ppe_encode_frame(ngtcp2_ppe *ppe, ngtcp2_frame *fr) {
ngtcp2_ssize rv;
ngtcp2_buf *buf = &ppe->buf;
size_t buf_left = ngtcp2_buf_left(buf);
ngtcp2_crypto_cc *cc = ppe->cc;
if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) {
if (buf_left <= cc->aead.max_overhead) {
return NGTCP2_ERR_NOBUF;
}
rv = ngtcp2_pkt_encode_frame(
buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, fr);
rv = ngtcp2_pkt_encode_frame(buf->last, buf_left - cc->aead.max_overhead, fr);
if (rv < 0) {
return (int)rv;
}
@ -172,18 +173,13 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) {
size_t ngtcp2_ppe_left(const ngtcp2_ppe *ppe) {
ngtcp2_crypto_cc *cc = ppe->cc;
size_t buf_left = ngtcp2_buf_left(&ppe->buf);
if (ngtcp2_buf_left(&ppe->buf) < cc->aead.max_overhead) {
if (buf_left <= cc->aead.max_overhead) {
return 0;
}
return ngtcp2_buf_left(&ppe->buf) - cc->aead.max_overhead;
}
size_t ngtcp2_ppe_pktlen(const ngtcp2_ppe *ppe) {
ngtcp2_crypto_cc *cc = ppe->cc;
return ngtcp2_buf_len(&ppe->buf) + cc->aead.max_overhead;
return buf_left - cc->aead.max_overhead;
}
size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) {
@ -208,6 +204,10 @@ size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) {
assert(ngtcp2_buf_left(buf) >= len + cc->aead.max_overhead);
if (len == 0) {
return 0;
}
buf->last = ngtcp2_setmem(buf->last, 0, len);
return len;

View file

@ -110,12 +110,6 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt);
*/
size_t ngtcp2_ppe_left(const ngtcp2_ppe *ppe);
/*
* ngtcp2_ppe_pktlen returns the provisional packet length. It
* includes AEAD overhead.
*/
size_t ngtcp2_ppe_pktlen(const ngtcp2_ppe *ppe);
/*
* ngtcp2_ppe_dgram_padding is equivalent to call
* ngtcp2_ppe_dgram_padding_size(ppe, NGTCP2_MAX_UDP_PAYLOAD_SIZE).

View file

@ -110,7 +110,9 @@ void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len);
void *ngtcp2_ringbuf_get(const ngtcp2_ringbuf *rb, size_t offset);
/* ngtcp2_ringbuf_len returns the number of elements stored. */
#define ngtcp2_ringbuf_len(RB) ((RB)->len)
static inline size_t ngtcp2_ringbuf_len(const ngtcp2_ringbuf *rb) {
return rb->len;
}
/* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
int ngtcp2_ringbuf_full(const ngtcp2_ringbuf *rb);

View file

@ -38,7 +38,6 @@ void ngtcp2_rs_init(ngtcp2_rs *rs) {
rs->prior_ts = UINT64_MAX;
rs->tx_in_flight = 0;
rs->lost = 0;
rs->prior_lost = 0;
rs->send_elapsed = 0;
rs->ack_elapsed = 0;
rs->last_end_seq = -1;
@ -58,7 +57,6 @@ void ngtcp2_rst_reset(ngtcp2_rst *rst) {
rst->app_limited = 0;
rst->is_cwnd_limited = 0;
rst->lost = 0;
rst->valid_after_seq = rst->last_seq;
}
void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
@ -89,7 +87,6 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
rs->interval = ngtcp2_max_uint64(rs->send_elapsed, rs->ack_elapsed);
rs->delivered = rst->delivered - rs->prior_delivered;
rs->lost = rst->lost - rs->prior_lost;
if (rs->interval < cstat->min_rtt) {
rs->interval = UINT64_MAX;
@ -103,31 +100,23 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
cstat->delivery_rate_sec = rs->delivered * NGTCP2_SECONDS / rs->interval;
}
static int rst_is_newest_pkt(const ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
const ngtcp2_rs *rs) {
return ent->ts > rst->first_sent_ts ||
(ent->ts == rst->first_sent_ts && ent->rst.end_seq > rs->last_end_seq);
static int is_newest_pkt(const ngtcp2_rtb_entry *ent, const ngtcp2_rs *rs) {
return ent->rst.end_seq > rs->last_end_seq;
}
void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
ngtcp2_tstamp ts) {
ngtcp2_rs *rs = &rst->rs;
if (ent->rst.end_seq <= rst->valid_after_seq) {
return;
}
rst->delivered += ent->pktlen;
rst->delivered_ts = ts;
if (rs->prior_ts == UINT64_MAX || rst_is_newest_pkt(rst, ent, rs)) {
if (rs->prior_ts == UINT64_MAX || is_newest_pkt(ent, rs)) {
rs->prior_delivered = ent->rst.delivered;
rs->prior_ts = ent->rst.delivered_ts;
rs->is_app_limited = ent->rst.is_app_limited;
rs->send_elapsed = ent->ts - ent->rst.first_sent_ts;
rs->ack_elapsed = rst->delivered_ts - ent->rst.delivered_ts;
rs->tx_in_flight = ent->rst.tx_in_flight;
rs->prior_lost = ent->rst.lost;
rs->last_end_seq = ent->rst.end_seq;
rst->first_sent_ts = ent->ts;
}

View file

@ -48,7 +48,6 @@ typedef struct ngtcp2_rs {
ngtcp2_tstamp prior_ts;
uint64_t tx_in_flight;
uint64_t lost;
uint64_t prior_lost;
ngtcp2_duration send_elapsed;
ngtcp2_duration ack_elapsed;
int64_t last_end_seq;
@ -73,10 +72,6 @@ typedef struct ngtcp2_rst {
across all packet number spaces, we can replace this with a
packet number. */
int64_t last_seq;
/* valid_after_seq is the sequence number, and ignore a packet if
the sequence number of the packet is less than or equal to this
number. */
int64_t valid_after_seq;
int is_cwnd_limited;
} ngtcp2_rst;

View file

@ -43,16 +43,19 @@ ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent)
static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd,
ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
size_t pktlen, uint16_t flags) {
memset(ent, 0, sizeof(*ent));
ent->hd.pkt_num = hd->pkt_num;
ent->hd.type = hd->type;
ent->hd.flags = hd->flags;
ent->frc = frc;
ent->ts = ts;
ent->lost_ts = UINT64_MAX;
ent->pktlen = pktlen;
ent->flags = flags;
*ent = (ngtcp2_rtb_entry){
.hd =
{
.pkt_num = hd->pkt_num,
.type = hd->type,
.flags = hd->flags,
},
.frc = frc,
.ts = ts,
.lost_ts = UINT64_MAX,
.pktlen = pktlen,
.flags = flags,
};
}
int ngtcp2_rtb_entry_objalloc_new(ngtcp2_rtb_entry **pent,
@ -102,7 +105,7 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_rst *rst, ngtcp2_cc *cc,
rtb->cc_pkt_num = cc_pkt_num;
rtb->cc_bytes_in_flight = 0;
rtb->num_lost_pkts = 0;
rtb->num_lost_pmtud_pkts = 0;
rtb->num_lost_ignore_pkts = 0;
}
void ngtcp2_rtb_free(ngtcp2_rtb *rtb) {
@ -153,9 +156,10 @@ static size_t rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
assert(rtb->num_lost_pkts);
--rtb->num_lost_pkts;
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) {
assert(rtb->num_lost_pmtud_pkts);
--rtb->num_lost_pmtud_pkts;
if (ent->flags &
(NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
assert(rtb->num_lost_ignore_pkts);
--rtb->num_lost_ignore_pkts;
}
return 0;
@ -244,22 +248,17 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags,
fr->stream.offset + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt);
range = ngtcp2_range_intersect(&range, &gap);
if (ngtcp2_range_len(&range) == 0) {
if (!fr->stream.fin) {
if (ngtcp2_range_len(&range) == 0 && !fr->stream.fin &&
/* 0 length STREAM frame with offset == 0 must be
retransmitted if no non-empty data are sent to this
stream, fin flag is not set, and no data in this stream
are acknowledged. */
if (fr->stream.offset != 0 || fr->stream.datacnt != 0 ||
(fr->stream.offset != 0 || fr->stream.datacnt != 0 ||
strm->tx.offset ||
(strm->flags &
(NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_ANY_ACKED))) {
(NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_ANY_ACKED)))) {
continue;
}
} else if (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED) {
continue;
}
}
if ((flags & NGTCP2_RECLAIM_FLAG_ON_LOSS) &&
ent->hd.pkt_num != strm->tx.last_lost_pkt_num) {
@ -443,16 +442,22 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
ngtcp2_cc *cc = rtb->cc;
ngtcp2_cc_pkt pkt;
if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags,
ent->ts);
if (rtb->qlog) {
ngtcp2_qlog_pkt_lost(rtb->qlog, ent);
}
}
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) {
++rtb->num_lost_pmtud_pkts;
} else if (rtb->cc->on_pkt_lost) {
if (ent->flags &
(NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
++rtb->num_lost_ignore_pkts;
} else if (ent->hd.pkt_num >= rtb->cc_pkt_num) {
rtb->rst->lost += ent->pktlen;
if (rtb->cc->on_pkt_lost) {
cc->on_pkt_lost(cc, cstat,
ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
pktns->id, ent->ts, ent->rst.lost,
@ -460,6 +465,7 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
ent->rst.is_app_limited),
ts);
}
}
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
@ -705,6 +711,8 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
ngtcp2_cc *cc = rtb->cc;
ngtcp2_cc_pkt pkt;
assert(ent->hd.pkt_num >= rtb->cc_pkt_num);
ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts);
if (cc->on_pkt_acked) {
@ -786,7 +794,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
size_t ecn_acked = 0;
int verify_ecn = 0;
ngtcp2_cc_ack cc_ack = {0};
size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_pmtud_pkts;
size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_ignore_pkts;
cc_ack.prior_bytes_in_flight = cstat->bytes_in_flight;
cc_ack.rtt = UINT64_MAX;
@ -830,6 +838,11 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
ent = ngtcp2_ksl_it_get(&it);
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP) {
rv = NGTCP2_ERR_PROTO;
goto fail;
}
if (largest_ack == pkt_num) {
largest_pkt_sent_ts = ent->ts;
}
@ -839,7 +852,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
}
rtb_remove(rtb, &it, &acked_ent, ent, cstat);
++num_acked;
}
for (i = 0; i < fr->rangecnt; ++i) {
@ -859,12 +871,16 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
ent = ngtcp2_ksl_it_get(&it);
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP) {
rv = NGTCP2_ERR_PROTO;
goto fail;
}
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
ack_eliciting_pkt_acked = 1;
}
rtb_remove(rtb, &it, &acked_ent, ent, cstat);
++num_acked;
}
}
@ -873,7 +889,8 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
ngtcp2_max_uint64(pkt_ts - largest_pkt_sent_ts, NGTCP2_NANOSECONDS);
rv = ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
if (rv == 0 && cc->new_rtt_sample) {
if (rv == 0 && cc->new_rtt_sample &&
rtb->largest_acked_tx_pkt_num >= rtb->cc_pkt_num) {
cc->new_rtt_sample(cc, cstat, ts);
}
}
@ -895,9 +912,12 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
cc_ack.bytes_delivered += ent->pktlen;
cc_ack.pkt_delivered = ent->rst.delivered;
}
rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
++num_acked;
}
acked_ent = ent->next;
ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
rtb->frc_objalloc, rtb->mem);
@ -912,13 +932,14 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
for (ent = acked_ent; ent; ent = acked_ent) {
rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
acked_ent = ent->next;
++num_acked;
ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
rtb->frc_objalloc, rtb->mem);
}
}
if (rtb->cc->on_spurious_congestion && num_lost_pkts &&
rtb->num_lost_pkts == rtb->num_lost_pmtud_pkts) {
rtb->num_lost_pkts == rtb->num_lost_ignore_pkts) {
rtb->cc->on_spurious_congestion(cc, cstat, ts);
}
@ -933,8 +954,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
}
}
rtb->rst->lost += cc_ack.bytes_lost;
cc_ack.largest_pkt_sent_ts = largest_pkt_sent_ts;
if (num_acked && cc->on_ack_recv) {
cc->on_ack_recv(cc, cstat, &cc_ack, ts);
@ -1189,8 +1208,9 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
--rtb->num_lost_pkts;
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) {
--rtb->num_lost_pmtud_pkts;
if (ent->flags &
(NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
--rtb->num_lost_ignore_pkts;
}
rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num);
@ -1200,27 +1220,28 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
}
}
void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb,
ngtcp2_duration timeout,
ngtcp2_tstamp ts) {
ngtcp2_ksl_it it;
ngtcp2_rtb_entry *ent;
int rv;
(void)rv;
if (ngtcp2_ksl_len(&rtb->ents) == 0) {
if (rtb->num_lost_pkts == 0) {
return;
}
it = ngtcp2_ksl_end(&rtb->ents);
for (;;) {
for (; rtb->num_lost_pkts;) {
assert(ngtcp2_ksl_it_end(&it));
ngtcp2_ksl_it_prev(&it);
ent = ngtcp2_ksl_it_get(&it);
if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) ||
ts - ent->lost_ts < pto) {
ts - ent->lost_ts < timeout) {
return;
}
@ -1229,18 +1250,15 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
--rtb->num_lost_pkts;
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) {
--rtb->num_lost_pmtud_pkts;
if (ent->flags &
(NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
--rtb->num_lost_ignore_pkts;
}
rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num);
assert(0 == rv);
ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
rtb->frc_objalloc, rtb->mem);
if (ngtcp2_ksl_len(&rtb->ents) == 0) {
return;
}
}
}
@ -1263,60 +1281,14 @@ ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(const ngtcp2_rtb *rtb) {
return ent->lost_ts;
}
static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
static int rtb_reclaim_frame_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
ngtcp2_pktns *pktns,
ngtcp2_rtb_entry *ent) {
ngtcp2_frame_chain **pfrc, *frc;
ngtcp2_frame_chain **pfrc = &ent->frc, *frc;
ngtcp2_stream *sfr;
ngtcp2_strm *strm;
int rv;
ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags,
ent->ts);
if (rtb->qlog) {
ngtcp2_qlog_pkt_lost(rtb->qlog, ent);
}
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE) {
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
"pkn=%" PRId64
" is a probe packet, no retransmission is necessary",
ent->hd.pkt_num);
return 0;
}
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) {
--rtb->num_lost_pkts;
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) {
--rtb->num_lost_pmtud_pkts;
}
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
"pkn=%" PRId64
" was declared lost and has already been retransmitted",
ent->hd.pkt_num);
return 0;
}
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
"pkn=%" PRId64 " has already been reclaimed on PTO",
ent->hd.pkt_num);
return 0;
}
if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) &&
(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) ||
!conn->callbacks.lost_datagram)) {
/* PADDING only (or PADDING + ACK ) packets will have NULL
ent->frc. */
return 0;
}
pfrc = &ent->frc;
for (; *pfrc;) {
switch ((*pfrc)->fr.type) {
case NGTCP2_FRAME_STREAM:
@ -1390,14 +1362,12 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
return 0;
}
int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
int ngtcp2_rtb_reclaim_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat) {
ngtcp2_rtb_entry *ent;
ngtcp2_ksl_it it;
ngtcp2_ksl_it it = ngtcp2_ksl_begin(&rtb->ents);
int rv;
it = ngtcp2_ksl_begin(&rtb->ents);
for (; !ngtcp2_ksl_it_end(&it);) {
ent = ngtcp2_ksl_it_get(&it);
@ -1405,7 +1375,42 @@ int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num);
assert(0 == rv);
rv = rtb_on_pkt_lost_resched_move(rtb, conn, pktns, ent);
if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type,
ent->hd.flags, ent->ts);
if (rtb->qlog) {
ngtcp2_qlog_pkt_lost(rtb->qlog, ent);
}
}
/* We never send PING only probe packet because we should have
CRYPTO data or just nothing. If we have nothing, then we do
not send probe packet. */
assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE));
/* We never get ACK before Retry packet. */
assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED));
assert(0 == rtb->num_lost_pkts);
assert(0 == rtb->num_lost_ignore_pkts);
/* PMTUD probe must not be sent before handshake completion. */
assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE));
if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC,
"pkn=%" PRId64 " has already been reclaimed on PTO",
ent->hd.pkt_num);
continue;
}
if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) &&
(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) ||
!conn->callbacks.lost_datagram)) {
continue;
}
rv = rtb_reclaim_frame_on_retry(rtb, conn, pktns, ent);
ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
rtb->frc_objalloc, rtb->mem);

View file

@ -80,6 +80,9 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
/* 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
/* NGTCP2_RTB_ENTRY_FLAG_SKIP indicates that the entry has the skipped
packet number. */
#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200u
typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry;
@ -187,10 +190,11 @@ typedef struct ngtcp2_rtb {
/* num_lost_pkts is the number entries in ents which has
NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set. */
size_t num_lost_pkts;
/* num_lost_pmtud_pkts is the number of entries in ents which have
both NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED and
NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE flags set. */
size_t num_lost_pmtud_pkts;
/* num_lost_ignore_pkts is the number of entries in ents which have
NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set, and should be
excluded from lost byte count. If only those packets are lost,
congestion event is not triggered. */
size_t num_lost_ignore_pkts;
} ngtcp2_rtb;
/*
@ -258,7 +262,8 @@ int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
/*
* ngtcp2_rtb_remove_expired_lost_pkt removes expired lost packet.
*/
void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb,
ngtcp2_duration timeout,
ngtcp2_tstamp ts);
/*
@ -269,11 +274,11 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(const ngtcp2_rtb *rtb);
/*
* ngtcp2_rtb_remove_all removes all packets from |rtb|, and prepends
* all frames to |*pfrc|. Even when this function fails, some frames
* might be prepended to |*pfrc|, and the caller should handle them.
* ngtcp2_rtb_reclaim_on_retry is called when Retry packet is
* received. It removes all packets from |rtb|, and retransmittable
* frames are reclaimed for retransmission.
*/
int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
int ngtcp2_rtb_reclaim_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat);
/*

View file

@ -120,7 +120,7 @@ uint64_t ngtcp2_strm_rx_offset(const ngtcp2_strm *strm) {
/* strm_rob_heavily_fragmented returns nonzero if the number of gaps
in |rob| exceeds the limit. */
static int strm_rob_heavily_fragmented(const ngtcp2_rob *rob) {
return ngtcp2_ksl_len(&rob->gapksl) >= 5000;
return ngtcp2_ksl_len(&rob->gapksl) >= 1000;
}
int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
@ -138,11 +138,16 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
}
}
rv = ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
if (rv != 0) {
return rv;
}
if (strm_rob_heavily_fragmented(strm->rx.rob)) {
return NGTCP2_ERR_INTERNAL;
}
return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
return 0;
}
void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) {
@ -196,6 +201,8 @@ int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
if (rv != 0) {
return rv;
}
} else if (ngtcp2_ksl_len(strm->tx.streamfrq) >= 1000) {
return NGTCP2_ERR_INTERNAL;
}
return ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
@ -398,7 +405,11 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
/* datalen could be zero if 0 length STREAM has been sent */
if (left == 0 && datalen) {
/* We might see more data in the queue, then left < datalen could be
true. We only see the first one for now. */
if ((fr->type == NGTCP2_FRAME_STREAM &&
(left < datalen && left < NGTCP2_MIN_STREAM_DATALEN)) ||
(left == 0 && datalen)) {
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
@ -737,7 +748,16 @@ int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len) {
}
}
return ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
rv = ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
if (rv != 0) {
return rv;
}
if (ngtcp2_ksl_len(&strm->tx.acked_offset->gap) >= 1000) {
return NGTCP2_ERR_INTERNAL;
}
return 0;
}
void ngtcp2_strm_set_app_error_code(ngtcp2_strm *strm,

View file

@ -523,12 +523,12 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version,
}
/* Set default values */
memset(params, 0, sizeof(*params));
params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE;
params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
params->active_connection_id_limit =
NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
*params = (ngtcp2_transport_params){
.max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE,
.ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT,
.max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY,
.active_connection_id_limit = NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT,
};
p = end = data;

View file

@ -33,13 +33,6 @@
#include "ngtcp2_mem.h"
/*
* ngtcp2_vec_lit is a convenient macro to fill the object pointed by
* |DEST| with the literal string |LIT|.
*/
#define ngtcp2_vec_lit(DEST, LIT) \
((DEST)->base = (uint8_t *)(LIT), (DEST)->len = sizeof(LIT) - 1, (DEST))
/*
* ngtcp2_vec_init initializes |vec| with the given parameters. It
* returns |vec|.

View file

@ -5,7 +5,7 @@
// QUIC is only available in Openssl 3.5.x and later. It was not introduced in
// Node.js until 3.5.1... prior to that we will not compile any of the QUIC
// related code.
#if OPENSSL_VERSION_NUMBER < 0x30500010
#if OPENSSL_VERSION_NUMBER < 0x30500010 || OPENSSL_IS_BORINGSSL
#define OPENSSL_NO_QUIC = 1
#endif
#else