deps: update ngtcp2 to 1.11.0

PR-URL: https://github.com/nodejs/node/pull/57179
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
This commit is contained in:
Node.js GitHub Bot 2025-02-24 19:53:20 -05:00 committed by GitHub
parent 9a97b722aa
commit 9e103b09a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1722 additions and 1213 deletions

View File

@ -331,7 +331,7 @@ ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
* :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to
* set negotiated AEAD and message digest algorithm. After the
* successful call of this function, application can use
* `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_early_crypto_ctx`
* `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_0rtt_crypto_ctx`
* if |level| ==
* :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to
* get :type:`ngtcp2_crypto_ctx`.
@ -378,7 +378,7 @@ NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_rx_key(
* :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to
* set negotiated AEAD and message digest algorithm. After the
* successful call of this function, application can use
* `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_early_crypto_ctx`
* `ngtcp2_conn_get_crypto_ctx` (or `ngtcp2_conn_get_0rtt_crypto_ctx`
* if |level| ==
* :enum:`ngtcp2_encryption_level.NGTCP2_ENCRYPTION_LEVEL_0RTT`) to
* get :type:`ngtcp2_crypto_ctx`.

View File

@ -125,7 +125,7 @@ static int supported_cipher_suite(ptls_cipher_suite_t *cs) {
#ifdef PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
|| cs->aead == &ptls_openssl_chacha20poly1305
#endif /* defined(PTLS_OPENSSL_HAVE_CHACHA20_POLY1305) */
;
;
}
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
@ -146,7 +146,7 @@ ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
ctx->hp.native_handle = (void *)crypto_cipher_suite_get_hp(cs);
ctx->max_encryption = crypto_cipher_suite_get_aead_max_encryption(cs);
ctx->max_decryption_failure =
crypto_cipher_suite_get_aead_max_decryption_failure(cs);
crypto_cipher_suite_get_aead_max_decryption_failure(cs);
return ctx;
}
@ -329,19 +329,22 @@ int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
const uint8_t *nonce, size_t noncelen,
const uint8_t *aad, size_t aadlen) {
ptls_aead_context_t *actx = aead_ctx->native_handle;
size_t nwrite;
(void)aead;
ptls_aead_xor_iv(actx, nonce, noncelen);
if (ptls_aead_decrypt(actx, dest, ciphertext, ciphertextlen, 0, aad,
aadlen) == SIZE_MAX) {
return -1;
}
nwrite =
ptls_aead_decrypt(actx, dest, ciphertext, ciphertextlen, 0, aad, aadlen);
/* zero-out static iv once again */
ptls_aead_xor_iv(actx, nonce, noncelen);
if (nwrite == SIZE_MAX) {
return -1;
}
return 0;
}
@ -360,13 +363,13 @@ int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
}
int ngtcp2_crypto_read_write_crypto_data(
ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level,
const uint8_t *data, size_t datalen) {
ngtcp2_conn *conn, ngtcp2_encryption_level encryption_level,
const uint8_t *data, size_t datalen) {
ngtcp2_crypto_picotls_ctx *cptls = ngtcp2_conn_get_tls_native_handle(conn);
ptls_buffer_t sendbuf;
size_t epoch_offsets[5] = {0};
size_t epoch =
ngtcp2_crypto_picotls_from_ngtcp2_encryption_level(encryption_level);
ngtcp2_crypto_picotls_from_ngtcp2_encryption_level(encryption_level);
size_t epoch_datalen;
size_t i;
int rv;
@ -388,7 +391,7 @@ int ngtcp2_crypto_read_write_crypto_data(
if (!ngtcp2_conn_is_server(conn) &&
cptls->handshake_properties.client.early_data_acceptance ==
PTLS_EARLY_DATA_REJECTED) {
PTLS_EARLY_DATA_REJECTED) {
rv = ngtcp2_conn_tls_early_data_rejected(conn);
if (rv != 0) {
rv = -1;
@ -405,8 +408,8 @@ int ngtcp2_crypto_read_write_crypto_data(
assert(i != 1);
if (ngtcp2_conn_submit_crypto_data(
conn, ngtcp2_crypto_picotls_from_epoch(i),
sendbuf.base + epoch_offsets[i], epoch_datalen) != 0) {
conn, ngtcp2_crypto_picotls_from_epoch(i),
sendbuf.base + epoch_offsets[i], epoch_datalen) != 0) {
rv = -1;
goto fin;
}
@ -463,7 +466,7 @@ ngtcp2_encryption_level ngtcp2_crypto_picotls_from_epoch(size_t epoch) {
}
size_t ngtcp2_crypto_picotls_from_ngtcp2_encryption_level(
ngtcp2_encryption_level encryption_level) {
ngtcp2_encryption_level encryption_level) {
switch (encryption_level) {
case NGTCP2_ENCRYPTION_LEVEL_INITIAL:
return 0;
@ -532,8 +535,8 @@ fail:
}
int ngtcp2_crypto_picotls_collect_extension(
ptls_t *ptls, struct st_ptls_handshake_properties_t *properties,
uint16_t type) {
ptls_t *ptls, struct st_ptls_handshake_properties_t *properties,
uint16_t type) {
(void)ptls;
(void)properties;
@ -541,8 +544,8 @@ int ngtcp2_crypto_picotls_collect_extension(
}
int ngtcp2_crypto_picotls_collected_extensions(
ptls_t *ptls, struct st_ptls_handshake_properties_t *properties,
ptls_raw_extension_t *extensions) {
ptls_t *ptls, struct st_ptls_handshake_properties_t *properties,
ptls_raw_extension_t *extensions) {
ngtcp2_crypto_conn_ref *conn_ref;
ngtcp2_conn *conn;
int rv;
@ -558,7 +561,7 @@ int ngtcp2_crypto_picotls_collected_extensions(
conn = conn_ref->get_conn(conn_ref);
rv = ngtcp2_conn_decode_and_set_remote_transport_params(
conn, extensions->data.base, extensions->data.len);
conn, extensions->data.base, extensions->data.len);
if (rv != 0) {
ngtcp2_conn_set_tls_error(conn, rv);
return -1;
@ -613,7 +616,7 @@ static int update_traffic_key_server_cb(ptls_update_traffic_key_t *self,
}
static ptls_update_traffic_key_t update_traffic_key_server = {
update_traffic_key_server_cb,
update_traffic_key_server_cb,
};
static int update_traffic_key_cb(ptls_update_traffic_key_t *self, ptls_t *ptls,
@ -661,7 +664,7 @@ int ngtcp2_crypto_picotls_configure_client_context(ptls_context_t *ctx) {
}
int ngtcp2_crypto_picotls_configure_server_session(
ngtcp2_crypto_picotls_ctx *cptls) {
ngtcp2_crypto_picotls_ctx *cptls) {
ptls_handshake_properties_t *hsprops = &cptls->handshake_properties;
hsprops->collect_extension = ngtcp2_crypto_picotls_collect_extension;
@ -671,7 +674,7 @@ int ngtcp2_crypto_picotls_configure_server_session(
}
int ngtcp2_crypto_picotls_configure_client_session(
ngtcp2_crypto_picotls_ctx *cptls, ngtcp2_conn *conn) {
ngtcp2_crypto_picotls_ctx *cptls, ngtcp2_conn *conn) {
ptls_handshake_properties_t *hsprops = &cptls->handshake_properties;
hsprops->client.max_early_data_size = calloc(1, sizeof(size_t));
@ -692,7 +695,7 @@ int ngtcp2_crypto_picotls_configure_client_session(
}
void ngtcp2_crypto_picotls_deconfigure_session(
ngtcp2_crypto_picotls_ctx *cptls) {
ngtcp2_crypto_picotls_ctx *cptls) {
ptls_handshake_properties_t *hsprops;
ptls_raw_extension_t *exts;

View File

@ -167,8 +167,12 @@ typedef void *(*ngtcp2_realloc)(void *ptr, size_t size, void *user_data);
* }
*
* void conn_new() {
* ngtcp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb,
* my_realloc_cb};
* ngtcp2_mem mem = {
* .malloc = my_malloc_cb,
* .free = my_free_cb,
* .calloc = my_calloc_cb,
* .realloc = my_realloc_cb,
* };
*
* ...
* }

View File

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

View File

@ -25,6 +25,7 @@
#include "ngtcp2_acktr.h"
#include <assert.h>
#include <string.h>
#include "ngtcp2_macro.h"
#include "ngtcp2_tstamp.h"
@ -70,6 +71,9 @@ void ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log,
acktr->flags = NGTCP2_ACKTR_FLAG_NONE;
acktr->first_unacked_ts = UINT64_MAX;
acktr->rx_npkt = 0;
acktr->max_pkt_num = -1;
acktr->max_pkt_ts = UINT64_MAX;
memset(&acktr->ecn, 0, sizeof(acktr->ecn));
}
void ngtcp2_acktr_free(ngtcp2_acktr *acktr) {
@ -180,6 +184,11 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack,
ngtcp2_acktr_entry_objalloc_del(delent, &acktr->objalloc);
}
if (acktr->max_pkt_num < pkt_num) {
acktr->max_pkt_num = pkt_num;
acktr->max_pkt_ts = ts;
}
return 0;
}
@ -323,3 +332,108 @@ int ngtcp2_acktr_require_active_ack(const ngtcp2_acktr *acktr,
void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) {
acktr->flags |= NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK;
}
ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
ngtcp2_frame *fr, uint8_t type,
ngtcp2_tstamp ts,
ngtcp2_duration ack_delay,
uint64_t ack_delay_exponent) {
int64_t last_pkt_num;
ngtcp2_ack_range *range;
ngtcp2_ksl_it it;
ngtcp2_acktr_entry *rpkt;
ngtcp2_ack *ack = &fr->ack;
ngtcp2_tstamp largest_ack_ts;
size_t num_acks;
if (acktr->flags & NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK) {
ack_delay = 0;
}
if (!ngtcp2_acktr_require_active_ack(acktr, ack_delay, ts)) {
return NULL;
}
it = ngtcp2_acktr_get(acktr);
if (ngtcp2_ksl_it_end(&it)) {
ngtcp2_acktr_commit_ack(acktr);
return NULL;
}
num_acks = ngtcp2_ksl_len(&acktr->ents);
if (acktr->ecn.ect0 || acktr->ecn.ect1 || acktr->ecn.ce) {
ack->type = NGTCP2_FRAME_ACK_ECN;
ack->ecn.ect0 = acktr->ecn.ect0;
ack->ecn.ect1 = acktr->ecn.ect1;
ack->ecn.ce = acktr->ecn.ce;
} else {
ack->type = NGTCP2_FRAME_ACK;
}
ack->rangecnt = 0;
rpkt = ngtcp2_ksl_it_get(&it);
if (rpkt->pkt_num == acktr->max_pkt_num) {
last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
largest_ack_ts = rpkt->tstamp;
ack->largest_ack = rpkt->pkt_num;
ack->first_ack_range = rpkt->len - 1;
ngtcp2_ksl_it_next(&it);
--num_acks;
} else if (rpkt->pkt_num + 1 == acktr->max_pkt_num) {
last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
largest_ack_ts = acktr->max_pkt_ts;
ack->largest_ack = acktr->max_pkt_num;
ack->first_ack_range = rpkt->len;
ngtcp2_ksl_it_next(&it);
--num_acks;
} else {
assert(rpkt->pkt_num < acktr->max_pkt_num);
last_pkt_num = acktr->max_pkt_num;
largest_ack_ts = acktr->max_pkt_ts;
ack->largest_ack = acktr->max_pkt_num;
ack->first_ack_range = 0;
}
if (type == NGTCP2_PKT_1RTT) {
ack->ack_delay_unscaled = ts - largest_ack_ts;
ack->ack_delay = ack->ack_delay_unscaled / NGTCP2_MICROSECONDS /
(1ULL << ack_delay_exponent);
} else {
ack->ack_delay_unscaled = 0;
ack->ack_delay = 0;
}
num_acks = ngtcp2_min_size(num_acks, NGTCP2_MAX_ACK_RANGES);
for (; ack->rangecnt < num_acks; ngtcp2_ksl_it_next(&it)) {
rpkt = ngtcp2_ksl_it_get(&it);
range = &ack->ranges[ack->rangecnt++];
range->gap = (uint64_t)(last_pkt_num - rpkt->pkt_num - 2);
range->len = rpkt->len - 1;
last_pkt_num = rpkt->pkt_num - (int64_t)(rpkt->len - 1);
}
return fr;
}
void ngtcp2_acktr_increase_ecn_counts(ngtcp2_acktr *acktr,
const ngtcp2_pkt_info *pi) {
switch (pi->ecn & NGTCP2_ECN_MASK) {
case NGTCP2_ECN_ECT_0:
++acktr->ecn.ect0;
break;
case NGTCP2_ECN_ECT_1:
++acktr->ecn.ect1;
break;
case NGTCP2_ECN_CE:
++acktr->ecn.ce;
break;
}
}

View File

@ -128,6 +128,26 @@ typedef struct ngtcp2_acktr {
/* rx_npkt is the number of ACK eliciting packets received without
sending ACK. */
size_t rx_npkt;
/* max_pkt_num is the largest packet number received so far. */
int64_t max_pkt_num;
/* max_pkt_ts is the timestamp when max_pkt_num packet is
received. */
ngtcp2_tstamp max_pkt_ts;
struct {
/* ect0, ect1, and ce are the number of QUIC packets received
with those markings. */
size_t ect0;
size_t ect1;
size_t ce;
struct {
/* ect0, ect1, ce are the ECN counts received in the latest
ACK frame. */
uint64_t ect0;
uint64_t ect1;
uint64_t ce;
} ack;
} ecn;
} ngtcp2_acktr;
/*
@ -165,7 +185,7 @@ int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack,
void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent);
/*
* ngtcp2_acktr_get returns the pointer to pointer to the entry which
* ngtcp2_acktr_get returns the iterator to pointer to the entry which
* has the largest packet number to be acked. If there is no entry,
* returned value satisfies ngtcp2_ksl_it_end(&it) != 0.
*/
@ -213,4 +233,26 @@ int ngtcp2_acktr_require_active_ack(const ngtcp2_acktr *acktr,
*/
void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr);
/*
* ngtcp2_acktr_create_ack_frame creates ACK frame in the object
* pointed by |fr|, and returns |fr| if there are any received packets
* to acknowledge. If there are no packets to acknowledge, this
* function returns NULL. fr->ack.ranges must be able to contain at
* least NGTCP2_MAX_ACK_RANGES elements.
*
* Call ngtcp2_acktr_commit_ack after a created ACK frame is
* successfully serialized into a packet.
*/
ngtcp2_frame *ngtcp2_acktr_create_ack_frame(ngtcp2_acktr *acktr,
ngtcp2_frame *fr, uint8_t type,
ngtcp2_tstamp ts,
ngtcp2_duration ack_delay,
uint64_t ack_delay_exponent);
/*
* ngtcp2_acktr_increase_ecn_counts increases ECN counts from |pi|.
*/
void ngtcp2_acktr_increase_ecn_counts(ngtcp2_acktr *acktr,
const ngtcp2_pkt_info *pi);
#endif /* !defined(NGTCP2_ACKTR_H) */

View File

@ -51,8 +51,10 @@ void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr,
}
}
static int sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) {
assert(a->sa_family == b->sa_family);
int ngtcp2_sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) {
if (a->sa_family != b->sa_family) {
return 0;
}
switch (a->sa_family) {
case NGTCP2_AF_INET: {
@ -73,17 +75,16 @@ static int sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) {
}
int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b) {
return a->addr->sa_family == b->addr->sa_family &&
sockaddr_eq(a->addr, b->addr);
return ngtcp2_sockaddr_eq(a->addr, b->addr);
}
uint32_t ngtcp2_addr_compare(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
uint32_t flags = NGTCP2_ADDR_COMPARE_FLAG_NONE;
uint32_t ngtcp2_addr_cmp(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
uint32_t flags = NGTCP2_ADDR_CMP_FLAG_NONE;
const ngtcp2_sockaddr *a = aa->addr;
const ngtcp2_sockaddr *b = bb->addr;
if (a->sa_family != b->sa_family) {
return NGTCP2_ADDR_COMPARE_FLAG_FAMILY;
return NGTCP2_ADDR_CMP_FLAG_FAMILY;
}
switch (a->sa_family) {
@ -91,10 +92,10 @@ uint32_t ngtcp2_addr_compare(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
*bi = (const ngtcp2_sockaddr_in *)(void *)b;
if (memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr))) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_ADDR;
flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
}
if (ai->sin_port != bi->sin_port) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_PORT;
flags |= NGTCP2_ADDR_CMP_FLAG_PORT;
}
return flags;
}
@ -102,10 +103,10 @@ uint32_t ngtcp2_addr_compare(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
*bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
if (memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr))) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_ADDR;
flags |= NGTCP2_ADDR_CMP_FLAG_ADDR;
}
if (ai->sin6_port != bi->sin6_port) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_PORT;
flags |= NGTCP2_ADDR_CMP_FLAG_PORT;
}
return flags;
}

