From: Jan Doskočil Date: Wed, 16 Apr 2025 12:05:15 +0000 (+0200) Subject: libngtcp2: update embedded library to v1.12 X-Git-Tag: v3.5.0~107 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d6bd4e8ae0029b69f4cc4ba63d371b15a00a59dd;p=thirdparty%2Fknot-dns.git libngtcp2: update embedded library to v1.12 --- diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c index a20f04521e..e399db8730 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c @@ -168,15 +168,15 @@ static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr, static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); -static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr, - ngtcp2_conn_stat *cstat); +static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat); -static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack); +static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack); static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); + const ngtcp2_cc_ack *ack); static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts); @@ -189,24 +189,20 @@ static int bbr_is_reno_coexistence_probe_time(ngtcp2_cc_bbr *bbr, static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat); -static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts); - -static int is_inflight_too_high(const ngtcp2_rs *rs); +static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr); static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_rs *rs, ngtcp2_tstamp ts); + ngtcp2_tstamp ts); static void bbr_note_loss(ngtcp2_cc_bbr *bbr); static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts); -static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr, - const ngtcp2_rs *rs, - const ngtcp2_cc_pkt *pkt); +static uint64_t +bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_pkt *pkt); static void bbr_update_min_rtt(ngtcp2_cc_bbr *bbr, const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts); @@ -326,7 +322,7 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, bbr->bw_probe_up_rounds = 0; bbr->bw_probe_up_acks = 0; - bbr->inflight_hi = UINT64_MAX; + bbr->inflight_longterm = UINT64_MAX; bbr->probe_rtt_expired = 0; bbr->probe_rtt_min_delay = UINT64_MAX; @@ -349,8 +345,8 @@ static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) { } static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) { - bbr->bw_lo = UINT64_MAX; - bbr->inflight_lo = UINT64_MAX; + bbr->bw_shortterm = UINT64_MAX; + bbr->inflight_shortterm = UINT64_MAX; } static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr) { @@ -367,7 +363,7 @@ static void bbr_reset_full_bw(ngtcp2_cc_bbr *bbr) { static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { - if (bbr->full_bw_now || bbr->rst->rs.is_app_limited) { + if (bbr->full_bw_now || !bbr->round_start || bbr->rst->rs.is_app_limited) { return; } @@ -378,10 +374,6 @@ static void bbr_check_full_bw_reached(ngtcp2_cc_bbr *bbr, return; } - if (!bbr->round_start) { - return; - } - ++bbr->full_bw_count; bbr->full_bw_now = bbr->full_bw_count >= 3; @@ -399,13 +391,13 @@ static void bbr_check_startup_high_loss(ngtcp2_cc_bbr *bbr) { if (bbr->full_bw_reached || bbr->loss_events_in_round <= 6 || (bbr->in_loss_recovery && bbr->round_count <= bbr->round_count_at_recovery) || - !is_inflight_too_high(&bbr->rst->rs)) { + !bbr_is_inflight_too_high(bbr)) { return; } bbr->full_bw_reached = 1; - bbr->inflight_hi = ngtcp2_max_uint64(bbr_bdp_multiple(bbr, bbr->cwnd_gain_h), - bbr->inflight_latest); + bbr->inflight_longterm = ngtcp2_max_uint64( + bbr_bdp_multiple(bbr, bbr->cwnd_gain_h), bbr->inflight_latest); } static void bbr_init_pacing_rate(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { @@ -546,25 +538,26 @@ static void bbr_adapt_lower_bounds_from_congestion(ngtcp2_cc_bbr *bbr, } static void bbr_init_lower_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { - if (bbr->bw_lo == UINT64_MAX) { - bbr->bw_lo = bbr->max_bw; + if (bbr->bw_shortterm == UINT64_MAX) { + bbr->bw_shortterm = bbr->max_bw; } - if (bbr->inflight_lo == UINT64_MAX) { - bbr->inflight_lo = cstat->cwnd; + if (bbr->inflight_shortterm == UINT64_MAX) { + bbr->inflight_shortterm = cstat->cwnd; } } static void bbr_loss_lower_bounds(ngtcp2_cc_bbr *bbr) { - bbr->bw_lo = ngtcp2_max_uint64( - bbr->bw_latest, bbr->bw_lo * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); - bbr->inflight_lo = ngtcp2_max_uint64( + bbr->bw_shortterm = ngtcp2_max_uint64( + bbr->bw_latest, + bbr->bw_shortterm * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); + bbr->inflight_shortterm = ngtcp2_max_uint64( bbr->inflight_latest, - bbr->inflight_lo * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); + bbr->inflight_shortterm * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); } static void bbr_bound_bw_for_model(ngtcp2_cc_bbr *bbr) { - bbr->bw = ngtcp2_min_uint64(bbr->max_bw, bbr->bw_lo); + bbr->bw = ngtcp2_min_uint64(bbr->max_bw, bbr->bw_shortterm); } static void bbr_update_max_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, @@ -738,7 +731,7 @@ static void bbr_start_probe_bw_up(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { bbr->pacing_gain_h = 125; bbr->cwnd_gain_h = 225; - bbr_raise_inflight_hi_slope(bbr, cstat); + bbr_raise_inflight_longterm_slope(bbr, cstat); } static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, @@ -749,7 +742,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr, return; } - bbr_adapt_upper_bounds(bbr, cstat, ack, ts); + bbr_adapt_upper_bounds(bbr, cstat, ack); if (!bbr_is_in_probe_bw_state(bbr)) { return; @@ -806,7 +799,7 @@ 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) { - if (bbr->rst->is_cwnd_limited && cstat->cwnd >= bbr->inflight_hi) { + if (bbr->rst->is_cwnd_limited && cstat->cwnd >= bbr->inflight_longterm) { bbr_reset_full_bw(bbr); bbr->full_bw = cstat->delivery_rate_sec; } else if (bbr->full_bw_now) { @@ -826,24 +819,25 @@ static uint64_t bbr_inflight_with_headroom(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { uint64_t headroom; uint64_t mpcwnd; - if (bbr->inflight_hi == UINT64_MAX) { + if (bbr->inflight_longterm == UINT64_MAX) { return UINT64_MAX; } - headroom = ngtcp2_max_uint64(cstat->max_tx_udp_payload_size, - bbr->inflight_hi * NGTCP2_BBR_HEADROOM_NUMER / - NGTCP2_BBR_HEADROOM_DENOM); + headroom = + ngtcp2_max_uint64(cstat->max_tx_udp_payload_size, + bbr->inflight_longterm * NGTCP2_BBR_HEADROOM_NUMER / + NGTCP2_BBR_HEADROOM_DENOM); mpcwnd = min_pipe_cwnd(cstat->max_tx_udp_payload_size); - if (bbr->inflight_hi > headroom) { - return ngtcp2_max_uint64(bbr->inflight_hi - headroom, mpcwnd); + if (bbr->inflight_longterm > headroom) { + return ngtcp2_max_uint64(bbr->inflight_longterm - headroom, mpcwnd); } return mpcwnd; } -static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr, - ngtcp2_conn_stat *cstat) { +static void bbr_raise_inflight_longterm_slope(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat) { uint64_t growth_this_round = cstat->max_tx_udp_payload_size << bbr->bw_probe_up_rounds; @@ -851,12 +845,12 @@ static void bbr_raise_inflight_hi_slope(ngtcp2_cc_bbr *bbr, bbr->probe_up_cnt = ngtcp2_max_uint64(cstat->cwnd / growth_this_round, 1); } -static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr, - ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack) { +static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr, + ngtcp2_conn_stat *cstat, + const ngtcp2_cc_ack *ack) { uint64_t delta; - if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_hi) { + if (!bbr->rst->is_cwnd_limited || cstat->cwnd < bbr->inflight_longterm) { return; } @@ -867,16 +861,16 @@ static void bbr_probe_inflight_hi_upward(ngtcp2_cc_bbr *bbr, bbr->probe_up_cnt * cstat->max_tx_udp_payload_size) { delta = bbr->bw_probe_up_acks / bbr->probe_up_cnt; bbr->bw_probe_up_acks -= delta * bbr->probe_up_cnt; - bbr->inflight_hi += delta; + bbr->inflight_longterm += delta; } if (bbr->round_start) { - bbr_raise_inflight_hi_slope(bbr, cstat); + bbr_raise_inflight_longterm_slope(bbr, cstat); } } static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) { + const ngtcp2_cc_ack *ack) { if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING && bbr->round_start) { bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK; @@ -889,17 +883,17 @@ static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, } } - if (!bbr_check_inflight_too_high(bbr, cstat, ts)) { - if (bbr->inflight_hi == UINT64_MAX) { + if (!bbr_is_inflight_too_high(bbr)) { + if (bbr->inflight_longterm == UINT64_MAX) { return; } - if (bbr->rst->rs.tx_in_flight > bbr->inflight_hi) { - bbr->inflight_hi = bbr->rst->rs.tx_in_flight; + if (bbr->rst->rs.tx_in_flight > bbr->inflight_longterm) { + bbr->inflight_longterm = bbr->rst->rs.tx_in_flight; } if (bbr->state == NGTCP2_BBR_STATE_PROBE_BW_UP) { - bbr_probe_inflight_hi_upward(bbr, cstat, ack); + bbr_probe_inflight_longterm_upward(bbr, cstat, ack); } } } @@ -941,33 +935,21 @@ static uint64_t bbr_target_inflight(ngtcp2_cc_bbr *bbr, return ngtcp2_min_uint64(bbr->bdp, cstat->cwnd); } -static int bbr_check_inflight_too_high(ngtcp2_cc_bbr *bbr, - ngtcp2_conn_stat *cstat, - ngtcp2_tstamp ts) { - if (is_inflight_too_high(&bbr->rst->rs)) { - if (bbr->bw_probe_samples) { - bbr_handle_inflight_too_high(bbr, cstat, &bbr->rst->rs, ts); - } - - return 1; - } - - return 0; -} - -static int is_inflight_too_high(const ngtcp2_rs *rs) { +static int bbr_is_inflight_too_high(ngtcp2_cc_bbr *bbr) { + const ngtcp2_rs *rs = &bbr->rst->rs; return rs->lost * NGTCP2_BBR_LOSS_THRESH_DENOM > rs->tx_in_flight * NGTCP2_BBR_LOSS_THRESH_NUMER; } static void bbr_handle_inflight_too_high(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, - const ngtcp2_rs *rs, ngtcp2_tstamp ts) { + const ngtcp2_rs *rs = &bbr->rst->rs; + bbr->bw_probe_samples = 0; if (!rs->is_app_limited) { - bbr->inflight_hi = ngtcp2_max_uint64( + bbr->inflight_longterm = ngtcp2_max_uint64( rs->tx_in_flight, bbr_target_inflight(bbr, cstat) * NGTCP2_BBR_BETA_NUMER / NGTCP2_BBR_BETA_DENOM); } @@ -987,7 +969,7 @@ static void bbr_note_loss(ngtcp2_cc_bbr *bbr) { static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) { - ngtcp2_rs rs = {0}; + ngtcp2_rs *rs = &bbr->rst->rs; bbr_note_loss(bbr); @@ -995,22 +977,23 @@ static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat, return; } - rs.tx_in_flight = pkt->tx_in_flight; + rs->tx_in_flight = pkt->tx_in_flight; /* bbr->rst->lost is not incremented for pkt yet */ assert(bbr->rst->lost + pkt->pktlen >= pkt->lost); - rs.lost = bbr->rst->lost + pkt->pktlen - pkt->lost; - rs.is_app_limited = pkt->is_app_limited; + rs->lost = bbr->rst->lost + pkt->pktlen - pkt->lost; + rs->is_app_limited = pkt->is_app_limited; - if (is_inflight_too_high(&rs)) { - rs.tx_in_flight = bbr_inflight_hi_from_lost_packet(bbr, &rs, pkt); + if (bbr_is_inflight_too_high(bbr)) { + rs->tx_in_flight = bbr_inflight_longterm_from_lost_packet(bbr, pkt); - bbr_handle_inflight_too_high(bbr, cstat, &rs, ts); + bbr_handle_inflight_too_high(bbr, cstat, ts); } } -static uint64_t bbr_inflight_hi_from_lost_packet(ngtcp2_cc_bbr *bbr, - const ngtcp2_rs *rs, - const ngtcp2_cc_pkt *pkt) { +static uint64_t +bbr_inflight_longterm_from_lost_packet(ngtcp2_cc_bbr *bbr, + const ngtcp2_cc_pkt *pkt) { + ngtcp2_rs *rs = &bbr->rst->rs; uint64_t inflight_prev, lost_prev, lost_prefix; (void)bbr; @@ -1204,9 +1187,6 @@ static void bbr_update_max_inflight(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) { uint64_t inflight; - /* Not documented */ - /* bbr_update_aggregation_budget(bbr); */ - inflight = bbr_bdp_multiple(bbr, bbr->cwnd_gain_h) + bbr->extra_acked; bbr->max_inflight = bbr_quantization_budget(bbr, cstat, inflight); } @@ -1281,13 +1261,13 @@ static void bbr_bound_cwnd_for_model(ngtcp2_cc_bbr *bbr, if (bbr_is_in_probe_bw_state(bbr) && bbr->state != NGTCP2_BBR_STATE_PROBE_BW_CRUISE) { - cap = bbr->inflight_hi; + cap = bbr->inflight_longterm; } else if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT || bbr->state == NGTCP2_BBR_STATE_PROBE_BW_CRUISE) { cap = bbr_inflight_with_headroom(bbr, cstat); } - cap = ngtcp2_min_uint64(cap, bbr->inflight_lo); + cap = ngtcp2_min_uint64(cap, bbr->inflight_shortterm); cap = ngtcp2_max_uint64(cap, mpcwnd); cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, cap); diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.h index 74eb2d640b..e823711a50 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.h @@ -86,8 +86,8 @@ typedef struct ngtcp2_cc_bbr { uint64_t inflight_latest; /* Lower bounds */ - uint64_t bw_lo; - uint64_t inflight_lo; + uint64_t bw_shortterm; + uint64_t inflight_shortterm; /* Round counting */ uint64_t next_round_delivered; @@ -123,7 +123,7 @@ typedef struct ngtcp2_cc_bbr { int bw_probe_samples; size_t bw_probe_up_rounds; uint64_t bw_probe_up_acks; - uint64_t inflight_hi; + uint64_t inflight_longterm; int probe_rtt_expired; ngtcp2_duration probe_rtt_min_delay; ngtcp2_tstamp probe_rtt_min_stamp; diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.c index 8bff06c0c1..acbee78aaf 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.c @@ -149,3 +149,9 @@ int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid, ? 0 : NGTCP2_ERR_INVALID_ARGUMENT; } + +void ngtcp2_dcid_apply_validated_path(ngtcp2_dcid *dcid, + const ngtcp2_path_history_entry *ent) { + dcid->flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED; + dcid->max_udp_payload_size = ent->max_udp_payload_size; +} diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.h index c6ab16831a..9321cfb64e 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.h @@ -176,4 +176,24 @@ int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid, const ngtcp2_path *path, const uint8_t *token); +/* TODO It might be performance win if we store congestion state in + this entry, and restore it when migrate back to this path. */ +typedef struct ngtcp2_path_history_entry { + /* ps contains path. */ + ngtcp2_path_storage ps; + /* max_udp_payload_size is the maximum size of UDP datagram payload + that is allowed to be sent to this path. */ + size_t max_udp_payload_size; + /* ts is the timestamp when this entry is added to the path history. + It happens when a local endpoint migrates to the another path. */ + ngtcp2_tstamp ts; +} ngtcp2_path_history_entry; + +/* + * ngtcp2_dcid_apply_validated_path applies the defaults from |ent| + * which contains the validated path and its stored configurations. + */ +void ngtcp2_dcid_apply_validated_path(ngtcp2_dcid *dcid, + const ngtcp2_path_history_entry *ent); + #endif /* !defined(NGTCP2_CID_H) */ diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c index 59eb90f6ea..dc1268d4e3 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c @@ -1032,6 +1032,56 @@ conn_set_local_transport_params(ngtcp2_conn *conn, p->version_info_present = 1; } +static void conn_update_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns) { + uint8_t gap; + + conn->callbacks.rand(&gap, 1, &conn->local.settings.rand_ctx); + + pktns->tx.skip_pkt.next_pkt_num = + pktns->tx.last_pkt_num + 3 + + (int64_t)gap * (1ll << pktns->tx.skip_pkt.exponent++); + + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "next skip pkn=%" PRId64, + pktns->tx.skip_pkt.next_pkt_num); +} + +static int conn_handle_skip_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns, + ngtcp2_tstamp ts) { + ngtcp2_rtb_entry *rtbent; + ngtcp2_pkt_hd hd; + int rv; + + assert(NGTCP2_PKTNS_ID_APPLICATION == pktns->id); + + if (pktns->tx.last_pkt_num + 1 != pktns->tx.skip_pkt.next_pkt_num) { + return 0; + } + + ngtcp2_pkt_hd_init(&hd, 0, NGTCP2_PKT_1RTT, NULL, NULL, + pktns->tx.skip_pkt.next_pkt_num, 0, 0); + + rv = ngtcp2_rtb_entry_objalloc_new(&rtbent, &hd, NULL, ts, 0, + NGTCP2_RTB_ENTRY_FLAG_SKIP, + &conn->rtb_entry_objalloc); + if (rv != 0) { + assert(ngtcp2_err_is_fatal(rv)); + return rv; + } + + rv = ngtcp2_rtb_add(&pktns->rtb, rtbent, &conn->cstat); + if (rv != 0) { + ngtcp2_rtb_entry_objalloc_del(rtbent, &conn->rtb_entry_objalloc, + &conn->frc_objalloc, conn->mem); + return rv; + } + + ++pktns->tx.last_pkt_num; + + conn_update_skip_pkt(conn, pktns); + + return 0; +} + static size_t buflen_align(size_t buflen) { return (buflen + 0x7) & (size_t)~0x7; } @@ -1251,6 +1301,10 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, ngtcp2_unreachable(); } + ngtcp2_static_ringbuf_path_history_init(&(*pconn)->path_history); + + (*pconn)->callbacks = *callbacks; + rv = pktns_new(&(*pconn)->in_pktns, NGTCP2_PKTNS_ID_INITIAL, &(*pconn)->rst, &(*pconn)->cc, settings->initial_pkt_num, &(*pconn)->log, &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, @@ -1272,6 +1326,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, &(*pconn)->qlog, &(*pconn)->rtb_entry_objalloc, &(*pconn)->frc_objalloc, mem); + conn_update_skip_pkt(*pconn, &(*pconn)->pktns); + scident = ngtcp2_mem_malloc(mem, sizeof(*scident)); if (scident == NULL) { rv = NGTCP2_ERR_NOMEM; @@ -1378,7 +1434,6 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid, (*pconn)->keep_alive.timeout = UINT64_MAX; (*pconn)->oscid = *scid; - (*pconn)->callbacks = *callbacks; (*pconn)->mem = mem; (*pconn)->user_data = user_data; (*pconn)->idle_ts = settings->initial_ts; @@ -2211,7 +2266,7 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, if (num_reclaimed < 0) { ngtcp2_frame_chain_list_objalloc_del(frq, &conn->frc_objalloc, conn->mem); - return rv; + return num_reclaimed; } if (num_reclaimed) { goto build_pkt; @@ -2220,12 +2275,11 @@ conn_write_handshake_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, those packets have been acknowledged (i.e., retransmission in another packet). For server, in this case, we don't have to send any probe packet. Client needs to send probe packets - until it knows that server has completed address validation or - handshake has been confirmed. */ + until it knows that server has completed address + validation. */ if (pktns->rtb.num_pto_eliciting == 0 && (conn->server || - (conn->flags & (NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED | - NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) { + (conn->flags & NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED))) { pktns->rtb.probe_pkt_left = 0; ngtcp2_conn_set_loss_detection_timer(conn, ts); /* TODO If packet is empty, we should return now if cwnd is @@ -3180,6 +3234,11 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, nfrc->fr.max_data.max_data; } + rv = conn_handle_skip_pkt(conn, pktns, ts); + if (rv != 0) { + return rv; + } + ngtcp2_pkt_hd_init(hd, hd_flags, type, &conn->dcid.current.cid, scid, pktns->tx.last_pkt_num + 1, pktns_select_pkt_numlen(pktns), version); @@ -3681,7 +3740,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, pktns->rtb.num_retransmittable && pktns->rtb.probe_pkt_left) { num_reclaimed = ngtcp2_rtb_reclaim_on_pto(&pktns->rtb, conn, pktns, 1); if (num_reclaimed < 0) { - return rv; + return num_reclaimed; } if (num_reclaimed) { goto build_pkt; @@ -3979,7 +4038,10 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, /* TODO Push STREAM frame back to ngtcp2_strm if there is an error before ngtcp2_rtb_entry is safely created and added. */ - if (require_padding) { + if ((flags & (NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY)) && + (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING)) { + lfr.padding.len = ngtcp2_ppe_padding_size(ppe, destlen); + } else if (require_padding) { lfr.padding.len = ngtcp2_ppe_dgram_padding(ppe); } else { lfr.padding.len = ngtcp2_ppe_padding_size(ppe, min_pktlen); @@ -4130,6 +4192,12 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( version = conn->negotiated_version; cc.ckm = pktns->crypto.tx.ckm; cc.hp_ctx = pktns->crypto.tx.hp_ctx; + + rv = conn_handle_skip_pkt(conn, pktns, ts); + if (rv != 0) { + return rv; + } + break; default: /* We don't support 0-RTT packet in this function. */ @@ -5033,12 +5101,12 @@ static int conn_on_retry(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, /* Just freeing memory is dangerous because we might free twice. */ - rv = ngtcp2_rtb_remove_all(rtb, conn, &conn->pktns, &conn->cstat); + rv = ngtcp2_rtb_reclaim_on_retry(rtb, conn, &conn->pktns, &conn->cstat); if (rv != 0) { return rv; } - rv = ngtcp2_rtb_remove_all(in_rtb, conn, in_pktns, &conn->cstat); + rv = ngtcp2_rtb_reclaim_on_retry(in_rtb, conn, in_pktns, &conn->cstat); if (rv != 0) { return rv; } @@ -5100,7 +5168,6 @@ static int conn_recv_ack(ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_ack *fr, num_acked = ngtcp2_rtb_recv_ack(&pktns->rtb, fr, &conn->cstat, conn, pktns, pkt_ts, ts); if (num_acked < 0) { - assert(ngtcp2_err_is_fatal((int)num_acked)); return (int)num_acked; } @@ -5432,11 +5499,13 @@ decrypt_hp(ngtcp2_pkt_hd *hd, uint8_t *dest, const ngtcp2_crypto_cipher *hp, hd->pkt_numlen = (size_t)((dest[0] & NGTCP2_PKT_NUMLEN_MASK) + 1); - for (i = 0; i < hd->pkt_numlen; ++i) { + for (i = 0; i < 4; ++i) { *p++ = *(pkt + pkt_num_offset + i) ^ mask[i + 1]; } - hd->pkt_num = ngtcp2_get_pkt_num(p - hd->pkt_numlen, hd->pkt_numlen); + p -= 4; + hd->pkt_num = ngtcp2_get_pkt_num(p, hd->pkt_numlen); + p += hd->pkt_numlen; return p - dest; } @@ -5625,6 +5694,10 @@ static int conn_recv_path_response(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, } } + if (conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) { + ngtcp2_conn_add_path_history(conn, &conn->dcid.current, ts); + } + ngtcp2_dcid_copy(&conn->dcid.current, &pv->dcid); conn_reset_congestion_state(conn, ts); @@ -7053,9 +7126,9 @@ static void handle_max_remote_streams_extension(uint64_t *punsent_max_remote_streams, size_t n) { if ( -#if SIZE_MAX > UINT32_MAX +#if SIZE_MAX == UINT64_MAX NGTCP2_MAX_STREAMS < n || -#endif /* SIZE_MAX > UINT32_MAX */ +#endif /* SIZE_MAX == UINT64_MAX */ *punsent_max_remote_streams > (uint64_t)(NGTCP2_MAX_STREAMS - n)) { *punsent_max_remote_streams = NGTCP2_MAX_STREAMS; } else { @@ -8168,13 +8241,14 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, int new_cid_used, ngtcp2_tstamp ts) { ngtcp2_dcid dcid; - ngtcp2_pv *pv; + ngtcp2_pv *pv = NULL; int rv; ngtcp2_duration pto; int require_new_cid; int local_addr_eq; int pref_addr_migration; uint32_t remote_addr_cmp; + const ngtcp2_path_history_entry *validated_path; assert(conn->server); @@ -8198,7 +8272,11 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, /* Run PMTUD just in case if it is prematurely aborted */ assert(!conn->pmtud); - return conn_start_pmtud(conn); + if (!conn->local.settings.no_pmtud) { + return conn_start_pmtud(conn); + } + + return 0; } remote_addr_cmp = @@ -8268,25 +8346,32 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, dcid.bytes_recv += dgramlen; - pto = conn_compute_pto(conn, &conn->pktns); + validated_path = ngtcp2_conn_find_path_history(conn, path, ts); + if (!validated_path) { + pto = conn_compute_pto(conn, &conn->pktns); - rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout_pto(conn, pto), - NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); - if (rv != 0) { - return rv; - } + rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout_pto(conn, pto), + NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); + if (rv != 0) { + return rv; + } - if (conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT)) { - ngtcp2_pv_set_fallback(pv, &conn->pv->fallback_dcid, - conn->pv->fallback_pto); - /* Unset the flag bit so that conn_stop_pv does not retire - DCID. */ - conn->pv->flags &= (uint8_t)~NGTCP2_PV_FLAG_FALLBACK_PRESENT; - } else if (!pref_addr_migration) { - ngtcp2_pv_set_fallback(pv, &conn->dcid.current, pto); + if (conn->pv && (conn->pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT)) { + ngtcp2_pv_set_fallback(pv, &conn->pv->fallback_dcid, + conn->pv->fallback_pto); + /* Unset the flag bit so that conn_stop_pv does not retire + DCID. */ + conn->pv->flags &= (uint8_t)~NGTCP2_PV_FLAG_FALLBACK_PRESENT; + } else if (!pref_addr_migration) { + ngtcp2_pv_set_fallback(pv, &conn->dcid.current, pto); + } } - if (!pref_addr_migration) { + if (!pref_addr_migration || validated_path) { + if (conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) { + ngtcp2_conn_add_path_history(conn, &conn->dcid.current, ts); + } + ngtcp2_dcid_copy(&conn->dcid.current, &dcid); if (!local_addr_eq || (remote_addr_cmp & (NGTCP2_ADDR_CMP_FLAG_ADDR | @@ -8297,6 +8382,17 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn, conn_reset_ecn_validation_state(conn); ngtcp2_conn_stop_pmtud(conn); + + if (validated_path) { + ngtcp2_dcid_apply_validated_path(&conn->dcid.current, validated_path); + + if (!conn->local.settings.no_pmtud) { + rv = conn_start_pmtud(conn); + if (rv != 0) { + return rv; + } + } + } } if (conn->pv) { @@ -8485,34 +8581,6 @@ conn_recv_delayed_handshake_pkt(ngtcp2_conn *conn, const ngtcp2_pkt_info *pi, return 0; } -/* - * conn_allow_path_change_under_disable_active_migration returns - * nonzero if a packet from |path| is acceptable under - * disable_active_migration is on. - */ -static int -conn_allow_path_change_under_disable_active_migration(ngtcp2_conn *conn, - const ngtcp2_path *path) { - uint32_t remote_addr_cmp; - - assert(conn->server); - assert(conn->local.transport_params.disable_active_migration); - - /* If local address does not change, it must be passive migration - (NAT rebinding). */ - if (ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, &path->local)) { - remote_addr_cmp = - ngtcp2_addr_cmp(&conn->dcid.current.ps.path.remote, &path->remote); - - return (remote_addr_cmp | NGTCP2_ADDR_CMP_FLAG_PORT) == - NGTCP2_ADDR_CMP_FLAG_PORT; - } - - /* If local address changes, it must be one of the preferred - addresses. */ - return conn_server_preferred_addr_migration(conn, &path->local); -} - /* * conn_recv_pkt processes a packet contained in the buffer pointed by * |pkt| of length |pktlen|. |pkt| may contain multiple QUIC packets. @@ -8577,30 +8645,6 @@ static ngtcp2_ssize conn_recv_pkt(ngtcp2_conn *conn, const ngtcp2_path *path, int path_challenge_recved = 0; size_t num_ack_processed = 0; - if (conn->server) { - if (conn->local.transport_params.disable_active_migration && - !ngtcp2_path_eq(&conn->dcid.current.ps.path, path) && - !conn_allow_path_change_under_disable_active_migration(conn, path)) { - ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_PKT, - "packet is discarded because local active migration is disabled"); - - return NGTCP2_ERR_DISCARD_PKT; - } - - assert(conn->remote.transport_params); - - if (conn->remote.transport_params->disable_active_migration && - !ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, &path->local) && - !conn_server_preferred_addr_migration(conn, &path->local)) { - ngtcp2_log_info( - &conn->log, NGTCP2_LOG_EVENT_PKT, - "packet is discarded because remote active migration is disabled"); - - return NGTCP2_ERR_DISCARD_PKT; - } - } - if (pkt[0] & NGTCP2_HEADER_FORM_BIT) { nread = ngtcp2_pkt_decode_hd_long(&hd, pkt, pktlen); if (nread < 0) { @@ -9380,6 +9424,15 @@ static int conn_recv_cpkt(ngtcp2_conn *conn, const ngtcp2_path *path, conn->dcid.current.bytes_recv += dgramlen; } + if (conn->server && conn->local.transport_params.disable_active_migration && + !ngtcp2_addr_eq(&conn->dcid.current.ps.path.local, &path->local) && + !conn_server_preferred_addr_migration(conn, &path->local)) { + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_PKT, + "packet is discarded because active migration is disabled"); + + return 0; + } + while (pktlen) { nread = conn_recv_pkt(conn, path, pi, pkt, pktlen, dgramlen, ts, ts); if (nread < 0) { @@ -9841,7 +9894,7 @@ static int conn_validate_early_transport_params_limits(ngtcp2_conn *conn) { */ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - uint64_t write_datalen, + uint8_t wflags, uint64_t write_datalen, ngtcp2_tstamp ts) { int rv; ngtcp2_ssize res = 0, nwrite = 0, early_spktlen = 0; @@ -9874,8 +9927,8 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (pending_early_datalen) { early_spktlen = conn_retransmit_retry_early( conn, pi, dest + nwrite, destlen - (size_t)nwrite, (size_t)nwrite, - nwrite ? NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING - : NGTCP2_WRITE_PKT_FLAG_NONE, + wflags | (nwrite ? NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING + : NGTCP2_WRITE_PKT_FLAG_NONE), ts); if (early_spktlen < 0) { @@ -9917,7 +9970,15 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, if (pending_early_datalen && !(conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED)) { nwrite = conn_retransmit_retry_early( - conn, pi, dest, destlen, (size_t)res, NGTCP2_WRITE_PKT_FLAG_NONE, ts); + conn, pi, dest, destlen, (size_t)res, + wflags | ((nwrite && + ngtcp2_pkt_get_type_long( + conn->negotiated_version ? conn->negotiated_version + : conn->client_chosen_version, + *(dest - nwrite)) == NGTCP2_PKT_INITIAL) + ? NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING + : NGTCP2_WRITE_PKT_FLAG_NONE), + ts); if (nwrite < 0) { return nwrite; } @@ -10069,17 +10130,15 @@ static ngtcp2_ssize conn_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, * pointed by |dest| if it succeeds, or one of the following negative * error codes: (TBD). */ -static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, - ngtcp2_pkt_info *pi, - uint8_t *dest, size_t destlen, - ngtcp2_vmsg *vmsg, - ngtcp2_tstamp ts) { +static ngtcp2_ssize +conn_client_write_handshake(ngtcp2_conn *conn, ngtcp2_pkt_info *pi, + uint8_t *dest, size_t destlen, uint8_t wflags, + ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts) { int send_stream = 0; int send_datagram = 0; ngtcp2_ssize spktlen, early_spktlen; uint64_t datalen; uint64_t write_datalen = 0; - uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE; int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0; uint32_t version; @@ -10120,7 +10179,8 @@ static ngtcp2_ssize conn_client_write_handshake(ngtcp2_conn *conn, } if (!ppe_pending) { - spktlen = conn_write_handshake(conn, pi, dest, destlen, write_datalen, ts); + spktlen = + conn_write_handshake(conn, pi, dest, destlen, wflags, write_datalen, ts); if (spktlen < 0) { return spktlen; @@ -10736,7 +10796,7 @@ ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn) { if (conn->in_pktns) { ts = ngtcp2_rtb_lost_pkt_ts(&conn->in_pktns->rtb); if (ts != UINT64_MAX) { - ts += conn_compute_pto(conn, conn->in_pktns); + ts += conn_compute_pto(conn, conn->in_pktns) * 3; res = ngtcp2_min_uint64(res, ts); } } @@ -10744,14 +10804,14 @@ ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn) { if (conn->hs_pktns) { ts = ngtcp2_rtb_lost_pkt_ts(&conn->hs_pktns->rtb); if (ts != UINT64_MAX) { - ts += conn_compute_pto(conn, conn->hs_pktns); + ts += conn_compute_pto(conn, conn->hs_pktns) * 3; res = ngtcp2_min_uint64(res, ts); } } ts = ngtcp2_rtb_lost_pkt_ts(&conn->pktns.rtb); if (ts != UINT64_MAX) { - ts += conn_compute_pto(conn, &conn->pktns); + ts += conn_compute_pto(conn, &conn->pktns) * 3; res = ngtcp2_min_uint64(res, ts); } @@ -10759,18 +10819,18 @@ ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn) { } void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts) { - ngtcp2_duration pto; + ngtcp2_duration timeout; if (conn->in_pktns) { - pto = conn_compute_pto(conn, conn->in_pktns); - ngtcp2_rtb_remove_expired_lost_pkt(&conn->in_pktns->rtb, pto, ts); + timeout = conn_compute_pto(conn, conn->in_pktns) * 3; + ngtcp2_rtb_remove_expired_lost_pkt(&conn->in_pktns->rtb, timeout, ts); } if (conn->hs_pktns) { - pto = conn_compute_pto(conn, conn->hs_pktns); - ngtcp2_rtb_remove_expired_lost_pkt(&conn->hs_pktns->rtb, pto, ts); + timeout = conn_compute_pto(conn, conn->hs_pktns) * 3; + ngtcp2_rtb_remove_expired_lost_pkt(&conn->hs_pktns->rtb, timeout, ts); } - pto = conn_compute_pto(conn, &conn->pktns); - ngtcp2_rtb_remove_expired_lost_pkt(&conn->pktns.rtb, pto, ts); + timeout = conn_compute_pto(conn, &conn->pktns) * 3; + ngtcp2_rtb_remove_expired_lost_pkt(&conn->pktns.rtb, timeout, ts); } /* @@ -11315,27 +11375,34 @@ ngtcp2_ssize ngtcp2_conn_write_stream_versioned( ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, ngtcp2_ssize *pdatalen, uint32_t flags, int64_t stream_id, const uint8_t *data, size_t datalen, ngtcp2_tstamp ts) { - ngtcp2_vec datav; + ngtcp2_vec datav, *v; + size_t datacnt; - datav.len = datalen; - datav.base = (uint8_t *)data; + if (datalen == 0) { + v = NULL; + datacnt = 0; + } else { + datav.len = datalen; + datav.base = (uint8_t *)data; + v = &datav; + datacnt = 1; + } return ngtcp2_conn_writev_stream_versioned(conn, path, pkt_info_version, pi, dest, destlen, pdatalen, flags, - stream_id, &datav, 1, ts); + stream_id, v, datacnt, ts); } -static ngtcp2_ssize conn_write_vmsg_wrapper(ngtcp2_conn *conn, - ngtcp2_path *path, - int pkt_info_version, - ngtcp2_pkt_info *pi, uint8_t *dest, - size_t destlen, ngtcp2_vmsg *vmsg, - ngtcp2_tstamp ts) { +static ngtcp2_ssize +conn_write_vmsg_wrapper(ngtcp2_conn *conn, ngtcp2_path *path, + int pkt_info_version, ngtcp2_pkt_info *pi, + uint8_t *dest, size_t destlen, uint8_t wflags, + ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts) { ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_ssize nwrite; nwrite = ngtcp2_conn_write_vmsg(conn, path, pkt_info_version, pi, dest, - destlen, vmsg, ts); + destlen, wflags, vmsg, ts); if (nwrite < 0) { return nwrite; } @@ -11364,6 +11431,7 @@ ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( ngtcp2_vmsg vmsg, *pvmsg; ngtcp2_strm *strm; int64_t datalen; + uint8_t wflags; if (pdatalen) { *pdatalen = -1; @@ -11406,8 +11474,14 @@ ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( pvmsg = NULL; } + if (flags & NGTCP2_WRITE_STREAM_FLAG_PADDING) { + wflags = NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY; + } else { + wflags = NGTCP2_WRITE_PKT_FLAG_NONE; + } + return conn_write_vmsg_wrapper(conn, path, pkt_info_version, pi, dest, - destlen, pvmsg, ts); + destlen, wflags, pvmsg, ts); } ngtcp2_ssize ngtcp2_conn_write_datagram_versioned( @@ -11415,14 +11489,22 @@ ngtcp2_ssize ngtcp2_conn_write_datagram_versioned( ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, int *paccepted, uint32_t flags, uint64_t dgram_id, const uint8_t *data, size_t datalen, ngtcp2_tstamp ts) { - ngtcp2_vec datav; + ngtcp2_vec datav, *v; + size_t datacnt; - datav.len = datalen; - datav.base = (uint8_t *)data; + if (datalen == 0) { + v = NULL; + datacnt = 0; + } else { + datav.len = datalen; + datav.base = (uint8_t *)data; + v = &datav; + datacnt = 1; + } return ngtcp2_conn_writev_datagram_versioned(conn, path, pkt_info_version, pi, dest, destlen, paccepted, flags, - dgram_id, &datav, 1, ts); + dgram_id, v, datacnt, ts); } ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( @@ -11432,6 +11514,7 @@ ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( ngtcp2_tstamp ts) { ngtcp2_vmsg vmsg; int64_t datalen; + uint8_t wflags; if (paccepted) { *paccepted = 0; @@ -11444,9 +11527,9 @@ ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( datalen = ngtcp2_vec_len_varint(datav, datavcnt); if (datalen == -1 -#if UINT64_MAX > SIZE_MAX +#if SIZE_MAX < UINT64_MAX || (uint64_t)datalen > SIZE_MAX -#endif /* UINT64_MAX > SIZE_MAX */ +#endif /* SIZE_MAX < UINT64_MAX */ ) { return NGTCP2_ERR_INVALID_ARGUMENT; } @@ -11463,19 +11546,25 @@ ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( vmsg.datagram.datacnt = datavcnt; vmsg.datagram.paccepted = paccepted; + if (flags & NGTCP2_WRITE_DATAGRAM_FLAG_PADDING) { + wflags = NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY; + } else { + wflags = NGTCP2_WRITE_PKT_FLAG_NONE; + } + return conn_write_vmsg_wrapper(conn, path, pkt_info_version, pi, dest, - destlen, &vmsg, ts); + destlen, wflags, &vmsg, ts); } ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts) { + uint8_t wflags, ngtcp2_vmsg *vmsg, + ngtcp2_tstamp ts) { ngtcp2_ssize nwrite; size_t origlen; size_t origdestlen = destlen; int rv; - uint8_t wflags = NGTCP2_WRITE_PKT_FLAG_NONE; int ppe_pending = (conn->flags & NGTCP2_CONN_FLAG_PPE_PENDING) != 0; ngtcp2_conn_stat *cstat = &conn->cstat; ngtcp2_ssize res = 0; @@ -11507,7 +11596,8 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, return conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts); } - nwrite = conn_client_write_handshake(conn, pi, dest, destlen, vmsg, ts); + nwrite = + conn_client_write_handshake(conn, pi, dest, destlen, wflags, vmsg, ts); /* We might be unable to write a packet because of depletion of congestion window budget, perhaps due to packet loss that shrinks the window drastically. */ @@ -11575,7 +11665,7 @@ ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, } } - nwrite = conn_write_handshake(conn, pi, dest, destlen, + nwrite = conn_write_handshake(conn, pi, dest, destlen, wflags, /* write_datalen = */ 0, ts); if (nwrite < 0) { return nwrite; @@ -12980,6 +13070,7 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn, int rv; ngtcp2_dcid dcid; ngtcp2_pv *pv; + const ngtcp2_path_history_entry *validated_path; assert(!conn->server); @@ -13007,22 +13098,38 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn, ngtcp2_dcidtr_pop_unused(&conn->dcid.dtr, &dcid); ngtcp2_dcid_set_path(&dcid, path); + if (conn->dcid.current.flags & NGTCP2_DCID_FLAG_PATH_VALIDATED) { + ngtcp2_conn_add_path_history(conn, &conn->dcid.current, ts); + } + ngtcp2_dcid_copy(&conn->dcid.current, &dcid); conn_reset_congestion_state(conn, ts); conn_reset_ecn_validation_state(conn); - /* TODO It might be better to add a new flag which indicates that a - connection should be closed if this path validation failed. The - current design allows an application to continue, by migrating - into yet another path. */ - rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout(conn), - NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); - if (rv != 0) { - return rv; - } + validated_path = ngtcp2_conn_find_path_history(conn, path, ts); + if (validated_path) { + ngtcp2_dcid_apply_validated_path(&conn->dcid.current, validated_path); - conn->pv = pv; + if (!conn->local.settings.no_pmtud) { + rv = conn_start_pmtud(conn); + if (rv != 0) { + return rv; + } + } + } else { + /* TODO It might be better to add a new flag which indicates that + a connection should be closed if this path validation failed. + The current design allows an application to continue, by + migrating into yet another path. */ + rv = ngtcp2_pv_new(&pv, &dcid, conn_compute_pv_timeout(conn), + NGTCP2_PV_FLAG_NONE, &conn->log, conn->mem); + if (rv != 0) { + return rv; + } + + conn->pv = pv; + } return conn_call_activate_dcid(conn, &conn->dcid.current); } @@ -13035,6 +13142,10 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path, assert(!conn->server); + if (ngtcp2_conn_find_path_history(conn, path, ts)) { + return ngtcp2_conn_initiate_immediate_migration(conn, path, ts); + } + conn_update_timestamp(conn, ts); rv = conn_initiate_migration_precheck(conn, &path->local); @@ -13283,6 +13394,37 @@ size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, int64_t stream_id) { return strm->tx.loss_count; } +void ngtcp2_conn_add_path_history(ngtcp2_conn *conn, const ngtcp2_dcid *dcid, + ngtcp2_tstamp ts) { + ngtcp2_path_history_entry *ent; + + ent = ngtcp2_ringbuf_push_front(&conn->path_history.rb); + ngtcp2_path_storage_init2(&ent->ps, &dcid->ps.path); + ent->max_udp_payload_size = dcid->max_udp_payload_size; + ent->ts = ts; +} + +const ngtcp2_path_history_entry * +ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path, + ngtcp2_tstamp ts) { + ngtcp2_ringbuf *rb = &conn->path_history.rb; + size_t i, len = ngtcp2_ringbuf_len(rb); + ngtcp2_path_history_entry *ent; + + for (i = 0; i < len; ++i) { + ent = ngtcp2_ringbuf_get(rb, i); + if (ngtcp2_tstamp_elapsed(ent->ts, 10 * NGTCP2_MINUTES, ts)) { + return NULL; + } + + if (ngtcp2_path_eq(path, &ent->ps.path)) { + return ent; + } + } + + return NULL; +} + void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, const ngtcp2_path *path, const uint8_t *data) { diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h index 0ba8d6efcc..5979d39654 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h @@ -110,6 +110,9 @@ typedef enum { NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING, but it requests to add padding to the full UDP datagram payload size. */ #define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04u +/* NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY adds padding to the QUIC + packet as much as possible if the packet is not empty. */ +#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08u /* * ngtcp2_max_frame is defined so that it covers the largest ACK @@ -203,6 +206,13 @@ typedef struct ngtcp2_pktns { /* last_pkt_num is the packet number which the local endpoint sent last time.*/ int64_t last_pkt_num; + struct { + /* next_pkt_num is the next packet number to skip. */ + int64_t next_pkt_num; + /* exponent makes gap of skipping packets spread + exponentially. */ + int64_t exponent; + } skip_pkt; ngtcp2_frame_chain *frq; /* non_ack_pkt_start_ts is the timestamp since the local endpoint starts sending continuous non ACK-eliciting packets. */ @@ -308,6 +318,8 @@ typedef struct ngtcp2_early_transport_params { ngtcp2_static_ringbuf_def(path_challenge, 4, sizeof(ngtcp2_path_challenge_entry)) +ngtcp2_static_ringbuf_def(path_history, 4, sizeof(ngtcp2_path_history_entry)) + ngtcp2_objalloc_decl(strm, ngtcp2_strm, oplent) struct ngtcp2_conn { @@ -625,6 +637,10 @@ struct ngtcp2_conn { ngtcp2_cc_cubic cubic; ngtcp2_cc_bbr bbr; }; + /* path_history remembers the paths that have been validated + successfully. The path is added to this history when a local + endpoint migrates to the another path. */ + ngtcp2_static_ringbuf_path_history path_history; const ngtcp2_mem *mem; /* idle_ts is the time instant when idle timer started. */ ngtcp2_tstamp idle_ts; @@ -801,7 +817,8 @@ ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn); ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path, int pkt_info_version, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen, - ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts); + uint8_t wflags, ngtcp2_vmsg *vmsg, + ngtcp2_tstamp ts); /* * ngtcp2_conn_write_single_frame_pkt writes a packet which contains @@ -1094,4 +1111,11 @@ void ngtcp2_conn_discard_initial_state(ngtcp2_conn *conn, ngtcp2_tstamp ts); */ void ngtcp2_conn_discard_handshake_state(ngtcp2_conn *conn, ngtcp2_tstamp ts); +void ngtcp2_conn_add_path_history(ngtcp2_conn *conn, const ngtcp2_dcid *dcid, + ngtcp2_tstamp ts); + +const ngtcp2_path_history_entry * +ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path, + ngtcp2_tstamp ts); + #endif /* !defined(NGTCP2_CONN_H) */ diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c index 8a8d773379..170b9f803c 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c @@ -157,10 +157,11 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest, return 0; } -static int verify_stateless_reset(const ngtcp2_ringbuf *rb, - const ngtcp2_path *path, - const uint8_t *token) { +int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr, + const ngtcp2_path *path, + const uint8_t *token) { const ngtcp2_dcid *dcid; + const ngtcp2_ringbuf *rb = &dtr->bound.rb; size_t i, len = ngtcp2_ringbuf_len(rb); for (i = 0; i < len; ++i) { @@ -173,19 +174,6 @@ static int verify_stateless_reset(const ngtcp2_ringbuf *rb, return NGTCP2_ERR_INVALID_ARGUMENT; } -int ngtcp2_dcidtr_verify_stateless_reset(const ngtcp2_dcidtr *dtr, - const ngtcp2_path *path, - const uint8_t *token) { - int rv; - - rv = verify_stateless_reset(&dtr->retired.rb, path, token); - if (rv == 0) { - return 0; - } - - return verify_stateless_reset(&dtr->bound.rb, path, token); -} - static int verify_token_uniqueness(const ngtcp2_ringbuf *rb, int *pfound, uint64_t seq, const ngtcp2_cid *cid, const uint8_t *token) { diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h index 17942389b8..63043427bc 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h @@ -340,4 +340,4 @@ int ngtcp2_dcidtr_unused_empty(const ngtcp2_dcidtr *dtr); */ int ngtcp2_dcidtr_bound_full(const ngtcp2_dcidtr *dtr); -#endif /* NGTCP2_DCIDTR_H */ +#endif /* !defined(NGTCP2_DCIDTR_H) */ diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c index d78978492c..af8a059d08 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c @@ -304,11 +304,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt, } ngtcp2_get_uvarint(&vi, p); -#if SIZE_MAX > UINT32_MAX +#if SIZE_MAX < UINT64_MAX if (vi > SIZE_MAX) { return NGTCP2_ERR_INVALID_ARGUMENT; } -#endif /* SIZE_MAX > UINT32_MAX */ +#endif /* SIZE_MAX < UINT64_MAX */ longlen = (size_t)vi; } @@ -2080,8 +2080,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_datagram_frame(uint8_t *out, size_t outlen, } for (i = 0; i < fr->datacnt; ++i) { - assert(fr->data[i].len); - assert(fr->data[i].base); + if (fr->data[i].len == 0) { + continue; + } + p = ngtcp2_cpymem(p, fr->data[i].base, fr->data[i].len); } @@ -2421,9 +2423,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset, left -= n; if (left > 8 + 1073741823 && len > 1073741823) { -#if SIZE_MAX > UINT32_MAX len = ngtcp2_min_uint64(len, 4611686018427387903lu); -#endif /* SIZE_MAX > UINT32_MAX */ return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 8)); } @@ -2453,9 +2453,9 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) { left -= n; if (left > 8 + 1073741823 && len > 1073741823) { -#if SIZE_MAX > UINT32_MAX +#if SIZE_MAX == UINT64_MAX len = ngtcp2_min_size(len, 4611686018427387903lu); -#endif /* SIZE_MAX > UINT32_MAX */ +#endif /* SIZE_MAX == UINT64_MAX */ return ngtcp2_min_size(len, left - 8); } diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.c index 13ef2b2490..4d193125ae 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.c @@ -47,9 +47,10 @@ void ngtcp2_ppe_init(ngtcp2_ppe *ppe, uint8_t *out, size_t outlen, int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { ngtcp2_ssize rv; ngtcp2_buf *buf = &ppe->buf; + size_t buf_left = ngtcp2_buf_left(buf); ngtcp2_crypto_cc *cc = ppe->cc; - if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) { + if (buf_left <= cc->aead.max_overhead) { return NGTCP2_ERR_NOBUF; } @@ -62,13 +63,13 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { ppe->pkt_num_offset = ppe->len_offset + NGTCP2_PKT_LENGTHLEN; - rv = ngtcp2_pkt_encode_hd_long( - buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd); + rv = ngtcp2_pkt_encode_hd_long(buf->last, buf_left - cc->aead.max_overhead, + hd); } else { ppe->pkt_num_offset = 1 + hd->dcid.datalen; - rv = ngtcp2_pkt_encode_hd_short( - buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd); + rv = ngtcp2_pkt_encode_hd_short(buf->last, buf_left - cc->aead.max_overhead, + hd); } if (rv < 0) { @@ -87,14 +88,14 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { int ngtcp2_ppe_encode_frame(ngtcp2_ppe *ppe, ngtcp2_frame *fr) { ngtcp2_ssize rv; ngtcp2_buf *buf = &ppe->buf; + size_t buf_left = ngtcp2_buf_left(buf); ngtcp2_crypto_cc *cc = ppe->cc; - if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) { + if (buf_left <= cc->aead.max_overhead) { return NGTCP2_ERR_NOBUF; } - rv = ngtcp2_pkt_encode_frame( - buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, fr); + rv = ngtcp2_pkt_encode_frame(buf->last, buf_left - cc->aead.max_overhead, fr); if (rv < 0) { return (int)rv; } @@ -172,18 +173,13 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { size_t ngtcp2_ppe_left(const ngtcp2_ppe *ppe) { ngtcp2_crypto_cc *cc = ppe->cc; + size_t buf_left = ngtcp2_buf_left(&ppe->buf); - if (ngtcp2_buf_left(&ppe->buf) < cc->aead.max_overhead) { + if (buf_left <= cc->aead.max_overhead) { return 0; } - return ngtcp2_buf_left(&ppe->buf) - cc->aead.max_overhead; -} - -size_t ngtcp2_ppe_pktlen(const ngtcp2_ppe *ppe) { - ngtcp2_crypto_cc *cc = ppe->cc; - - return ngtcp2_buf_len(&ppe->buf) + cc->aead.max_overhead; + return buf_left - cc->aead.max_overhead; } size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) { @@ -208,6 +204,10 @@ size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) { assert(ngtcp2_buf_left(buf) >= len + cc->aead.max_overhead); + if (len == 0) { + return 0; + } + buf->last = ngtcp2_setmem(buf->last, 0, len); return len; diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.h index 660b1482b5..9874b36800 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.h @@ -110,12 +110,6 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt); */ size_t ngtcp2_ppe_left(const ngtcp2_ppe *ppe); -/* - * ngtcp2_ppe_pktlen returns the provisional packet length. It - * includes AEAD overhead. - */ -size_t ngtcp2_ppe_pktlen(const ngtcp2_ppe *ppe); - /* * ngtcp2_ppe_dgram_padding is equivalent to call * ngtcp2_ppe_dgram_padding_size(ppe, NGTCP2_MAX_UDP_PAYLOAD_SIZE). diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c index f7a7f5724b..101dcaa99f 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c @@ -102,7 +102,7 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_rst *rst, ngtcp2_cc *cc, rtb->cc_pkt_num = cc_pkt_num; rtb->cc_bytes_in_flight = 0; rtb->num_lost_pkts = 0; - rtb->num_lost_pmtud_pkts = 0; + rtb->num_lost_ignore_pkts = 0; } void ngtcp2_rtb_free(ngtcp2_rtb *rtb) { @@ -153,9 +153,10 @@ static size_t rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, assert(rtb->num_lost_pkts); --rtb->num_lost_pkts; - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { - assert(rtb->num_lost_pmtud_pkts); - --rtb->num_lost_pmtud_pkts; + if (ent->flags & + (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) { + assert(rtb->num_lost_ignore_pkts); + --rtb->num_lost_ignore_pkts; } return 0; @@ -244,21 +245,16 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, fr->stream.offset + ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt); range = ngtcp2_range_intersect(&range, &gap); - if (ngtcp2_range_len(&range) == 0) { - if (!fr->stream.fin) { + if (ngtcp2_range_len(&range) == 0 && !fr->stream.fin && /* 0 length STREAM frame with offset == 0 must be retransmitted if no non-empty data are sent to this stream, fin flag is not set, and no data in this stream are acknowledged. */ - if (fr->stream.offset != 0 || fr->stream.datacnt != 0 || - strm->tx.offset || - (strm->flags & - (NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_ANY_ACKED))) { - continue; - } - } else if (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED) { - continue; - } + (fr->stream.offset != 0 || fr->stream.datacnt != 0 || + strm->tx.offset || + (strm->flags & + (NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_ANY_ACKED)))) { + continue; } if ((flags & NGTCP2_RECLAIM_FLAG_ON_LOSS) && @@ -443,15 +439,18 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, ngtcp2_cc *cc = rtb->cc; ngtcp2_cc_pkt pkt; - ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags, - ent->ts); + if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP)) { + ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags, + ent->ts); - if (rtb->qlog) { - ngtcp2_qlog_pkt_lost(rtb->qlog, ent); + if (rtb->qlog) { + ngtcp2_qlog_pkt_lost(rtb->qlog, ent); + } } - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { - ++rtb->num_lost_pmtud_pkts; + if (ent->flags & + (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) { + ++rtb->num_lost_ignore_pkts; } else if (rtb->cc->on_pkt_lost) { cc->on_pkt_lost(cc, cstat, ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, @@ -786,7 +785,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, size_t ecn_acked = 0; int verify_ecn = 0; ngtcp2_cc_ack cc_ack = {0}; - size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_pmtud_pkts; + size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_ignore_pkts; cc_ack.prior_bytes_in_flight = cstat->bytes_in_flight; cc_ack.rtt = UINT64_MAX; @@ -830,6 +829,11 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ent = ngtcp2_ksl_it_get(&it); + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP) { + rv = NGTCP2_ERR_PROTO; + goto fail; + } + if (largest_ack == pkt_num) { largest_pkt_sent_ts = ent->ts; } @@ -859,6 +863,11 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, ent = ngtcp2_ksl_it_get(&it); + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP) { + rv = NGTCP2_ERR_PROTO; + goto fail; + } + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) { ack_eliciting_pkt_acked = 1; } @@ -918,7 +927,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, } if (rtb->cc->on_spurious_congestion && num_lost_pkts && - rtb->num_lost_pkts == rtb->num_lost_pmtud_pkts) { + rtb->num_lost_pkts == rtb->num_lost_ignore_pkts) { rtb->cc->on_spurious_congestion(cc, cstat, ts); } @@ -1189,8 +1198,9 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) { --rtb->num_lost_pkts; - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { - --rtb->num_lost_pmtud_pkts; + if (ent->flags & + (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) { + --rtb->num_lost_ignore_pkts; } rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num); @@ -1200,27 +1210,28 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) { } } -void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, +void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, + ngtcp2_duration timeout, ngtcp2_tstamp ts) { ngtcp2_ksl_it it; ngtcp2_rtb_entry *ent; int rv; (void)rv; - if (ngtcp2_ksl_len(&rtb->ents) == 0) { + if (rtb->num_lost_pkts == 0) { return; } it = ngtcp2_ksl_end(&rtb->ents); - for (;;) { + for (; rtb->num_lost_pkts;) { assert(ngtcp2_ksl_it_end(&it)); ngtcp2_ksl_it_prev(&it); ent = ngtcp2_ksl_it_get(&it); if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) || - ts - ent->lost_ts < pto) { + ts - ent->lost_ts < timeout) { return; } @@ -1229,18 +1240,15 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, --rtb->num_lost_pkts; - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { - --rtb->num_lost_pmtud_pkts; + if (ent->flags & + (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) { + --rtb->num_lost_ignore_pkts; } rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num); assert(0 == rv); ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc, rtb->frc_objalloc, rtb->mem); - - if (ngtcp2_ksl_len(&rtb->ents) == 0) { - return; - } } } @@ -1263,60 +1271,14 @@ ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(const ngtcp2_rtb *rtb) { return ent->lost_ts; } -static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, - ngtcp2_pktns *pktns, - ngtcp2_rtb_entry *ent) { - ngtcp2_frame_chain **pfrc, *frc; +static int rtb_reclaim_frame_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn, + ngtcp2_pktns *pktns, + ngtcp2_rtb_entry *ent) { + ngtcp2_frame_chain **pfrc = &ent->frc, *frc; ngtcp2_stream *sfr; ngtcp2_strm *strm; int rv; - ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags, - ent->ts); - - if (rtb->qlog) { - ngtcp2_qlog_pkt_lost(rtb->qlog, ent); - } - - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, - "pkn=%" PRId64 - " is a probe packet, no retransmission is necessary", - ent->hd.pkt_num); - return 0; - } - - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) { - --rtb->num_lost_pkts; - - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { - --rtb->num_lost_pmtud_pkts; - } - - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, - "pkn=%" PRId64 - " was declared lost and has already been retransmitted", - ent->hd.pkt_num); - return 0; - } - - if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { - ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, - "pkn=%" PRId64 " has already been reclaimed on PTO", - ent->hd.pkt_num); - return 0; - } - - if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) && - (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) || - !conn->callbacks.lost_datagram)) { - /* PADDING only (or PADDING + ACK ) packets will have NULL - ent->frc. */ - return 0; - } - - pfrc = &ent->frc; - for (; *pfrc;) { switch ((*pfrc)->fr.type) { case NGTCP2_FRAME_STREAM: @@ -1390,14 +1352,12 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, return 0; } -int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn, - ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat) { +int ngtcp2_rtb_reclaim_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn, + ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat) { ngtcp2_rtb_entry *ent; - ngtcp2_ksl_it it; + ngtcp2_ksl_it it = ngtcp2_ksl_begin(&rtb->ents); int rv; - it = ngtcp2_ksl_begin(&rtb->ents); - for (; !ngtcp2_ksl_it_end(&it);) { ent = ngtcp2_ksl_it_get(&it); @@ -1405,7 +1365,42 @@ int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn, rv = ngtcp2_ksl_remove_hint(&rtb->ents, &it, &it, &ent->hd.pkt_num); assert(0 == rv); - rv = rtb_on_pkt_lost_resched_move(rtb, conn, pktns, ent); + if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_SKIP)) { + ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, + ent->hd.flags, ent->ts); + + if (rtb->qlog) { + ngtcp2_qlog_pkt_lost(rtb->qlog, ent); + } + } + + /* We never send PING only probe packet because we should have + CRYPTO data or just nothing. If we have nothing, then we do + not send probe packet. */ + assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE)); + + /* We never get ACK before Retry packet. */ + assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)); + assert(0 == rtb->num_lost_pkts); + assert(0 == rtb->num_lost_ignore_pkts); + + /* PMTUD probe must not be sent before handshake completion. */ + assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE)); + + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) { + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_LDC, + "pkn=%" PRId64 " has already been reclaimed on PTO", + ent->hd.pkt_num); + continue; + } + + if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) && + (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) || + !conn->callbacks.lost_datagram)) { + continue; + } + + rv = rtb_reclaim_frame_on_retry(rtb, conn, pktns, ent); ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc, rtb->frc_objalloc, rtb->mem); diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h index 3a9397eac5..14684a458a 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h @@ -80,6 +80,9 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain; /* NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING indicates that the entry includes a packet which elicits PTO probe packets. */ #define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100u +/* NGTCP2_RTB_ENTRY_FLAG_SKIP indicates that the entry has the skipped + packet number. */ +#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200u typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry; @@ -187,10 +190,11 @@ typedef struct ngtcp2_rtb { /* num_lost_pkts is the number entries in ents which has NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set. */ size_t num_lost_pkts; - /* num_lost_pmtud_pkts is the number of entries in ents which have - both NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED and - NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE flags set. */ - size_t num_lost_pmtud_pkts; + /* num_lost_ignore_pkts is the number of entries in ents which have + NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set, and should be + excluded from lost byte count. If only those packets are lost, + congestion event is not triggered. */ + size_t num_lost_ignore_pkts; } ngtcp2_rtb; /* @@ -258,7 +262,8 @@ int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn, /* * ngtcp2_rtb_remove_expired_lost_pkt removes expired lost packet. */ -void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, +void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, + ngtcp2_duration timeout, ngtcp2_tstamp ts); /* @@ -269,12 +274,12 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(const ngtcp2_rtb *rtb); /* - * ngtcp2_rtb_remove_all removes all packets from |rtb|, and prepends - * all frames to |*pfrc|. Even when this function fails, some frames - * might be prepended to |*pfrc|, and the caller should handle them. + * ngtcp2_rtb_reclaim_on_retry is called when Retry packet is + * received. It removes all packets from |rtb|, and retransmittable + * frames are reclaimed for retransmission. */ -int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn, - ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat); +int ngtcp2_rtb_reclaim_on_retry(ngtcp2_rtb *rtb, ngtcp2_conn *conn, + ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat); /* * ngtcp2_rtb_remove_early_data removes all entries for 0RTT packets. diff --git a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h index d2a2fe1fe1..52d05b20f0 100644 --- a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h +++ b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h @@ -214,10 +214,18 @@ typedef struct ngtcp2_mem { /** * @macro * - * :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1 - * second. + * :macro:`NGTCP2_NANOSECONDS` is a count of tick which corresponds to + * 1 nanosecond. + */ +#define NGTCP2_NANOSECONDS ((ngtcp2_duration)1ULL) + +/** + * @macro + * + * :macro:`NGTCP2_MICROSECONDS` is a count of tick which corresponds + * to 1 microsecond. */ -#define NGTCP2_SECONDS ((ngtcp2_duration)1000000000ULL) +#define NGTCP2_MICROSECONDS ((ngtcp2_duration)(1000ULL * NGTCP2_NANOSECONDS)) /** * @macro @@ -225,23 +233,23 @@ typedef struct ngtcp2_mem { * :macro:`NGTCP2_MILLISECONDS` is a count of tick which corresponds * to 1 millisecond. */ -#define NGTCP2_MILLISECONDS ((ngtcp2_duration)1000000ULL) +#define NGTCP2_MILLISECONDS ((ngtcp2_duration)(1000ULL * NGTCP2_MICROSECONDS)) /** * @macro * - * :macro:`NGTCP2_MICROSECONDS` is a count of tick which corresponds - * to 1 microsecond. + * :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1 + * second. */ -#define NGTCP2_MICROSECONDS ((ngtcp2_duration)1000ULL) +#define NGTCP2_SECONDS ((ngtcp2_duration)(1000ULL * NGTCP2_MILLISECONDS)) /** * @macro * - * :macro:`NGTCP2_NANOSECONDS` is a count of tick which corresponds to - * 1 nanosecond. + * :macro:`NGTCP2_MINUTES` is a count of tick which corresponds to 1 + * minute. */ -#define NGTCP2_NANOSECONDS ((ngtcp2_duration)1ULL) +#define NGTCP2_MINUTES ((ngtcp2_duration)(60ULL * NGTCP2_SECONDS)) /** * @macrosection @@ -2858,7 +2866,8 @@ typedef int (*ngtcp2_extend_max_stream_data)(ngtcp2_conn *conn, * :type:`ngtcp2_rand` is a callback function to get random data of * length |destlen|. Application must fill random |destlen| bytes to * the buffer pointed by |dest|. The generated data is used only in - * non-cryptographic context. + * non-cryptographic context. But it is strongly recommended to use a + * secure random number generator. */ typedef void (*ngtcp2_rand)(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx); @@ -4398,6 +4407,17 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, */ #define NGTCP2_WRITE_STREAM_FLAG_FIN 0x02u +/** + * @macro + * + * :macro:`NGTCP2_WRITE_STREAM_FLAG_PADDING` indicates that a + * non-empty 0 RTT or 1 RTT packet is padded to the minimum length of + * a sending path MTU or a given packet buffer when finalizing it. + * ACK, PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE only packets + * and PMTUD packets are excluded. + */ +#define NGTCP2_WRITE_STREAM_FLAG_PADDING 0x04u + /** * @function * @@ -4522,6 +4542,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_stream_versioned( * include, call this function with |stream_id| as -1 to stop * coalescing and write a packet. * + * If :macro:`NGTCP2_WRITE_STREAM_FLAG_PADDING` is set in |flags| when + * finalizing a non-empty 0 RTT or 1 RTT packet, the packet is padded + * to the minimum length of a sending path MTU or a given packet + * buffer. + * * This function returns 0 if it cannot write any frame because buffer * is too small, or packet is congestion limited. Application should * keep reading and wait for congestion window to grow. @@ -4586,6 +4611,17 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_stream_versioned( */ #define NGTCP2_WRITE_DATAGRAM_FLAG_MORE 0x01u +/** + * @macro + * + * :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_PADDING` indicates that a + * non-empty 0 RTT or 1 RTT packet is padded to the minimum length of + * a sending path MTU or a given packet buffer when finalizing it. + * ACK, PATH_CHALLENGE, PATH_RESPONSE, CONNECTION_CLOSE only packets + * and PMTUD packets are excluded. + */ +#define NGTCP2_WRITE_DATAGRAM_FLAG_PADDING 0x02u + /** * @function * @@ -4667,6 +4703,11 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_write_datagram_versioned( * (or `ngtcp2_conn_writev_stream`) until it returns a positive number * (which indicates a complete packet is ready). * + * If :macro:`NGTCP2_WRITE_DATAGRAM_FLAG_PADDING` is set in |flags| + * when finalizing a non-empty 0 RTT or 1 RTT packet, the packet is + * padded to the minimum length of a sending path MTU or a given + * packet buffer. + * * This function returns the number of bytes written in |dest| if it * succeeds, or one of the following negative error codes: * diff --git a/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h b/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h index 4eaf615bd3..003ec6b4c3 100644 --- a/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h +++ b/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h @@ -69,6 +69,13 @@ extern "C" { */ #define NGTCP2_CRYPTO_ERR_VERIFY_TOKEN -203 +/** + * @macro + * + * :macro:`NGTCP2_CRYPTO_ERR_NOMEM` indicates out of memory. + */ +#define NGTCP2_CRYPTO_ERR_NOMEM -501 + /** * @function * diff --git a/src/contrib/libngtcp2/ngtcp2/version.h b/src/contrib/libngtcp2/ngtcp2/version.h index bb983f5cf4..bc538e9d84 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.11.0" +#define NGTCP2_VERSION "1.12.0" /** * @macro @@ -46,6 +46,6 @@ * number, 8 bits for minor and 8 bits for patch. Version 1.2.3 * becomes 0x010203. */ -#define NGTCP2_VERSION_NUM 0x010b00 +#define NGTCP2_VERSION_NUM 0x010c00 #endif /* !defined(NGTCP2_VERSION_H) */