From: Jan Doskočil Date: Fri, 25 Jul 2025 15:31:21 +0000 (+0200) Subject: libngtcp2: update embedded library to v1.14.0 X-Git-Tag: v3.5.0~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=048c94982da33d4b487973bb1d839d34800aad2b;p=thirdparty%2Fknot-dns.git libngtcp2: update embedded library to v1.14.0 --- diff --git a/src/contrib/Makefile.inc b/src/contrib/Makefile.inc index bae9078bf0..36832c8ffa 100644 --- a/src/contrib/Makefile.inc +++ b/src/contrib/Makefile.inc @@ -222,6 +222,8 @@ libembngtcp2_la_SOURCES = \ contrib/libngtcp2/ngtcp2/lib/ngtcp2_window_filter.h \ contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c \ contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h \ + contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c \ + contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h \ contrib/libngtcp2/ngtcp2/ngtcp2.h \ contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h \ contrib/libngtcp2/ngtcp2/ngtcp2_crypto_gnutls.h \ diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c index 04612f11be..a2ffeb6188 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c @@ -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); @@ -175,8 +174,9 @@ 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); +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); @@ -288,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); @@ -344,7 +344,7 @@ static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) { bbr->inflight_latest = 0; } -static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) { +static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr) { bbr->bw_shortterm = UINT64_MAX; bbr->inflight_shortterm = UINT64_MAX; } @@ -707,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; @@ -744,7 +744,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, return; } - bbr_adapt_upper_bounds(bbr, cstat, ack); + bbr_adapt_longterm_model(bbr, cstat, ack); if (!bbr_is_in_probe_bw_state(bbr)) { return; @@ -756,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); } @@ -785,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; - - 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; - } +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)); - 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_longterm) { bbr_reset_full_bw(bbr); bbr->full_bw = cstat->delivery_rate_sec; - } else if (bbr->full_bw_now) { - return 1; + + return 0; } - return 0; + return bbr->full_bw_now; } static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr, @@ -871,8 +863,9 @@ static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr, } } -static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { +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; @@ -917,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); @@ -980,9 +973,8 @@ 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; + assert(bbr->rst->lost >= pkt->lost); + rs->lost = bbr->rst->lost - pkt->lost; rs->is_app_limited = pkt->is_app_limited; if (bbr_is_inflight_too_high(bbr)) { @@ -1121,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); @@ -1226,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)); } } @@ -1401,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); } diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_buf.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_buf.h index e87adb1199..b2bdafc387 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_buf.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_buf.h @@ -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, diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c new file mode 100644 index 0000000000..7e77186772 --- /dev/null +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c @@ -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 +#include + +#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(); + } +} diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h new file mode 100644 index 0000000000..751766bb83 --- /dev/null +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h @@ -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 +#endif /* defined(HAVE_CONFIG_H) */ + +#include + +/* + * 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) */ diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.c index ad3665b6cf..c16953802a 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.c @@ -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,7 +150,7 @@ 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; @@ -176,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); } @@ -223,23 +226,45 @@ uint64_t ngtcp2_cbrt(uint64_t n) { #define NGTCP2_HS_CSS_GROWTH_DIVISOR 4 #define NGTCP2_HS_CSS_ROUNDS 5 -static int64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic, - const ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { +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; - int64_t tx = (int64_t)((t << 10) / NGTCP2_SECONDS); - int64_t time_delta = ngtcp2_min_int64(tx - cubic->current.k, 3600 << 10); - int64_t delta = ((((time_delta * time_delta) >> 10) * time_delta) >> 20) * - (int64_t)cstat->max_tx_udp_payload_size * 4 / 10; + uint64_t tx_m = (t << 10) / NGTCP2_SECONDS; + int neg = tx_m < cubic->current.k_m; + uint64_t time_delta_m; + uint64_t delta; + + /* 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_m = ngtcp2_min_uint64(time_delta_m, 3600 << 10); + + delta = ((((time_delta_m * time_delta_m) >> 10) * time_delta_m) >> 10) * + cstat->max_tx_udp_payload_size * 4 / 10; + delta >>= 10; + + if (neg) { + if (cubic->current.w_max < delta) { + /* Negative w_cubic is not interesting. */ + return 0; + } - return (int64_t)cubic->current.w_max + delta; + 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); - int64_t w_cubic, w_cubic_next; + uint64_t w_cubic, w_cubic_next; uint64_t target, m; ngtcp2_duration rtt_thresh; int round_start; @@ -346,13 +371,12 @@ 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 < (int64_t)cstat->cwnd) { + if (w_cubic_next < cstat->cwnd) { target = cstat->cwnd; - } else if (2 * w_cubic_next > 3 * (int64_t)cstat->cwnd) { + } else if (2 * w_cubic_next > 3 * cstat->cwnd) { target = cstat->cwnd * 3 / 2; } else { - assert(w_cubic_next >= 0); - target = (uint64_t)w_cubic_next; + target = w_cubic_next; } m = ack->bytes_delivered * cstat->max_tx_udp_payload_size + @@ -365,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 ((int64_t)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); } @@ -413,6 +437,9 @@ 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) { @@ -430,17 +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) { - cwnd_delta = cubic->current.w_max - cstat->cwnd; - } else { - cwnd_delta = cstat->cwnd - cubic->current.w_max; - } + assert(cubic->current.w_max >= cstat->cwnd); - cubic->current.k = (int64_t)ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 / - cstat->max_tx_udp_payload_size); - if (cstat->cwnd >= cubic->current.w_max) { - cubic->current.k = -cubic->current.k; - } + 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, diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.h index 296a1a433f..e4e19e1aa6 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.h @@ -329,7 +329,8 @@ void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, typedef struct ngtcp2_cubic_vars { uint64_t cwnd_prior; uint64_t w_max; - int64_t k; + /* CUBIC K with 10 bits extra precision. */ + uint64_t k_m; ngtcp2_tstamp epoch_start; uint64_t w_est; diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c index 6abebee33a..393c2281f1 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c @@ -39,6 +39,7 @@ #include "ngtcp2_net.h" #include "ngtcp2_transport_params.h" #include "ngtcp2_settings.h" +#include "ngtcp2_callbacks.h" #include "ngtcp2_tstamp.h" #include "ngtcp2_frame_chain.h" @@ -283,6 +284,33 @@ static int conn_call_remove_connection_id(ngtcp2_conn *conn, return 0; } +static int conn_call_begin_path_validation(ngtcp2_conn *conn, + const ngtcp2_pv *pv) { + int rv; + uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE; + const ngtcp2_path *old_path = NULL; + + if (!pv || !conn->callbacks.begin_path_validation) { + return 0; + } + + if (pv->flags & NGTCP2_PV_FLAG_PREFERRED_ADDR) { + flags |= NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR; + } + + if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) { + old_path = &pv->fallback_dcid.ps.path; + } + + rv = conn->callbacks.begin_path_validation(conn, flags, &pv->dcid.ps.path, + old_path, conn->user_data); + if (rv != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv, ngtcp2_path_validation_result res) { int rv; @@ -668,13 +696,13 @@ static int conn_call_recv_tx_key(ngtcp2_conn *conn, return 0; } +// pktns_init initializes |pktns|. It assumes that the object pointed +// by |pktns| is zero-cleared. static void pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id, ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num, ngtcp2_log *log, ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { - memset(pktns, 0, sizeof(*pktns)); - ngtcp2_gaptr_init(&pktns->rx.pngap, mem); pktns->tx.last_pkt_num = initial_pkt_num - 1; @@ -696,7 +724,7 @@ static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id, ngtcp2_log *log, ngtcp2_qlog *qlog, ngtcp2_objalloc *rtb_entry_objalloc, ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) { - *ppktns = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pktns)); + *ppktns = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_pktns)); if (*ppktns == NULL) { return NGTCP2_ERR_NOMEM; } @@ -1109,13 +1137,16 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, uint32_t *preferred_versions; ngtcp2_settings settingsbuf; ngtcp2_transport_params paramsbuf; - (void)callbacks_version; + ngtcp2_callbacks callbacksbuf; + uint64_t map_seed; (void)settings_version; settings = ngtcp2_settings_convert_to_latest(&settingsbuf, settings_version, settings); params = ngtcp2_transport_params_convert_to_latest( ¶msbuf, transport_params_version, params); + callbacks = ngtcp2_callbacks_convert_to_latest(&callbacksbuf, + callbacks_version, callbacks); assert(settings->max_window <= NGTCP2_MAX_VARINT); assert(settings->max_stream_window <= NGTCP2_MAX_VARINT); @@ -1217,7 +1248,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ngtcp2_pq_init(&(*pconn)->scid.used, retired_ts_less, mem); - ngtcp2_map_init(&(*pconn)->strms, mem); + callbacks->rand((uint8_t *)&map_seed, sizeof(map_seed), &settings->rand_ctx); + ngtcp2_map_init(&(*pconn)->strms, map_seed, mem); ngtcp2_pq_init(&(*pconn)->tx.strmq, cycle_less, mem); @@ -3090,6 +3122,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, ngtcp2_strm *strm; int pkt_empty = 1; uint64_t ndatalen = 0; + uint64_t wdatalen; int send_stream = 0; int stream_blocked = 0; int send_datagram = 0; @@ -3780,10 +3813,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, left = ngtcp2_ppe_left(ppe); if (*pfrc == NULL && send_stream && ngtcp2_pq_empty(&conn->tx.strmq) && - (ndatalen = ngtcp2_pkt_stream_max_datalen( + (wdatalen = ngtcp2_pkt_stream_max_datalen( vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen, left)) != (size_t)-1 && - (ndatalen || datalen == 0)) { + (wdatalen == ndatalen || wdatalen >= NGTCP2_MIN_STREAM_DATALEN) && + (wdatalen || datalen == 0)) { + ndatalen = wdatalen; datacnt = ngtcp2_vec_copy_at_most(data, NGTCP2_MAX_STREAM_DATACNT, vmsg->stream.data, vmsg->stream.datacnt, (size_t)ndatalen); @@ -5786,7 +5821,7 @@ static int conn_recv_path_response(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, conn->pv = npv; - return 0; + return conn_call_begin_path_validation(conn, conn->pv); } /* @@ -6543,6 +6578,7 @@ static int is_unrecoverable_error(int liberr) { case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM: case NGTCP2_ERR_TRANSPORT_PARAM: case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE: + case NGTCP2_ERR_INTERNAL: return 1; } @@ -7056,23 +7092,23 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) { fin = (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) && rx_offset == strm->rx.last_offset; - if (fin || datalen) { - if (fin) { - sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; - } - if (!conn_is_tls_handshake_completed(conn)) { - sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; - } - rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, - (size_t)datalen); - if (rv != 0) { - return rv; - } + assert(fin || datalen); - rv = conn_emit_pending_stream_data(conn, strm, rx_offset); - if (rv != 0) { - return rv; - } + if (fin) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN; + } + if (!conn_is_tls_handshake_completed(conn)) { + sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT; + } + rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data, + (size_t)datalen); + if (rv != 0) { + return rv; + } + + rv = conn_emit_pending_stream_data(conn, strm, rx_offset); + if (rv != 0) { + return rv; } } else if (fr->datacnt && !(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) { rv = ngtcp2_strm_recv_reordering(strm, fr->data[0].base, fr->data[0].len, @@ -8030,7 +8066,12 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) { conn->pv = pv; - return conn_call_activate_dcid(conn, &pv->dcid); + rv = conn_call_activate_dcid(conn, &pv->dcid); + if (rv != 0) { + return rv; + } + + return conn_call_begin_path_validation(conn, conn->pv); } /* @@ -8421,7 +8462,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, conn->pv = pv; - return 0; + return conn_call_begin_path_validation(conn, conn->pv); } /* @@ -13138,7 +13179,12 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn, conn->pv = pv; } - return conn_call_activate_dcid(conn, &conn->dcid.current); + rv = conn_call_activate_dcid(conn, &conn->dcid.current); + if (rv != 0) { + return rv; + } + + return conn_call_begin_path_validation(conn, conn->pv); } int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, @@ -13178,7 +13224,12 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, conn->pv = pv; - return conn_call_activate_dcid(conn, &pv->dcid); + rv = conn_call_activate_dcid(conn, &pv->dcid); + if (rv != 0) { + return rv; + } + + return conn_call_begin_path_validation(conn, conn->pv); } uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) { @@ -13454,7 +13505,7 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close( ngtcp2_crypto_km ckm; ngtcp2_crypto_cc cc; ngtcp2_ppe ppe; - ngtcp2_frame fr = {0}; + ngtcp2_frame fr; int rv; ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_INITIAL, dcid, @@ -13485,11 +13536,12 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close( return NGTCP2_ERR_NOBUF; } - fr.type = NGTCP2_FRAME_CONNECTION_CLOSE; - fr.connection_close.error_code = error_code; - fr.connection_close.frame_type = 0; - fr.connection_close.reasonlen = reasonlen; - fr.connection_close.reason = (uint8_t *)reason; + fr.connection_close = (ngtcp2_connection_close){ + .type = NGTCP2_FRAME_CONNECTION_CLOSE, + .error_code = error_code, + .reasonlen = reasonlen, + .reason = (uint8_t *)reason, + }; rv = ngtcp2_ppe_encode_frame(&ppe, &fr); if (rv != 0) { diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h index de78bcb807..d5c3f61d2a 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h @@ -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. diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_log.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_log.c index fc4eb44351..e006c22e4e 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_log.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_log.c @@ -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"), diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.c index 5e4726e63f..246c779f29 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.c @@ -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 (;;) { diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.h index 9d882fb200..0c1a76552a 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.h @@ -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 diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.h index 756076e7a7..ec72708e04 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.h @@ -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; diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h index d490524805..73efb5255f 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h @@ -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); diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.c index 181691f3e6..6f44c8ac8d 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.c @@ -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; } diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.h index c2580306cc..1bb624de79 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.h @@ -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; diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c index 101dcaa99f..b50f482bc7 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c @@ -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, @@ -451,13 +454,17 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, if (ent->flags & (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) { ++rtb->num_lost_ignore_pkts; - } else 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, - ent->rst.tx_in_flight, - ent->rst.is_app_limited), - ts); + } 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, + ent->rst.tx_in_flight, + ent->rst.is_app_limited), + ts); + } } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { @@ -704,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) { @@ -843,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) { @@ -873,7 +881,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, } rtb_remove(rtb, &it, &acked_ent, ent, cstat); - ++num_acked; } } @@ -882,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); } } @@ -904,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; } - rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts); acked_ent = ent->next; ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc, rtb->frc_objalloc, rtb->mem); @@ -921,6 +932,7 @@ 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); } @@ -942,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); diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c index 8ea969c4ad..70ec6ee2fe 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c @@ -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, diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_transport_params.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_transport_params.c index ca517532e3..d652ece4e0 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_transport_params.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_transport_params.c @@ -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; diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_vec.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_vec.h index 55e735d164..d90a3204a9 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_vec.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_vec.h @@ -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|. diff --git a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h index d7a27b9213..b0cc867cde 100644 --- a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h +++ b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h @@ -2971,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_* + * `. |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 * @@ -3262,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 @@ -3527,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; /** diff --git a/src/contrib/libngtcp2/ngtcp2/version.h b/src/contrib/libngtcp2/ngtcp2/version.h index 5a261a2430..533f6d5ef6 100644 --- a/src/contrib/libngtcp2/ngtcp2/version.h +++ b/src/contrib/libngtcp2/ngtcp2/version.h @@ -36,7 +36,7 @@ * * Version number of the ngtcp2 library release. */ -#define NGTCP2_VERSION "1.13.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 0x010d00 +#define NGTCP2_VERSION_NUM 0x010e00 #endif /* !defined(NGTCP2_VERSION_H) */