View File

@ -45,22 +45,21 @@ 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_COMPARE_FLAG_NONE indicates that no flag set. */
#define NGTCP2_ADDR_COMPARE_FLAG_NONE 0x0u
/* NGTCP2_ADDR_COMPARE_FLAG_ADDR indicates IP addresses do not
/* NGTCP2_ADDR_CMP_FLAG_NONE indicates that no flag set. */
#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
/* NGTCP2_ADDR_CMP_FLAG_PORT indicates ports do not match. */
#define NGTCP2_ADDR_CMP_FLAG_PORT 0x2u
/* NGTCP2_ADDR_CMP_FLAG_FAMILY indicates address families do not
match. */
#define NGTCP2_ADDR_COMPARE_FLAG_ADDR 0x1u
/* NGTCP2_ADDR_COMPARE_FLAG_PORT indicates ports do not match. */
#define NGTCP2_ADDR_COMPARE_FLAG_PORT 0x2u
/* NGTCP2_ADDR_COMPARE_FLAG_FAMILY indicates address families do not
match. */
#define NGTCP2_ADDR_COMPARE_FLAG_FAMILY 0x4u
#define NGTCP2_ADDR_CMP_FLAG_FAMILY 0x4u
/*
* ngtcp2_addr_compare compares address and port between |a| and |b|,
* and returns zero or more of NGTCP2_ADDR_COMPARE_FLAG_*.
* ngtcp2_addr_cmp compares address and port between |a| and |b|, and
* returns zero or more of NGTCP2_ADDR_CMP_FLAG_*.
*/
uint32_t ngtcp2_addr_compare(const ngtcp2_addr *a, const ngtcp2_addr *b);
uint32_t ngtcp2_addr_cmp(const ngtcp2_addr *a, const ngtcp2_addr *b);
/*
* ngtcp2_addr_empty returns nonzero if |addr| has zero length
@ -68,4 +67,11 @@ uint32_t ngtcp2_addr_compare(const ngtcp2_addr *a, const ngtcp2_addr *b);
*/
int ngtcp2_addr_empty(const ngtcp2_addr *addr);
/**
* @function
*
* `ngtcp2_sockaddr_eq` returns nonzero if |a| equals |b|.
*/
int ngtcp2_sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b);
#endif /* !defined(NGTCP2_ADDR_H) */

View File

@ -39,7 +39,7 @@
#define NGTCP2_BBR_EXTRA_ACKED_FILTERLEN 10
#define NGTCP2_BBR_STARTUP_PACING_GAIN_H 277
#define NGTCP2_BBR_DRAIN_PACING_GAIN_H 35
#define NGTCP2_BBR_DRAIN_PACING_GAIN_H 50
#define NGTCP2_BBR_DEFAULT_CWND_GAIN_H 200
@ -130,6 +130,8 @@ static void bbr_start_round(ngtcp2_cc_bbr *bbr);
static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr);
static int bbr_is_probing_bw(ngtcp2_cc_bbr *bbr);
static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack,
@ -137,8 +139,8 @@ static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
static void bbr_enter_drain(ngtcp2_cc_bbr *bbr);
static void bbr_check_drain(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static void bbr_enter_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts);
@ -277,7 +279,8 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_window_filter_init(&bbr->extra_acked_filter,
NGTCP2_BBR_EXTRA_ACKED_FILTERLEN);
bbr->min_rtt = UINT64_MAX;
bbr->min_rtt =
cstat->first_rtt_sample_ts == UINT64_MAX ? UINT64_MAX : cstat->smoothed_rtt;
bbr->min_rtt_stamp = initial_ts;
/* remark: Use UINT64_MAX instead of 0 for consistency. */
bbr->probe_rtt_done_stamp = UINT64_MAX;
@ -335,6 +338,8 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
bbr->max_inflight = 0;
bbr->congestion_recovery_start_ts = UINT64_MAX;
bbr->bdp = 0;
}
static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) {
@ -404,8 +409,10 @@ static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) {
}
static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
cstat->pacing_interval = NGTCP2_MILLISECONDS * 100 /
NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd;
cstat->pacing_interval =
(cstat->first_rtt_sample_ts == UINT64_MAX ? NGTCP2_MILLISECONDS
: cstat->smoothed_rtt) *
100 / NGTCP2_BBR_STARTUP_PACING_GAIN_H / bbr->initial_cwnd;
}
static void bbr_set_pacing_rate_with_gain(ngtcp2_cc_bbr *bbr,
@ -465,7 +472,7 @@ static void bbr_update_model_and_state(ngtcp2_cc_bbr *bbr,
bbr_update_ack_aggregation(bbr, cstat, ack, ts);
bbr_check_full_bw_reached(bbr, cstat);
bbr_check_startup_done(bbr);
bbr_check_drain(bbr, cstat, ts);
bbr_check_drain_done(bbr, cstat, ts);
bbr_update_probe_bw_cycle_phase(bbr, cstat, ack, ts);
bbr_update_min_rtt(bbr, ack, ts);
bbr_check_probe_rtt(bbr, cstat, ts);
@ -528,7 +535,7 @@ static void bbr_update_congestion_signals(ngtcp2_cc_bbr *bbr,
static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat) {
if (bbr_is_in_probe_bw_state(bbr)) {
if (bbr_is_probing_bw(bbr)) {
return;
}
@ -607,6 +614,17 @@ static int bbr_is_in_probe_bw_state(ngtcp2_cc_bbr *bbr) {
}
}
static int bbr_is_probing_bw(ngtcp2_cc_bbr *bbr) {
switch (bbr->state) {
case NGTCP2_BBR_STATE_STARTUP:
case NGTCP2_BBR_STATE_PROBE_BW_REFILL:
case NGTCP2_BBR_STATE_PROBE_BW_UP:
return 1;
default:
return 0;
}
}
static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack,
@ -622,8 +640,13 @@ static void bbr_update_ack_aggregation(ngtcp2_cc_bbr *bbr,
}
bbr->extra_acked_delivered += ack->bytes_delivered;
extra = bbr->extra_acked_delivered - expected_delivered;
extra = ngtcp2_min_uint64(extra, cstat->cwnd);
if (bbr->extra_acked_delivered <= expected_delivered) {
extra = 0;
} else {
extra = bbr->extra_acked_delivered - expected_delivered;
extra = ngtcp2_min_uint64(extra, cstat->cwnd);
}
if (bbr->full_bw_reached) {
bbr->extra_acked_filter.window_length = NGTCP2_BBR_EXTRA_ACKED_FILTERLEN;
@ -645,8 +668,8 @@ static void bbr_enter_drain(ngtcp2_cc_bbr *bbr) {
bbr->cwnd_gain_h = NGTCP2_BBR_DEFAULT_CWND_GAIN_H;
}
static void bbr_check_drain(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
static void bbr_check_drain_done(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
if (bbr->state == NGTCP2_BBR_STATE_DRAIN &&
cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) {
bbr_enter_probe_bw(bbr, ts);
@ -825,8 +848,7 @@ static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr,
<< bbr->bw_probe_up_rounds;
bbr->bw_probe_up_rounds = ngtcp2_min_size(bbr->bw_probe_up_rounds + 1, 30);
bbr->probe_up_cnt = ngtcp2_max_uint64(cstat->cwnd / growth_this_round, 1) *
cstat->max_tx_udp_payload_size;
bbr->probe_up_cnt = ngtcp2_max_uint64(cstat->cwnd / growth_this_round, 1);
}
static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr,
@ -840,10 +862,12 @@ static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr,
bbr->bw_probe_up_acks += ack->bytes_delivered;
if (bbr->bw_probe_up_acks >= bbr->probe_up_cnt) {
if (bbr->probe_up_cnt != UINT64_MAX &&
bbr->bw_probe_up_acks >=
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 * cstat->max_tx_udp_payload_size;
bbr->inflight_hi += delta;
}
if (bbr->round_start) {
@ -901,8 +925,7 @@ static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr) {
bbr->rand(&rand, 1, &bbr->rand_ctx);
bbr->bw_probe_wait =
2 * NGTCP2_SECONDS + (ngtcp2_tstamp)(NGTCP2_SECONDS * rand / 255);
bbr->bw_probe_wait = 2 * NGTCP2_SECONDS + NGTCP2_SECONDS * rand / 255;
}
static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr,
@ -915,9 +938,7 @@ 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) {
uint64_t bdp = bbr_bdp_multiple(bbr, bbr->cwnd_gain_h);
return ngtcp2_min_uint64(bdp, cstat->cwnd);
return ngtcp2_min_uint64(bbr->bdp, cstat->cwnd);
}
static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr,
@ -957,12 +978,11 @@ static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr,
}
static void bbr_note_loss(ngtcp2_cc_bbr *bbr) {
if (bbr->loss_in_round) {
return;
if (!bbr->loss_in_round) {
bbr->loss_round_delivered = bbr->rst->delivered;
}
bbr->loss_in_round = 1;
bbr->loss_round_delivered = bbr->rst->delivered;
}
static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
@ -977,6 +997,7 @@ static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
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;
@ -1143,15 +1164,13 @@ static void bbr_handle_restart_from_idle(ngtcp2_cc_bbr *bbr,
}
static uint64_t bbr_bdp_multiple(ngtcp2_cc_bbr *bbr, uint64_t gain_h) {
uint64_t bdp;
if (bbr->min_rtt == UINT64_MAX) {
return bbr->initial_cwnd;
}
bdp = ngtcp2_max_uint64(bbr->bw * bbr->min_rtt / NGTCP2_SECONDS, 1);
bbr->bdp = ngtcp2_max_uint64(bbr->bw * bbr->min_rtt / NGTCP2_SECONDS, 1);
return (uint64_t)(bdp * gain_h / 100);
return (uint64_t)(bbr->bdp * gain_h / 100);
}
static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) {
@ -1324,10 +1343,6 @@ static void bbr_cc_on_pkt_lost(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
ngtcp2_cc_bbr *bbr = ngtcp2_struct_of(cc, ngtcp2_cc_bbr, cc);
if (bbr->state == NGTCP2_BBR_STATE_STARTUP) {
return;
}
bbr_update_on_loss(bbr, cstat, pkt, ts);
}

View File

@ -131,6 +131,7 @@ typedef struct ngtcp2_cc_bbr {
uint64_t round_count_at_recovery;
uint64_t max_inflight;
ngtcp2_tstamp congestion_recovery_start_ts;
uint64_t bdp;
} ngtcp2_cc_bbr;
void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log,

View File

@ -252,13 +252,15 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
uint64_t w_cubic, w_cubic_next, target, m;
ngtcp2_duration rtt_thresh;
int round_start;
int is_app_limited =
cubic->rst->rs.is_app_limited && !cubic->rst->is_cwnd_limited;
if (in_congestion_recovery(cstat, ack->largest_pkt_sent_ts)) {
return;
}
if (cubic->current.state == NGTCP2_CUBIC_STATE_CONGESTION_AVOIDANCE) {
if (cubic->rst->rs.is_app_limited && !cubic->rst->is_cwnd_limited) {
if (is_app_limited) {
if (cubic->current.app_limited_start_ts == UINT64_MAX) {
cubic->current.app_limited_start_ts = ts;
}
@ -271,7 +273,7 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ts - cubic->current.app_limited_start_ts;
cubic->current.app_limited_start_ts = UINT64_MAX;
}
} else if (cubic->rst->rs.is_app_limited && !cubic->rst->is_cwnd_limited) {
} else if (is_app_limited) {
return;
}

View File

@ -141,8 +141,10 @@ int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
}
int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
const ngtcp2_path *path,
const uint8_t *token) {
return (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
return ngtcp2_path_eq(&dcid->ps.path, path) &&
(dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
ngtcp2_cmemeq(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN)
? 0
: NGTCP2_ERR_INVALID_ARGUMENT;

View File

@ -149,7 +149,9 @@ void ngtcp2_dcid_copy(ngtcp2_dcid *dest, const ngtcp2_dcid *src);
/*
* ngtcp2_dcid_copy_cid_token behaves like ngtcp2_dcid_copy, but it
* only copies cid, seq, and token.
* only copies cid, seq, and token. dest->flags should be initialized
* before this call because NGTCP2_DCID_FLAG_TOKEN_PRESENT is set or
* unset.
*/
void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src);
@ -162,15 +164,16 @@ int ngtcp2_dcid_verify_uniqueness(const ngtcp2_dcid *dcid, uint64_t seq,
/*
* ngtcp2_dcid_verify_stateless_reset_token verifies stateless reset
* token |token| against the one included in |dcid|. Tokens are
* compared in constant time. This function returns 0 if the
* verification succeeds, or one of the following negative error
* codes:
* token |token| received on |path| against the one included in
* |dcid|. Tokens are compared in constant time. This function
* returns 0 if the verification succeeds, or one of the following
* negative error codes:
*
* 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);
#endif /* !defined(NGTCP2_CID_H) */

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,7 @@
#include "ngtcp2_qlog.h"
#include "ngtcp2_rst.h"
#include "ngtcp2_conn_stat.h"
#include "ngtcp2_dcidtr.h"
typedef enum {
/* Client specific handshake states */
@ -78,18 +79,6 @@ typedef enum {
accept. */
#define NGTCP2_MAX_RETRIES 3
/* NGTCP2_MAX_BOUND_DCID_POOL_SIZE is the maximum number of
destination connection ID which have been bound to a particular
path, but not yet used as primary path and path validation is not
performed from the local endpoint. */
#define NGTCP2_MAX_BOUND_DCID_POOL_SIZE 4
/* NGTCP2_MAX_DCID_POOL_SIZE is the maximum number of destination
connection ID the remote endpoint provides to store. It must be
the power of 2. */
#define NGTCP2_MAX_DCID_POOL_SIZE 8
/* NGTCP2_MAX_DCID_RETIRED_SIZE is the maximum number of retired DCID
kept to catch in-flight packet on retired path. */
#define NGTCP2_MAX_DCID_RETIRED_SIZE 2
/* NGTCP2_MAX_SCID_POOL_SIZE is the maximum number of source
connection ID the local endpoint provides to the remote endpoint.
The chosen value was described in old draft. Now a remote endpoint
@ -239,11 +228,6 @@ typedef struct ngtcp2_pktns {
/* pngap tracks received packet number in order to suppress
duplicated packet number. */
ngtcp2_gaptr pngap;
/* max_pkt_num is the largest packet number received so far. */
int64_t max_pkt_num;
/* max_pkt_ts is the timestamp when max_pkt_num packet is
received. */
ngtcp2_tstamp max_pkt_ts;
/* max_ack_eliciting_pkt_num is the largest ack-eliciting packet
number received so far. */
int64_t max_ack_eliciting_pkt_num;
@ -268,21 +252,6 @@ typedef struct ngtcp2_pktns {
* ngtcp2_pktns.
*/
ngtcp2_pkt_chain *buffed_pkts;
struct {
/* ect0, ect1, and ce are the number of QUIC packets received
with those markings. */
size_t ect0;
size_t ect1;
size_t ce;
struct {
/* ect0, ect1, ce are the ECN counts received in the latest
ACK frame. */
uint64_t ect0;
uint64_t ect1;
uint64_t ce;
} ack;
} ecn;
} rx;
struct {
@ -336,12 +305,6 @@ typedef struct ngtcp2_early_transport_params {
uint64_t max_datagram_frame_size;
} ngtcp2_early_transport_params;
ngtcp2_static_ringbuf_def(dcid_bound, NGTCP2_MAX_BOUND_DCID_POOL_SIZE,
sizeof(ngtcp2_dcid))
ngtcp2_static_ringbuf_def(dcid_unused, NGTCP2_MAX_DCID_POOL_SIZE,
sizeof(ngtcp2_dcid))
ngtcp2_static_ringbuf_def(dcid_retired, NGTCP2_MAX_DCID_RETIRED_SIZE,
sizeof(ngtcp2_dcid))
ngtcp2_static_ringbuf_def(path_challenge, 4,
sizeof(ngtcp2_path_challenge_entry))
@ -366,6 +329,8 @@ struct ngtcp2_conn {
records it in order to verify retry_source_connection_id
transport parameter. Server does not use this field. */
ngtcp2_cid retry_scid;
/* hs_local_addr is a local address used during handshake. */
ngtcp2_sockaddr_union hs_local_addr;
ngtcp2_pktns *in_pktns;
ngtcp2_pktns *hs_pktns;
ngtcp2_pktns pktns;
@ -373,31 +338,13 @@ struct ngtcp2_conn {
struct {
/* current is the current destination connection ID. */
ngtcp2_dcid current;
/* bound is a set of destination connection IDs which are bound to
particular paths. These paths are not validated yet. */
ngtcp2_static_ringbuf_dcid_bound bound;
/* unused is a set of unused CID received from peer. */
ngtcp2_static_ringbuf_dcid_unused unused;
/* retired is a set of CID retired by local endpoint. Keep them
in 3*PTO to catch packets in flight along the old path. */
ngtcp2_static_ringbuf_dcid_retired retired;
ngtcp2_dcidtr dtr;
/* seqgap tracks received sequence numbers in order to ignore
retransmitted duplicated NEW_CONNECTION_ID frame. */
ngtcp2_gaptr seqgap;
/* retire_prior_to is the largest retire_prior_to received so
far. */
uint64_t retire_prior_to;
struct {
/* seqs contains sequence number of Connection ID whose
retirement is not acknowledged by the remote endpoint yet. */
uint64_t seqs[NGTCP2_MAX_DCID_POOL_SIZE * 2];
/* len is the number of sequence numbers that seq contains. */
size_t len;
} retire_unacked;
/* zerolen_seq is a pseudo sequence number of zero-length
Destination Connection ID in order to distinguish between
them. */
uint64_t zerolen_seq;
} dcid;
struct {
@ -421,11 +368,6 @@ struct ngtcp2_conn {
struct {
/* strmq contains ngtcp2_strm which has frames to send. */
ngtcp2_pq strmq;
/* ack is ACK frame. The underlying buffer is reused. */
ngtcp2_frame *ack;
/* max_ack_ranges is the number of additional ngtcp2_ack_range
which ack can contain. */
size_t max_ack_ranges;
/* offset is the offset the local endpoint has sent to the remote
endpoint. */
uint64_t offset;
@ -458,6 +400,15 @@ struct ngtcp2_conn {
/* next_ts is the time to send next packet. It is UINT64_MAX if
packet pacing is disabled or expired.*/
ngtcp2_tstamp next_ts;
/* compensation is the amount of time that a local endpoint
waits too long for pacing. This happens because there is an
overhead before start writing packets after pacing timer
expires. If multiple QUIC connections are handled by a
single thread, which is typical use case for event loop based
servers, each processing of QUIC connection adds overhead,
for example, TLS handshake, and packet encryption/decryption,
etc. */
ngtcp2_duration compensation;
} pacing;
} tx;
@ -478,6 +429,12 @@ struct ngtcp2_conn {
ngtcp2_static_ringbuf_path_challenge path_challenge;
/* ccerr is the received connection close error. */
ngtcp2_ccerr ccerr;
struct {
/* pkt_num is the lowest incoming packet number of the packet
that server verified preferred address usage of client. */
int64_t pkt_num;
} preferred_addr;
} rx;
struct {
@ -671,6 +628,9 @@ struct ngtcp2_conn {
const ngtcp2_mem *mem;
/* idle_ts is the time instant when idle timer started. */
ngtcp2_tstamp idle_ts;
/* handshake_confirmed_ts is the time instant when handshake is
confirmed. For server, it is confirmed when completed. */
ngtcp2_tstamp handshake_confirmed_ts;
void *user_data;
uint32_t client_chosen_version;
uint32_t negotiated_version;
@ -724,21 +684,6 @@ typedef struct ngtcp2_vmsg {
};
} ngtcp2_vmsg;
/*
* ngtcp2_conn_sched_ack stores packet number |pkt_num| and its
* reception timestamp |ts| in order to send its ACK.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
* NGTCP2_ERR_PROTO
* Same packet number has already been added.
*/
int ngtcp2_conn_sched_ack(ngtcp2_conn *conn, ngtcp2_acktr *acktr,
int64_t pkt_num, int active_ack, ngtcp2_tstamp ts);
/*
* ngtcp2_conn_find_stream returns a stream whose stream ID is
* |stream_id|. If no such stream is found, it returns NULL.
@ -1137,28 +1082,6 @@ int ngtcp2_conn_set_remote_transport_params(
int ngtcp2_conn_set_0rtt_remote_transport_params(
ngtcp2_conn *conn, const ngtcp2_transport_params *params);
/*
* ngtcp2_conn_create_ack_frame creates ACK frame, and assigns its
* pointer to |*pfr| if there are any received packets to acknowledge.
* If there are no packets to acknowledge, this function returns 0,
* and |*pfr| is untouched. The caller is advised to set |*pfr| to
* NULL before calling this function, and check it after this function
* returns.
*
* Call ngtcp2_acktr_commit_ack after a created ACK frame is
* successfully serialized into a packet.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_conn_create_ack_frame(ngtcp2_conn *conn, ngtcp2_frame **pfr,
ngtcp2_pktns *pktns, uint8_t type,
ngtcp2_tstamp ts, ngtcp2_duration ack_delay,
uint64_t ack_delay_exponent);
/*
* ngtcp2_conn_discard_initial_state discards state for Initial packet
* number space.

497
deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c vendored Normal file
View File

@ -0,0 +1,497 @@
/*
* 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_dcidtr.h"
#include <assert.h>
#include "ngtcp2_tstamp.h"
#include "ngtcp2_macro.h"
void ngtcp2_dcidtr_init(ngtcp2_dcidtr *dtr) {
ngtcp2_static_ringbuf_dcid_unused_init(&dtr->unused);
ngtcp2_static_ringbuf_dcid_bound_init(&dtr->bound);
ngtcp2_static_ringbuf_dcid_retired_init(&dtr->retired);
dtr->retire_unacked.len = 0;
}
int ngtcp2_dcidtr_track_retired_seq(ngtcp2_dcidtr *dtr, uint64_t seq) {
if (dtr->retire_unacked.len >= ngtcp2_arraylen(dtr->retire_unacked.seqs)) {
return NGTCP2_ERR_CONNECTION_ID_LIMIT;
}
dtr->retire_unacked.seqs[dtr->retire_unacked.len++] = seq;
return 0;
}
void ngtcp2_dcidtr_untrack_retired_seq(ngtcp2_dcidtr *dtr, uint64_t seq) {
size_t i;
for (i = 0; i < dtr->retire_unacked.len; ++i) {
if (dtr->retire_unacked.seqs[i] != seq) {
continue;
}
if (i != dtr->retire_unacked.len - 1) {
dtr->retire_unacked.seqs[i] =
dtr->retire_unacked.seqs[dtr->retire_unacked.len - 1];
}
--dtr->retire_unacked.len;
return;
}
}
int ngtcp2_dcidtr_check_retired_seq_tracked(const ngtcp2_dcidtr *dtr,
uint64_t seq) {
size_t i;
for (i = 0; i < dtr->retire_unacked.len; ++i) {
if (dtr->retire_unacked.seqs[i] == seq) {
return 1;
}
}
return 0;
}
static int dcidtr_on_retire(ngtcp2_dcidtr *dtr, const ngtcp2_dcid *dcid,
ngtcp2_dcidtr_cb on_retire, void *user_data) {
int rv;
if (ngtcp2_dcidtr_check_retired_seq_tracked(dtr, dcid->seq)) {
return 0;
}
rv = ngtcp2_dcidtr_track_retired_seq(dtr, dcid->seq);
if (rv != 0) {
return rv;
}
if (!on_retire) {
return 0;
}
return on_retire(dcid, user_data);
}
ngtcp2_dcid *ngtcp2_dcidtr_find_bound_dcid(const ngtcp2_dcidtr *dtr,
const ngtcp2_path *path) {
ngtcp2_dcid *dcid;
const ngtcp2_ringbuf *rb = &dtr->bound.rb;
size_t i, len = ngtcp2_ringbuf_len(rb);
for (i = 0; i < len; ++i) {
dcid = ngtcp2_ringbuf_get(rb, i);
if (ngtcp2_path_eq(&dcid->ps.path, path)) {
return dcid;
}
}
return NULL;
}
ngtcp2_dcid *ngtcp2_dcidtr_bind_zerolen_dcid(ngtcp2_dcidtr *dtr,
const ngtcp2_path *path) {
ngtcp2_dcid *dcid = ngtcp2_ringbuf_push_back(&dtr->bound.rb);
ngtcp2_cid cid;
ngtcp2_cid_zero(&cid);
ngtcp2_dcid_init(dcid, 0, &cid, NULL);
ngtcp2_dcid_set_path(dcid, path);
return dcid;
}
int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest,
const ngtcp2_path *path, ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_retire, void *user_data) {
const ngtcp2_dcid *src;
ngtcp2_dcid *dest;
int rv;
if (ngtcp2_ringbuf_full(&dtr->bound.rb)) {
rv = dcidtr_on_retire(dtr, ngtcp2_ringbuf_get(&dtr->bound.rb, 0), on_retire,
user_data);
if (rv != 0) {
return rv;
}
}
src = ngtcp2_ringbuf_get(&dtr->unused.rb, 0);
dest = ngtcp2_ringbuf_push_back(&dtr->bound.rb);
ngtcp2_dcid_copy(dest, src);
dest->bound_ts = ts;
ngtcp2_dcid_set_path(dest, path);
ngtcp2_ringbuf_pop_front(&dtr->unused.rb);
*pdest = dest;
return 0;
}
static int verify_stateless_reset(const ngtcp2_ringbuf *rb,
const ngtcp2_path *path,
const uint8_t *token) {
const ngtcp2_dcid *dcid;
size_t i, len = ngtcp2_ringbuf_len(rb);
for (i = 0; i < len; ++i) {
dcid = ngtcp2_ringbuf_get(rb, i);
if (ngtcp2_dcid_verify_stateless_reset_token(dcid, path, token) == 0) {
return 0;
}
}
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) {
const ngtcp2_dcid *dcid;
size_t i, len = ngtcp2_ringbuf_len(rb);
int rv;
for (i = 0; i < len; ++i) {
dcid = ngtcp2_ringbuf_get(rb, i);
rv = ngtcp2_dcid_verify_uniqueness(dcid, seq, cid, token);
if (rv != 0) {
return NGTCP2_ERR_PROTO;
}
if (ngtcp2_cid_eq(&dcid->cid, cid)) {
*pfound = 1;
}
}
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 rv;
rv = verify_token_uniqueness(&dtr->bound.rb, pfound, seq, cid, token);
if (rv != 0) {
return rv;
}
return verify_token_uniqueness(&dtr->unused.rb, pfound, seq, cid, token);
}
static void remove_dcid_at(ngtcp2_ringbuf *rb, size_t at) {
const ngtcp2_dcid *src;
ngtcp2_dcid *dest;
if (at == 0) {
ngtcp2_ringbuf_pop_front(rb);
return;
}
if (at == ngtcp2_ringbuf_len(rb) - 1) {
ngtcp2_ringbuf_pop_back(rb);
return;
}
src = ngtcp2_ringbuf_get(rb, ngtcp2_ringbuf_len(rb) - 1);
dest = ngtcp2_ringbuf_get(rb, at);
ngtcp2_dcid_copy(dest, src);
ngtcp2_ringbuf_pop_back(rb);
}
static int dcidtr_retire_dcid_prior_to(ngtcp2_dcidtr *dtr, ngtcp2_ringbuf *rb,
uint64_t seq, ngtcp2_dcidtr_cb on_retire,
void *user_data) {
size_t i;
const ngtcp2_dcid *dcid;
int rv;
for (i = 0; i < ngtcp2_ringbuf_len(rb);) {
dcid = ngtcp2_ringbuf_get(rb, i);
if (dcid->seq >= seq) {
++i;
continue;
}
rv = dcidtr_on_retire(dtr, dcid, on_retire, user_data);
if (rv != 0) {
return rv;
}
remove_dcid_at(rb, i);
}
return 0;
}
int ngtcp2_dcidtr_retire_inactive_dcid_prior_to(ngtcp2_dcidtr *dtr,
uint64_t seq,
ngtcp2_dcidtr_cb on_retire,
void *user_data) {
int rv;
rv =
dcidtr_retire_dcid_prior_to(dtr, &dtr->bound.rb, seq, on_retire, user_data);
if (rv != 0) {
return rv;
}
return dcidtr_retire_dcid_prior_to(dtr, &dtr->unused.rb, seq, on_retire,
user_data);
}
int ngtcp2_dcidtr_retire_active_dcid(ngtcp2_dcidtr *dtr,
const ngtcp2_dcid *dcid, ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_deactivate,
void *user_data) {
ngtcp2_ringbuf *rb = &dtr->retired.rb;
const ngtcp2_dcid *stale_dcid;
ngtcp2_dcid *dest;
int rv;
assert(dcid->cid.datalen);
if (ngtcp2_ringbuf_full(rb)) {
stale_dcid = ngtcp2_ringbuf_get(rb, 0);
rv = on_deactivate(stale_dcid, user_data);
if (rv != 0) {
return rv;
}
}
dest = ngtcp2_ringbuf_push_back(rb);
ngtcp2_dcid_copy(dest, dcid);
dest->retired_ts = ts;
return dcidtr_on_retire(dtr, dest, NULL, NULL);
}
int ngtcp2_dcidtr_remove_stale_retired_dcid(ngtcp2_dcidtr *dtr,
ngtcp2_duration timeout,
ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_deactivate,
void *user_data) {
ngtcp2_ringbuf *rb = &dtr->retired.rb;
const ngtcp2_dcid *dcid;
int rv;
for (; ngtcp2_ringbuf_len(rb);) {
dcid = ngtcp2_ringbuf_get(rb, 0);
if (ngtcp2_tstamp_not_elapsed(dcid->retired_ts, timeout, ts)) {
break;
}
rv = on_deactivate(dcid, user_data);
if (rv != 0) {
return rv;
}
ngtcp2_ringbuf_pop_front(rb);
}
return 0;
}
int ngtcp2_dcidtr_pop_bound_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid *dest,
const ngtcp2_path *path) {
const ngtcp2_dcid *src;
ngtcp2_ringbuf *rb = &dtr->bound.rb;
size_t len = ngtcp2_ringbuf_len(rb);
size_t i;
for (i = 0; i < len; ++i) {
src = ngtcp2_ringbuf_get(rb, i);
if (ngtcp2_path_eq(&src->ps.path, path)) {
ngtcp2_dcid_copy(dest, src);
remove_dcid_at(rb, i);
return 0;
}
}
return NGTCP2_ERR_INVALID_ARGUMENT;
}
int ngtcp2_dcidtr_retire_stale_bound_dcid(ngtcp2_dcidtr *dtr,
ngtcp2_duration timeout,
ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_retire,
void *user_data) {
ngtcp2_ringbuf *rb = &dtr->bound.rb;
size_t i;
const ngtcp2_dcid *dcid;
int rv;
for (i = 0; i < ngtcp2_ringbuf_len(rb);) {
dcid = ngtcp2_ringbuf_get(rb, i);
assert(dcid->cid.datalen);
if (ngtcp2_tstamp_not_elapsed(dcid->bound_ts, timeout, ts)) {
++i;
continue;
}
rv = dcidtr_on_retire(dtr, dcid, on_retire, user_data);
if (rv != 0) {
return rv;
}
remove_dcid_at(rb, i);
}
return 0;
}
ngtcp2_tstamp ngtcp2_dcidtr_earliest_bound_ts(const ngtcp2_dcidtr *dtr) {
const ngtcp2_ringbuf *rb = &dtr->bound.rb;
size_t i, len = ngtcp2_ringbuf_len(rb);
ngtcp2_tstamp res = UINT64_MAX;
const ngtcp2_dcid *dcid;
for (i = 0; i < len; ++i) {
dcid = ngtcp2_ringbuf_get(rb, i);
assert(dcid->cid.datalen);
assert(dcid->bound_ts != UINT64_MAX);
res = ngtcp2_min_uint64(res, dcid->bound_ts);
}
return res;
}
ngtcp2_tstamp ngtcp2_dcidtr_earliest_retired_ts(const ngtcp2_dcidtr *dtr) {
const ngtcp2_ringbuf *rb = &dtr->retired.rb;
const ngtcp2_dcid *dcid;
if (ngtcp2_ringbuf_len(rb) == 0) {
return UINT64_MAX;
}
dcid = ngtcp2_ringbuf_get(rb, 0);
return dcid->retired_ts;
}
void ngtcp2_dcidtr_push_unused(ngtcp2_dcidtr *dtr, uint64_t seq,
const ngtcp2_cid *cid, const uint8_t *token) {
ngtcp2_dcid *dcid = ngtcp2_ringbuf_push_back(&dtr->unused.rb);
ngtcp2_dcid_init(dcid, seq, cid, token);
}
void ngtcp2_dcidtr_pop_unused_cid_token(ngtcp2_dcidtr *dtr, ngtcp2_dcid *dest) {
ngtcp2_ringbuf *rb = &dtr->unused.rb;
const ngtcp2_dcid *src;
assert(ngtcp2_ringbuf_len(rb));
src = ngtcp2_ringbuf_get(rb, 0);
dest->flags = NGTCP2_DCID_FLAG_NONE;
ngtcp2_dcid_copy_cid_token(dest, src);
ngtcp2_ringbuf_pop_front(rb);
}
void ngtcp2_dcidtr_pop_unused(ngtcp2_dcidtr *dtr, ngtcp2_dcid *dest) {
ngtcp2_ringbuf *rb = &dtr->unused.rb;
const ngtcp2_dcid *src;
assert(ngtcp2_ringbuf_len(rb));
src = ngtcp2_ringbuf_get(rb, 0);
ngtcp2_dcid_copy(dest, src);
ngtcp2_ringbuf_pop_front(rb);
}
int ngtcp2_dcidtr_check_path_retired(const ngtcp2_dcidtr *dtr,
const ngtcp2_path *path) {
const ngtcp2_ringbuf *rb = &dtr->retired.rb;
size_t i, len = ngtcp2_ringbuf_len(rb);
const ngtcp2_dcid *dcid;
for (i = 0; i < len; ++i) {
dcid = ngtcp2_ringbuf_get(rb, i);
if (ngtcp2_path_eq(&dcid->ps.path, path)) {
return 1;
}
}
return 0;
}
size_t ngtcp2_dcidtr_unused_len(const ngtcp2_dcidtr *dtr) {
return ngtcp2_ringbuf_len(&dtr->unused.rb);
}
size_t ngtcp2_dcidtr_bound_len(const ngtcp2_dcidtr *dtr) {
return ngtcp2_ringbuf_len(&dtr->bound.rb);
}
size_t ngtcp2_dcidtr_retired_len(const ngtcp2_dcidtr *dtr) {
return ngtcp2_ringbuf_len(&dtr->retired.rb);
}
size_t ngtcp2_dcidtr_inactive_len(const ngtcp2_dcidtr *dtr) {
return ngtcp2_ringbuf_len(&dtr->unused.rb) +
ngtcp2_ringbuf_len(&dtr->bound.rb);
}
int ngtcp2_dcidtr_unused_full(const ngtcp2_dcidtr *dtr) {
return ngtcp2_ringbuf_full(&dtr->unused.rb);
}
int ngtcp2_dcidtr_unused_empty(const ngtcp2_dcidtr *dtr) {
return ngtcp2_ringbuf_len(&dtr->unused.rb) == 0;
}
int ngtcp2_dcidtr_bound_full(const ngtcp2_dcidtr *dtr) {
return ngtcp2_ringbuf_full(&dtr->bound.rb);
}

343
deps/ngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h vendored Normal file
View File

@ -0,0 +1,343 @@
/*
* 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_DCIDTR_H
#define NGTCP2_DCIDTR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* defined(HAVE_CONFIG_H) */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_cid.h"
#include "ngtcp2_ringbuf.h"
/* NGTCP2_DCIDTR_MAX_BOUND_DCID_SIZE is the maximum number of
Destination Connection ID which has been bound to a particular
path, but not yet used as primary path, and path validation is not
performed from the local endpoint. It must be the power of 2. */
#define NGTCP2_DCIDTR_MAX_BOUND_DCID_SIZE 4
/* NGTCP2_DCIDTR_MAX_UNUSED_DCID_SIZE is the maximum number of
Destination Connection ID the remote endpoint provides to store.
It must be the power of 2. */
#define NGTCP2_DCIDTR_MAX_UNUSED_DCID_SIZE 8
/* NGTCP2_DCIDTR_MAX_RETIRED_DCID_SIZE is the maximum number of
retired Destination Connection ID kept to catch in-flight packet on
a retired path. It must be the power of 2. */
#define NGTCP2_DCIDTR_MAX_RETIRED_DCID_SIZE 2
ngtcp2_static_ringbuf_def(dcid_bound, NGTCP2_DCIDTR_MAX_BOUND_DCID_SIZE,
sizeof(ngtcp2_dcid))
ngtcp2_static_ringbuf_def(dcid_unused, NGTCP2_DCIDTR_MAX_UNUSED_DCID_SIZE,
sizeof(ngtcp2_dcid))
ngtcp2_static_ringbuf_def(dcid_retired, NGTCP2_DCIDTR_MAX_RETIRED_DCID_SIZE,
sizeof(ngtcp2_dcid))
/*
* ngtcp2_dcidtr stores unused, bound, and retired Destination
* Connection IDs.
*/
typedef struct ngtcp2_dcidtr {
/* unused is a set of unused Destination Connection ID received from
a remote endpoint. They are considered inactive. */
ngtcp2_static_ringbuf_dcid_unused unused;
/* bound is a set of Destination Connection IDs which are bound to
particular paths. These paths are not validated yet. They are
considered inactive. */
ngtcp2_static_ringbuf_dcid_bound bound;
/* retired is a set of Destination Connection ID retired by local
endpoint. Keep them in 3*PTO to catch packets in flight along
the old path. They are considered active. */
ngtcp2_static_ringbuf_dcid_retired retired;
struct {
/* seqs contains sequence number of Destination Connection ID
whose retirement is not acknowledged by the remote endpoint
yet. */
uint64_t seqs[NGTCP2_DCIDTR_MAX_UNUSED_DCID_SIZE * 2];
/* len is the number of sequence numbers that seq contains. */
size_t len;
} retire_unacked;
} ngtcp2_dcidtr;
typedef int (*ngtcp2_dcidtr_cb)(const ngtcp2_dcid *dcid, void *user_data);
/*
* ngtcp2_dcidtr_init initializes |dtr|.
*/
void ngtcp2_dcidtr_init(ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_track_retired_seq tracks the sequence number |seq| of
* unacknowledged retiring Destination Connection ID.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_CONNECTION_ID_LIMIT
* The number of unacknowledged retirement exceeds the limit.
*/
int ngtcp2_dcidtr_track_retired_seq(ngtcp2_dcidtr *dtr, uint64_t seq);
/*
* ngtcp2_dcidtr_untrack_retired_seq deletes the sequence number |seq|
* of unacknowledged retiring Destination Connection ID. It is fine
* if such sequence number is not found.
*/
void ngtcp2_dcidtr_untrack_retired_seq(ngtcp2_dcidtr *dtr, uint64_t seq);
/*
* ngtcp2_dcidtr_check_retired_seq_tracked returns nonzero if |seq|
* has already been tracked.
*/
int ngtcp2_dcidtr_check_retired_seq_tracked(const ngtcp2_dcidtr *dtr,
uint64_t seq);
/*
* ngtcp2_dcidtr_find_bound_dcid returns the pointer to ngtcp2_dcid
* that bound to |path|. It returns NULL if there is no such
* ngtcp2_dcid.
*/
ngtcp2_dcid *ngtcp2_dcidtr_find_bound_dcid(const ngtcp2_dcidtr *dtr,
const ngtcp2_path *path);
/*
* ngtcp2_dcidtr_bind_zerolen_dcid binds zero-length Destination
* Connection ID to |path|, and returns the pointer to the bound
* ngtcp2_dcid.
*/
ngtcp2_dcid *ngtcp2_dcidtr_bind_zerolen_dcid(ngtcp2_dcidtr *dtr,
const ngtcp2_path *path);
/*
* ngtcp2_dcidtr_bind_dcid binds non-zero Destination Connection ID to
* |path|. |ts| is the current timestamp. The buffer space of bound
* Destination Connection ID is limited. If it is full, the earliest
* one is removed. |on_retire|, if specified, is called for the
* removed ngtcp2_dcid with |user_data|. This function assigns the
* pointer to bound ngtcp2_dcid to |*pdest|.
*
* This function returns 0 if it succeeds, or negative error code that
* |on_retire| returns.
*/
int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest,
const ngtcp2_path *path, ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_retire, void *user_data);
/*
* ngtcp2_dcidtr_verify_stateless_reset verifies the stateless reset
* token |token| received from |path|. It returns 0 if it succeeds,
* or one of the following negative error codes:
*
* NGTCP2_ERR_INVALID_ARGUMENT
* 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);
/*
* ngtcp2_dcidtr_verify_token_uniqueness verifies that the uniqueness
* of the combination of |seq|, |cid|, and |token| against the exiting
* Destination Connection IDs. That is:
*
* - If they do not share the same seq, then their Connection IDs must
* be different.
*
* - If they share the same seq, then their Connection IDs and tokens
* must be the same.
*
* If this function succeeds, and there is Destination Connection ID
* which shares |seq|, |cid|, and |token|, |*pfound| is set to
* nonzero.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_PROTO
* 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);
/*
* ngtcp2_dcidtr_retire_inactive_dcid_prior_to retires inactive
* Destination Connection IDs (unused or bound) whose seq is less than
* |seq|. For each retired ngtcp2_dcid, |on_retire|, if specified, is
* called with |user_data|.
*
* This function returns 0 if it succeeds, or negative error code that
* |on_retire| returns.
*/
int ngtcp2_dcidtr_retire_inactive_dcid_prior_to(ngtcp2_dcidtr *dtr,
uint64_t seq,
ngtcp2_dcidtr_cb on_retire,
void *user_data);
/*
* ngtcp2_dcidtr_retire_active_dcid adds an active |dcid| to the
* retired Destination Connection ID buffer. The buffer space of
* retired Destination Connection ID is limited. If it is full, the
* earliest one is removed. |on_deactivate| is called for the removed
* ngtcp2_dcid with |user_data|.
*
* This function returns 0 if it succeeds, or negative error code that
* |on_deactivate| returns.
*/
int ngtcp2_dcidtr_retire_active_dcid(ngtcp2_dcidtr *dtr,
const ngtcp2_dcid *dcid, ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_deactivate,
void *user_data);
/*
* ngtcp2_dcidtr_retire_stale_bound_dcid retires stale bound
* Destination Connection ID. For each retired ngtcp2_dcid,
* |on_retire|, if specified, is called with |user_data|.
*/
int ngtcp2_dcidtr_retire_stale_bound_dcid(ngtcp2_dcidtr *dtr,
ngtcp2_duration timeout,
ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_retire,
void *user_data);
/*
* ngtcp2_dcidtr_remove_stale_retired_dcid removes stale retired
* Destination Connection ID. For each removed ngtcp2_dcid,
* |on_deactivate| is called with |user_data|.
*
* This function returns 0 if it succeeds, or negative error code that
* |on_deactivate| returns.
*/
int ngtcp2_dcidtr_remove_stale_retired_dcid(ngtcp2_dcidtr *dtr,
ngtcp2_duration timeout,
ngtcp2_tstamp ts,
ngtcp2_dcidtr_cb on_deactivate,
void *user_data);
/*
* ngtcp2_dcidtr_pop_bound_dcid removes Destination Connection ID that
* is bound to |path|, and copies it into the object pointed by
* |dest|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_INVALID_ARGUMENT
* No ngtcp2_dcid bound to |path| found.
*/
int ngtcp2_dcidtr_pop_bound_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid *dest,
const ngtcp2_path *path);
/*
* ngtcp2_dcidtr_earliest_bound_ts returns earliest timestamp when a
* Destination Connection ID is bound. If there is no bound
* Destination Connection ID, this function returns UINT64_MAX.
*/
ngtcp2_tstamp ngtcp2_dcidtr_earliest_bound_ts(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_earliest_retired_ts returns earliest timestamp when a
* Destination Connection ID is retired. If there is no retired
* Destination Connection ID, this function returns UINT64_MAX.
*/
ngtcp2_tstamp ngtcp2_dcidtr_earliest_retired_ts(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_push_unused adds new Destination Connection ID to the
* unused buffer. |seq| is its sequence number, |cid| is its
* Connection ID, and |token| is its stateless reset token. If the
* 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);
/*
* ngtcp2_dcidtr_pop_unused_cid_token removes an unused Destination
* Connection ID, and copies it into the object pointed by |dcid| with
* ngtcp2_dcid_copy_cid_token. This function assumes that there is at
* least one unused Destination Connection ID.
*/
void ngtcp2_dcidtr_pop_unused_cid_token(ngtcp2_dcidtr *dtr, ngtcp2_dcid *dcid);
/*
* ngtcp2_dcidtr_pop_unused removes an unused Destination Connection
* ID, and copies it into the object pointed by |dcid| with
* ngtcp2_dcid_copy. This function assumes that there is at least one
* unused Destination Connection ID.
*/
void ngtcp2_dcidtr_pop_unused(ngtcp2_dcidtr *dtr, ngtcp2_dcid *dcid);
/*
* ngtcp2_dcidtr_check_path_retired returns nonzero if |path| is
* included in retired Destination Connection IDs.
*/
int ngtcp2_dcidtr_check_path_retired(const ngtcp2_dcidtr *dtr,
const ngtcp2_path *path);
/*
* ngtcp2_dcidtr_unused_len returns the number of unused Destination
* Connection ID.
*/
size_t ngtcp2_dcidtr_unused_len(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_bound_len returns the number of bound Destination
* Connection ID.
*/
size_t ngtcp2_dcidtr_bound_len(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_retired_len returns the number of retired Destination
* Connection ID.
*/
size_t ngtcp2_dcidtr_retired_len(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_inactive_len returns the number of unused and bound
* Destination Connection ID.
*/
size_t ngtcp2_dcidtr_inactive_len(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_unused_full returns nonzero if the buffer of unused
* Destination Connection ID is full.
*/
int ngtcp2_dcidtr_unused_full(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_unused_empty returns nonzero if the buffer of unused
* Destination Connection ID is empty.
*/
int ngtcp2_dcidtr_unused_empty(const ngtcp2_dcidtr *dtr);
/*
* ngtcp2_dcidtr_bound_full returns nonzero if the buffer of bound
* Destination Connection ID is full.
*/
int ngtcp2_dcidtr_bound_full(const ngtcp2_dcidtr *dtr);
#endif /* NGTCP2_DCIDTR_H */

View File

@ -29,17 +29,6 @@
ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent)
int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem) {
*pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain));
if (*pfrc == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_frame_chain_init(*pfrc);
return 0;
}
int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc,
ngtcp2_objalloc *objalloc) {
*pfrc = ngtcp2_objalloc_frame_chain_get(objalloc);
@ -83,13 +72,13 @@ int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
size_t tokenlen,
ngtcp2_objalloc *objalloc,
const ngtcp2_mem *mem) {
size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token);
int rv;
uint8_t *p;
ngtcp2_frame *fr;
if (tokenlen > avail) {
rv = ngtcp2_frame_chain_extralen_new(pfrc, tokenlen - avail, mem);
if (tokenlen > NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES) {
rv = ngtcp2_frame_chain_extralen_new(
pfrc, tokenlen - NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES, mem);
} else {
rv = ngtcp2_frame_chain_objalloc_new(pfrc, objalloc);
}
@ -144,8 +133,7 @@ void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
break;
case NGTCP2_FRAME_NEW_TOKEN:
if (frc->fr.new_token.tokenlen >
sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token)) {
if (frc->fr.new_token.tokenlen > NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES) {
ngtcp2_frame_chain_del(frc, mem);
return;

View File

@ -95,28 +95,15 @@ int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b,
#define NGTCP2_MAX_STREAM_DATACNT 256
/*
* ngtcp2_frame_chain_new allocates ngtcp2_frame_chain object and
* assigns its pointer to |*pfrc|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_objalloc_new behaves like
* ngtcp2_frame_chain_new, but it uses |objalloc| to allocate the object.
* ngtcp2_frame_chain_objalloc_new allocates ngtcp2_frame_chain using
* |objalloc|.
*/
int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc,
ngtcp2_objalloc *objalloc);
/*
* ngtcp2_frame_chain_extralen_new works like ngtcp2_frame_chain_new,
* but it allocates extra memory |extralen| in order to extend
* ngtcp2_frame.
* ngtcp2_frame_chain_extralen_new allocates ngtcp2_frame_chain
* followed by |extralen| bytes.
*/
int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
const ngtcp2_mem *mem);
@ -134,12 +121,18 @@ int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
#define NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES \
(NGTCP2_FRAME_CHAIN_STREAM_AVAIL / sizeof(ngtcp2_vec) + 1)
/* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES is the length of a token that
changes allocation method. If the length is more than this value,
ngtcp2_frame_chain is allocated without ngtcp2_objalloc.
Otherwise, it is allocated using ngtcp2_objalloc. */
#define NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES \
(sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token))
/*
* ngtcp2_frame_chain_stream_datacnt_objalloc_new works like
* ngtcp2_frame_chain_new, but it allocates enough data to store
* additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_stream
* object. If no additional space is required, in other words,
* |datacnt| <= NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES,
* ngtcp2_frame_chain_stream_datacnt_objalloc_new allocates enough
* data to store additional |datacnt| - 1 ngtcp2_vec object after
* ngtcp2_stream object. If no additional space is required, in other
* words, |datacnt| <= NGTCP2_FRAME_CHAIN_STREAM_DATACNT_THRES,
* ngtcp2_frame_chain_objalloc_new is called internally. Otherwise,
* ngtcp2_frame_chain_extralen_new is used and objalloc is not used.
* Therefore, it is important to call ngtcp2_frame_chain_objalloc_del
@ -150,6 +143,13 @@ int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc,
ngtcp2_objalloc *objalloc,
const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_new_token_objalloc_new allocates enough space to
* store the given token. If |tokenlen| <=
* NGTCP2_FRAME_CHAIN_NEW_TOKEN_THRES, ngtcp2_frame_chain_objalloc_new
* is called internally. Otherwise, ngtcp2_frame_chain_extralen_new
* is used, and objalloc is not used.
*/
int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
const uint8_t *token,
size_t tokenlen,

View File

@ -35,7 +35,9 @@ void ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) {
}
static int gaptr_gap_init(ngtcp2_gaptr *gaptr) {
ngtcp2_range range = {0, UINT64_MAX};
ngtcp2_range range = {
.end = UINT64_MAX,
};
return ngtcp2_ksl_insert(&gaptr->gap, NULL, &range, NULL);
}
@ -50,7 +52,11 @@ void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr) {
int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, uint64_t datalen) {
int rv;
ngtcp2_range k, m, l, r, q = {offset, offset + datalen};
ngtcp2_range k, m, l, r;
ngtcp2_range q = {
.begin = offset,
.end = offset + datalen,
};
ngtcp2_ksl_it it;
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
@ -110,11 +116,16 @@ uint64_t ngtcp2_gaptr_first_gap_offset(const ngtcp2_gaptr *gaptr) {
ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
uint64_t offset) {
ngtcp2_range q = {offset, offset + 1};
ngtcp2_range q = {
.begin = offset,
.end = offset + 1,
};
ngtcp2_ksl_it it;
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
ngtcp2_range r = {0, UINT64_MAX};
ngtcp2_range r = {
.end = UINT64_MAX,
};
return r;
}
@ -128,7 +139,10 @@ ngtcp2_range ngtcp2_gaptr_get_first_gap_after(const ngtcp2_gaptr *gaptr,
int ngtcp2_gaptr_is_pushed(const ngtcp2_gaptr *gaptr, uint64_t offset,
uint64_t datalen) {
ngtcp2_range q = {offset, offset + datalen};
ngtcp2_range q = {
.begin = offset,
.end = offset + datalen,
};
ngtcp2_ksl_it it;
ngtcp2_range m;
@ -138,6 +152,9 @@ int ngtcp2_gaptr_is_pushed(const ngtcp2_gaptr *gaptr, uint64_t offset,
it = ngtcp2_ksl_lower_bound_search(&gaptr->gap, &q,
ngtcp2_ksl_range_exclusive_search);
assert(!ngtcp2_ksl_it_end(&it));
m = ngtcp2_range_intersect(&q, (ngtcp2_range *)ngtcp2_ksl_it_key(&it));
return ngtcp2_range_len(&m) == 0;

View File

@ -33,7 +33,7 @@
#include "ngtcp2_mem.h"
#include "ngtcp2_range.h"
static ngtcp2_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}};
static ngtcp2_ksl_blk null_blk;
ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent)

View File

@ -119,7 +119,11 @@ void ngtcp2_map_print_distance(const ngtcp2_map *map) {
static int insert(ngtcp2_map_bucket *table, size_t hashbits,
ngtcp2_map_key_type key, void *data) {
size_t idx = hash(key, hashbits);
ngtcp2_map_bucket b = {0, key, data}, *bkt;
ngtcp2_map_bucket b = {
.key = key,
.data = data,
};
ngtcp2_map_bucket *bkt;
size_t mask = (1u << hashbits) - 1;
for (;;) {

View File

@ -51,8 +51,12 @@ static void *default_realloc(void *ptr, size_t size, void *user_data) {
return realloc(ptr, size);
}
static const ngtcp2_mem mem_default = {NULL, default_malloc, default_free,
default_calloc, default_realloc};
static const ngtcp2_mem mem_default = {
.malloc = default_malloc,
.free = default_free,
.calloc = default_calloc,
.realloc = default_realloc,
};
const ngtcp2_mem *ngtcp2_mem_default(void) { return &mem_default; }

View File

@ -145,8 +145,7 @@ int ngtcp2_pkt_decode_version_cid(ngtcp2_version_cid *dest, const uint8_t *data,
void ngtcp2_pkt_hd_init(ngtcp2_pkt_hd *hd, uint8_t flags, uint8_t type,
const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
int64_t pkt_num, size_t pkt_numlen, uint32_t version,
size_t len) {
int64_t pkt_num, size_t pkt_numlen, uint32_t version) {
hd->flags = flags;
hd->type = type;
@ -167,7 +166,7 @@ void ngtcp2_pkt_hd_init(ngtcp2_pkt_hd *hd, uint8_t flags, uint8_t type,
hd->tokenlen = 0;
hd->pkt_numlen = pkt_numlen;
hd->version = version;
hd->len = len;
hd->len = 0;
}
ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt,
@ -2285,8 +2284,7 @@ ngtcp2_ssize ngtcp2_pkt_write_retry(
}
ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_RETRY, dcid,
scid, /* pkt_num = */ 0, /* pkt_numlen = */ 1, version,
/* len = */ 0);
scid, /* pkt_num = */ 0, /* pkt_numlen = */ 1, version);
pseudo_retrylen =
ngtcp2_pkt_encode_pseudo_retry(pseudo_retry, sizeof(pseudo_retry), &hd,

View File

@ -57,6 +57,10 @@
#define NGTCP2_STREAM_LEN_BIT 0x02
#define NGTCP2_STREAM_OFF_BIT 0x04
/* NGTCP2_MIN_QUIC_PKTLEN is the minimum length of a valid QUIC
packet. */
#define NGTCP2_MIN_QUIC_PKTLEN 21
/* NGTCP2_STREAM_OVERHEAD is the maximum number of bytes required
other than payload for STREAM frame. That is from type field to
the beginning of the payload. */
@ -407,13 +411,11 @@ void ngtcp2_pkt_chain_del(ngtcp2_pkt_chain *pc, const ngtcp2_mem *mem);
* |dcid| and/or |scid| is NULL, Destination Connection ID and/or
* Source Connection ID of |hd| is empty respectively. |pkt_numlen|
* is the number of bytes used to encode |pkt_num| and either 1, 2, or
* 4. |version| is QUIC version for long header. |len| is the length
* field of Initial, 0RTT, and Handshake packets.
* 4. |version| is QUIC version for long header.
*/
void ngtcp2_pkt_hd_init(ngtcp2_pkt_hd *hd, uint8_t flags, uint8_t type,
const ngtcp2_cid *dcid, const ngtcp2_cid *scid,
int64_t pkt_num, size_t pkt_numlen, uint32_t version,
size_t len);
int64_t pkt_num, size_t pkt_numlen, uint32_t version);
/*
* ngtcp2_pkt_encode_hd_long encodes |hd| as QUIC long header into

View File

@ -161,19 +161,3 @@ void ngtcp2_pq_remove(ngtcp2_pq *pq, ngtcp2_pq_entry *item) {
int ngtcp2_pq_empty(const ngtcp2_pq *pq) { return pq->length == 0; }
size_t ngtcp2_pq_size(const ngtcp2_pq *pq) { return pq->length; }
int ngtcp2_pq_each(const ngtcp2_pq *pq, ngtcp2_pq_item_cb fun, void *arg) {
size_t i;
if (pq->length == 0) {
return 0;
}
for (i = 0; i < pq->length; ++i) {
if ((*fun)(pq->q[i], arg)) {
return 1;
}
}
return 0;
}

View File

@ -109,17 +109,6 @@ int ngtcp2_pq_empty(const ngtcp2_pq *pq);
*/
size_t ngtcp2_pq_size(const ngtcp2_pq *pq);
typedef int (*ngtcp2_pq_item_cb)(ngtcp2_pq_entry *item, void *arg);
/*
* ngtcp2_pq_each applies |fun| to each item in |pq|. The |arg| is
* passed as arg parameter to callback function. This function must
* not change the ordering key. If the return value from callback is
* nonzero, this function returns 1 immediately without iterating
* remaining items. Otherwise this function returns 0.
*/
int ngtcp2_pq_each(const ngtcp2_pq *pq, ngtcp2_pq_item_cb fun, void *arg);
/*
* ngtcp2_pq_remove removes |item| from |pq|. |pq| must contain
* |item| otherwise the behavior is undefined.

View File

@ -170,3 +170,10 @@ void ngtcp2_pv_cancel_expired_timer(ngtcp2_pv *pv, ngtcp2_tstamp ts) {
pv->flags |= NGTCP2_PV_FLAG_CANCEL_TIMER;
}
void ngtcp2_pv_set_fallback(ngtcp2_pv *pv, const ngtcp2_dcid *dcid,
ngtcp2_duration pto) {
pv->flags |= NGTCP2_PV_FLAG_FALLBACK_PRESENT;
ngtcp2_dcid_copy(&pv->fallback_dcid, dcid);
pv->fallback_pto = pto;
}

View File

@ -71,11 +71,13 @@ void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
/* NGTCP2_PV_FLAG_CANCEL_TIMER indicates that the expiry timer is
cancelled. */
#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02u
/* NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE indicates that fallback DCID is
available in ngtcp2_pv. If path validation fails, fallback to the
fallback DCID. If path validation succeeds, fallback DCID is
retired if it does not equal to the current DCID. */
#define NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE 0x04u
/* 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
/* 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
@ -191,4 +193,10 @@ ngtcp2_tstamp ngtcp2_pv_next_expiry(ngtcp2_pv *pv);
*/
void ngtcp2_pv_cancel_expired_timer(ngtcp2_pv *pv, ngtcp2_tstamp ts);
/*
* ngtcp2_pv_set_fallback sets |dcid| and |pto| as fallback.
*/
void ngtcp2_pv_set_fallback(ngtcp2_pv *pv, const ngtcp2_dcid *dcid,
ngtcp2_duration pto);
#endif /* !defined(NGTCP2_PV_H) */

View File

@ -32,7 +32,7 @@ void ngtcp2_range_init(ngtcp2_range *r, uint64_t begin, uint64_t end) {
ngtcp2_range ngtcp2_range_intersect(const ngtcp2_range *a,
const ngtcp2_range *b) {
ngtcp2_range r = {0, 0};
ngtcp2_range r = {0};
uint64_t begin = ngtcp2_max_uint64(a->begin, b->begin);
uint64_t end = ngtcp2_min_uint64(a->end, b->end);

View File

@ -122,4 +122,6 @@ void *ngtcp2_ringbuf_get(const ngtcp2_ringbuf *rb, size_t offset) {
return &rb->buf[offset * rb->size];
}
int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->mask + 1; }
int ngtcp2_ringbuf_full(const ngtcp2_ringbuf *rb) {
return rb->len == rb->mask + 1;
}

View File

@ -113,7 +113,7 @@ void *ngtcp2_ringbuf_get(const ngtcp2_ringbuf *rb, size_t offset);
#define ngtcp2_ringbuf_len(RB) ((RB)->len)
/* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb);
int ngtcp2_ringbuf_full(const ngtcp2_ringbuf *rb);
/* ngtcp2_static_ringbuf_def defines ngtcp2_ringbuf struct wrapper
which uses a statically allocated buffer. ngtcp2_ringbuf_free

View File

@ -122,7 +122,10 @@ static int rob_write_data(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
size_t n;
int rv;
ngtcp2_rob_data *d;
ngtcp2_range range = {offset, offset + len};
ngtcp2_range range = {
.begin = offset,
.end = offset + len,
};
ngtcp2_ksl_it it;
for (it = ngtcp2_ksl_lower_bound_search(&rob->dataksl, &range,
@ -163,7 +166,11 @@ int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
size_t datalen) {
int rv;
ngtcp2_rob_gap *g;
ngtcp2_range m, l, r, q = {offset, offset + datalen};
ngtcp2_range m, l, r;
ngtcp2_range q = {
.begin = offset,
.end = offset + datalen,
};
ngtcp2_ksl_it it;
it = ngtcp2_ksl_lower_bound_search(&rob->gapksl, &q,

View File

@ -46,6 +46,11 @@ void ngtcp2_rs_init(ngtcp2_rs *rs) {
}
void ngtcp2_rst_init(ngtcp2_rst *rst) {
rst->last_seq = -1;
ngtcp2_rst_reset(rst);
}
void ngtcp2_rst_reset(ngtcp2_rst *rst) {
ngtcp2_rs_init(&rst->rs);
rst->delivered = 0;
rst->delivered_ts = 0;
@ -53,7 +58,7 @@ void ngtcp2_rst_init(ngtcp2_rst *rst) {
rst->app_limited = 0;
rst->is_cwnd_limited = 0;
rst->lost = 0;
rst->last_seq = -1;
rst->valid_after_seq = rst->last_seq;
}
void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
@ -108,6 +113,10 @@ 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;

View File

@ -73,11 +73,17 @@ 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;
void ngtcp2_rst_init(ngtcp2_rst *rst);
void ngtcp2_rst_reset(ngtcp2_rst *rst);
void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
const ngtcp2_conn_stat *cstat);
void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat);

View File

@ -101,7 +101,6 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_rst *rst, ngtcp2_cc *cc,
rtb->probe_pkt_left = 0;
rtb->cc_pkt_num = cc_pkt_num;
rtb->cc_bytes_in_flight = 0;
rtb->persistent_congestion_start_ts = UINT64_MAX;
rtb->num_lost_pkts = 0;
rtb->num_lost_pmtud_pkts = 0;
}
@ -672,8 +671,8 @@ static int process_acked_pkt(ngtcp2_rtb_entry *ent, ngtcp2_conn *conn,
break;
case NGTCP2_FRAME_RETIRE_CONNECTION_ID:
ngtcp2_conn_untrack_retired_dcid_seq(conn,
frc->fr.retire_connection_id.seq);
ngtcp2_dcidtr_untrack_retired_seq(&conn->dcid.dtr,
frc->fr.retire_connection_id.seq);
break;
case NGTCP2_FRAME_NEW_CONNECTION_ID:
assert(conn->scid.num_in_flight);
@ -734,11 +733,11 @@ static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
if ((ecn_acked && fr->type == NGTCP2_FRAME_ACK) ||
(fr->type == NGTCP2_FRAME_ACK_ECN &&
(pktns->rx.ecn.ack.ect0 > fr->ecn.ect0 ||
pktns->rx.ecn.ack.ect1 > fr->ecn.ect1 ||
pktns->rx.ecn.ack.ce > fr->ecn.ce ||
(fr->ecn.ect0 - pktns->rx.ecn.ack.ect0) +
(fr->ecn.ce - pktns->rx.ecn.ack.ce) <
(pktns->acktr.ecn.ack.ect0 > fr->ecn.ect0 ||
pktns->acktr.ecn.ack.ect1 > fr->ecn.ect1 ||
pktns->acktr.ecn.ack.ce > fr->ecn.ce ||
(fr->ecn.ect0 - pktns->acktr.ecn.ack.ect0) +
(fr->ecn.ce - pktns->acktr.ecn.ack.ce) <
ecn_acked ||
fr->ecn.ect0 > pktns->tx.ecn.ect0 || fr->ecn.ect1))) {
ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
@ -755,13 +754,13 @@ static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
if (fr->type == NGTCP2_FRAME_ACK_ECN) {
if (cc->congestion_event && largest_pkt_sent_ts != UINT64_MAX &&
fr->ecn.ce > pktns->rx.ecn.ack.ce) {
fr->ecn.ce > pktns->acktr.ecn.ack.ce) {
cc->congestion_event(cc, cstat, largest_pkt_sent_ts, 0, ts);
}
pktns->rx.ecn.ack.ect0 = fr->ecn.ect0;
pktns->rx.ecn.ack.ect1 = fr->ecn.ect1;
pktns->rx.ecn.ack.ce = fr->ecn.ce;
pktns->acktr.ecn.ack.ect0 = fr->ecn.ect0;
pktns->acktr.ecn.ack.ect1 = fr->ecn.ect1;
pktns->acktr.ecn.ack.ce = fr->ecn.ce;
}
}
@ -1052,7 +1051,7 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost,
max_ack_delay) *
NGTCP2_PERSISTENT_CONGESTION_THRESHOLD;
start_ts = ngtcp2_max_uint64(rtb->persistent_congestion_start_ts,
start_ts = ngtcp2_max_uint64(conn->handshake_confirmed_ts,
cstat->first_rtt_sample_ts);
for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) {

View File

@ -184,10 +184,6 @@ typedef struct ngtcp2_rtb {
count a packet whose packet number is greater than or equals to
cc_pkt_num. */
uint64_t cc_bytes_in_flight;
/* persistent_congestion_start_ts is the time when persistent
congestion evaluation is started. It happens roughly after
handshake is confirmed. */
ngtcp2_tstamp persistent_congestion_start_ts;
/* num_lost_pkts is the number entries in ents which has
NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set. */
size_t num_lost_pkts;

View File

@ -410,7 +410,7 @@ static int decode_varint(uint64_t *pdest, const uint8_t **pp,
}
len = ngtcp2_get_uvarintlen(p);
if ((uint64_t)(end - p) < len) {
if ((size_t)(end - p) < len) {
return -1;
}
@ -530,8 +530,11 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version,
params->active_connection_id_limit =
NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
p = data;
end = data + datalen;
p = end = data;
if (datalen) {
end += datalen;
}
for (; (size_t)(end - p) >= 2;) {
if (decode_varint(&param_type, &p, end) != 0) {

View File

@ -35,33 +35,6 @@ ngtcp2_vec *ngtcp2_vec_init(ngtcp2_vec *vec, const uint8_t *base, size_t len) {
return vec;
}
int ngtcp2_vec_new(ngtcp2_vec **pvec, const uint8_t *data, size_t datalen,
const ngtcp2_mem *mem) {
size_t len;
uint8_t *p;
len = sizeof(ngtcp2_vec) + datalen;
*pvec = ngtcp2_mem_malloc(mem, len);
if (*pvec == NULL) {
return NGTCP2_ERR_NOMEM;
}
p = (uint8_t *)(*pvec) + sizeof(ngtcp2_vec);
(*pvec)->base = p;
(*pvec)->len = datalen;
if (datalen) {
/* p = */ ngtcp2_cpymem(p, data, datalen);
}
return 0;
}
void ngtcp2_vec_del(ngtcp2_vec *vec, const ngtcp2_mem *mem) {
ngtcp2_mem_free(mem, vec);
}
uint64_t ngtcp2_vec_len(const ngtcp2_vec *vec, size_t n) {
size_t i;
size_t res = 0;
@ -225,13 +198,14 @@ size_t ngtcp2_vec_copy_at_most(ngtcp2_vec *dst, size_t dstcnt,
continue;
}
dst[j] = src[i];
if (dst[j].len > left) {
if (src[i].len > left) {
dst[j].base = src[i].base;
dst[j].len = left;
return j + 1;
}
dst[j] = src[i];
left -= dst[j].len;
++i;
++j;

View File

@ -46,22 +46,6 @@
*/
ngtcp2_vec *ngtcp2_vec_init(ngtcp2_vec *vec, const uint8_t *base, size_t len);
/*
* ngtcp2_vec_new allocates and initializes |*pvec| with given |data|
* of length |datalen|. This function allocates memory for |*pvec|
* and the given data with a single allocation, and the contents
* pointed by |data| is copied into the allocated memory space. To
* free the allocated memory, call ngtcp2_vec_del.
*/
int ngtcp2_vec_new(ngtcp2_vec **pvec, const uint8_t *data, size_t datalen,
const ngtcp2_mem *mem);
/*
* ngtcp2_vec_del frees the memory allocated by |vec| which is
* allocated and initialized by ngtcp2_vec_new.
*/
void ngtcp2_vec_del(ngtcp2_vec *vec, const ngtcp2_mem *mem);
/*
* ngtcp2_vec_len returns the sum of length in |vec| of |n| elements.
*/