]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
libngtcp2: update embedded library to v1.12
authorJan Doskočil <jan.doskocil@nic.cz>
Wed, 16 Apr 2025 12:05:15 +0000 (14:05 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Wed, 16 Apr 2025 12:10:15 +0000 (14:10 +0200)
16 files changed:
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h
src/contrib/libngtcp2/ngtcp2/ngtcp2.h
src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h
src/contrib/libngtcp2/ngtcp2/version.h

index a20f04521e36cad8074b598d533771cf83f2e97b..e399db8730076949a1c716db1084faf471197700 100644 (file)
@@ -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);
index 74eb2d640bd3f22347bbbd9bccef573de6764fe1..e823711a500654426794d6183ef292fc9b2d74fc 100644 (file)
@@ -86,8 +86,8 @@ typedef struct ngtcp2_cc_bbr {
   uint64_t inflight_latest;
 
   /* Lower bounds */
-  uint64_t bw_lo;
-  uint64_t inflight_lo;
+  uint64_t bw_shortterm;
+  uint64_t inflight_shortterm;
 
   /* Round counting */
   uint64_t next_round_delivered;
@@ -123,7 +123,7 @@ typedef struct ngtcp2_cc_bbr {
   int bw_probe_samples;
   size_t bw_probe_up_rounds;
   uint64_t bw_probe_up_acks;
-  uint64_t inflight_hi;
+  uint64_t inflight_longterm;
   int probe_rtt_expired;
   ngtcp2_duration probe_rtt_min_delay;
   ngtcp2_tstamp probe_rtt_min_stamp;
index 8bff06c0c1f2daa181cff5fb71bfe7d8387fe461..acbee78aaf435fd5b14bb8a95d6e962989f9ab84 100644 (file)
@@ -149,3 +149,9 @@ int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
            ? 0
            : NGTCP2_ERR_INVALID_ARGUMENT;
 }
+
+void ngtcp2_dcid_apply_validated_path(ngtcp2_dcid *dcid,
+                                      const ngtcp2_path_history_entry *ent) {
+  dcid->flags |= NGTCP2_DCID_FLAG_PATH_VALIDATED;
+  dcid->max_udp_payload_size = ent->max_udp_payload_size;
+}
index c6ab16831a38c404f12da254273247711aa57ea9..9321cfb64e6daf63d21f9ad9f68c415b272547a0 100644 (file)
@@ -176,4 +176,24 @@ int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
                                              const ngtcp2_path *path,
                                              const uint8_t *token);
 
+/* TODO It might be performance win if we store congestion state in
+   this entry, and restore it when migrate back to this path. */
+typedef struct ngtcp2_path_history_entry {
+  /* ps contains path. */
+  ngtcp2_path_storage ps;
+  /* max_udp_payload_size is the maximum size of UDP datagram payload
+     that is allowed to be sent to this path. */
+  size_t max_udp_payload_size;
+  /* ts is the timestamp when this entry is added to the path history.
+     It happens when a local endpoint migrates to the another path. */
+  ngtcp2_tstamp ts;
+} ngtcp2_path_history_entry;
+
+/*
+ * ngtcp2_dcid_apply_validated_path applies the defaults from |ent|
+ * which contains the validated path and its stored configurations.
+ */
+void ngtcp2_dcid_apply_validated_path(ngtcp2_dcid *dcid,
+                                      const ngtcp2_path_history_entry *ent);
+
 #endif /* !defined(NGTCP2_CID_H) */
index 59eb90f6ea1afa62d2538b9fc2d2c4f8e6a1e3f0..dc1268d4e31d51cd896e1af3e7fa554732a9004b 100644 (file)
@@ -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) {
index 0ba8d6efcc6ac1ad4273c8a0cd7e3ac50375ccc7..5979d39654b839eb6fb84d142183cd907dcedb1c 100644 (file)
@@ -110,6 +110,9 @@ typedef enum {
    NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING, but it requests to add
    padding to the full UDP datagram payload size. */
 #define NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING_FULL 0x04u
+/* NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY adds padding to the QUIC
+   packet as much as possible if the packet is not empty. */
+#define NGTCP2_WRITE_PKT_FLAG_PADDING_IF_NOT_EMPTY 0x08u
 
 /*
  * ngtcp2_max_frame is defined so that it covers the largest ACK
@@ -203,6 +206,13 @@ typedef struct ngtcp2_pktns {
     /* last_pkt_num is the packet number which the local endpoint sent
        last time.*/
     int64_t last_pkt_num;
+    struct {
+      /* next_pkt_num is the next packet number to skip. */
+      int64_t next_pkt_num;
+      /* exponent makes gap of skipping packets spread
+         exponentially. */
+      int64_t exponent;
+    } skip_pkt;
     ngtcp2_frame_chain *frq;
     /* non_ack_pkt_start_ts is the timestamp since the local endpoint
        starts sending continuous non ACK-eliciting packets. */
@@ -308,6 +318,8 @@ typedef struct ngtcp2_early_transport_params {
 ngtcp2_static_ringbuf_def(path_challenge, 4,
                           sizeof(ngtcp2_path_challenge_entry))
 
+ngtcp2_static_ringbuf_def(path_history, 4, sizeof(ngtcp2_path_history_entry))
+
 ngtcp2_objalloc_decl(strm, ngtcp2_strm, oplent)
 
 struct ngtcp2_conn {
@@ -625,6 +637,10 @@ struct ngtcp2_conn {
     ngtcp2_cc_cubic cubic;
     ngtcp2_cc_bbr bbr;
   };
+  /* path_history remembers the paths that have been validated
+     successfully.  The path is added to this history when a local
+     endpoint migrates to the another path. */
+  ngtcp2_static_ringbuf_path_history path_history;
   const ngtcp2_mem *mem;
   /* idle_ts is the time instant when idle timer started. */
   ngtcp2_tstamp idle_ts;
@@ -801,7 +817,8 @@ ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn);
 ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
                                     int pkt_info_version, ngtcp2_pkt_info *pi,
                                     uint8_t *dest, size_t destlen,
-                                    ngtcp2_vmsg *vmsg, ngtcp2_tstamp ts);
+                                    uint8_t wflags, ngtcp2_vmsg *vmsg,
+                                    ngtcp2_tstamp ts);
 
 /*
  * ngtcp2_conn_write_single_frame_pkt writes a packet which contains
@@ -1094,4 +1111,11 @@ void ngtcp2_conn_discard_initial_state(ngtcp2_conn *conn, ngtcp2_tstamp ts);
  */
 void ngtcp2_conn_discard_handshake_state(ngtcp2_conn *conn, ngtcp2_tstamp ts);
 
+void ngtcp2_conn_add_path_history(ngtcp2_conn *conn, const ngtcp2_dcid *dcid,
+                                  ngtcp2_tstamp ts);
+
+const ngtcp2_path_history_entry *
+ngtcp2_conn_find_path_history(ngtcp2_conn *conn, const ngtcp2_path *path,
+                              ngtcp2_tstamp ts);
+
 #endif /* !defined(NGTCP2_CONN_H) */
index 8a8d7733797176e57acf272fe981f7cd14c0cb9c..170b9f803cccec8d6085d96d97860fbeb974336e 100644 (file)
@@ -157,10 +157,11 @@ int ngtcp2_dcidtr_bind_dcid(ngtcp2_dcidtr *dtr, ngtcp2_dcid **pdest,
   return 0;
 }
 
-static int verify_stateless_reset(const ngtcp2_ringbuf *rb,
-                                  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) {
index 17942389b814d1ef081bbd6e81c066767dd7ee92..63043427bc0900462fde51a64fd0fb8da0d599b7 100644 (file)
@@ -340,4 +340,4 @@ int ngtcp2_dcidtr_unused_empty(const ngtcp2_dcidtr *dtr);
  */
 int ngtcp2_dcidtr_bound_full(const ngtcp2_dcidtr *dtr);
 
-#endif /* NGTCP2_DCIDTR_H */
+#endif /* !defined(NGTCP2_DCIDTR_H) */
index d78978492ca8e7176ea98435872b21991df532f0..af8a059d08f7bb13eb95008d6d3dd4b6b2fc2422 100644 (file)
@@ -304,11 +304,11 @@ ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, const uint8_t *pkt,
     }
 
     ngtcp2_get_uvarint(&vi, p);
-#if SIZE_MAX > UINT32_MAX
+#if SIZE_MAX < UINT64_MAX
     if (vi > SIZE_MAX) {
       return NGTCP2_ERR_INVALID_ARGUMENT;
     }
-#endif /* SIZE_MAX > UINT32_MAX */
+#endif /* SIZE_MAX < UINT64_MAX */
 
     longlen = (size_t)vi;
   }
@@ -2080,8 +2080,10 @@ ngtcp2_ssize ngtcp2_pkt_encode_datagram_frame(uint8_t *out, size_t outlen,
   }
 
   for (i = 0; i < fr->datacnt; ++i) {
-    assert(fr->data[i].len);
-    assert(fr->data[i].base);
+    if (fr->data[i].len == 0) {
+      continue;
+    }
+
     p = ngtcp2_cpymem(p, fr->data[i].base, fr->data[i].len);
   }
 
@@ -2421,9 +2423,7 @@ size_t ngtcp2_pkt_stream_max_datalen(int64_t stream_id, uint64_t offset,
   left -= n;
 
   if (left > 8 + 1073741823 && len > 1073741823) {
-#if SIZE_MAX > UINT32_MAX
     len = ngtcp2_min_uint64(len, 4611686018427387903lu);
-#endif /* SIZE_MAX > UINT32_MAX */
     return (size_t)ngtcp2_min_uint64(len, (uint64_t)(left - 8));
   }
 
@@ -2453,9 +2453,9 @@ size_t ngtcp2_pkt_crypto_max_datalen(uint64_t offset, size_t len, size_t left) {
   left -= n;
 
   if (left > 8 + 1073741823 && len > 1073741823) {
-#if SIZE_MAX > UINT32_MAX
+#if SIZE_MAX == UINT64_MAX
     len = ngtcp2_min_size(len, 4611686018427387903lu);
-#endif /* SIZE_MAX > UINT32_MAX */
+#endif /* SIZE_MAX == UINT64_MAX */
     return ngtcp2_min_size(len, left - 8);
   }
 
index 13ef2b2490890585fef6742cbf63e3be5af3282c..4d193125ae8e89c8a4e5c98ec0b84e4271ca629c 100644 (file)
@@ -47,9 +47,10 @@ void ngtcp2_ppe_init(ngtcp2_ppe *ppe, uint8_t *out, size_t outlen,
 int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) {
   ngtcp2_ssize rv;
   ngtcp2_buf *buf = &ppe->buf;
+  size_t buf_left = ngtcp2_buf_left(buf);
   ngtcp2_crypto_cc *cc = ppe->cc;
 
-  if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) {
+  if (buf_left <= cc->aead.max_overhead) {
     return NGTCP2_ERR_NOBUF;
   }
 
@@ -62,13 +63,13 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) {
 
     ppe->pkt_num_offset = ppe->len_offset + NGTCP2_PKT_LENGTHLEN;
 
-    rv = ngtcp2_pkt_encode_hd_long(
-      buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd);
+    rv = ngtcp2_pkt_encode_hd_long(buf->last, buf_left - cc->aead.max_overhead,
+                                   hd);
   } else {
     ppe->pkt_num_offset = 1 + hd->dcid.datalen;
 
-    rv = ngtcp2_pkt_encode_hd_short(
-      buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd);
+    rv = ngtcp2_pkt_encode_hd_short(buf->last, buf_left - cc->aead.max_overhead,
+                                    hd);
   }
 
   if (rv < 0) {
@@ -87,14 +88,14 @@ int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) {
 int ngtcp2_ppe_encode_frame(ngtcp2_ppe *ppe, ngtcp2_frame *fr) {
   ngtcp2_ssize rv;
   ngtcp2_buf *buf = &ppe->buf;
+  size_t buf_left = ngtcp2_buf_left(buf);
   ngtcp2_crypto_cc *cc = ppe->cc;
 
-  if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) {
+  if (buf_left <= cc->aead.max_overhead) {
     return NGTCP2_ERR_NOBUF;
   }
 
-  rv = ngtcp2_pkt_encode_frame(
-    buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, fr);
+  rv = ngtcp2_pkt_encode_frame(buf->last, buf_left - cc->aead.max_overhead, fr);
   if (rv < 0) {
     return (int)rv;
   }
@@ -172,18 +173,13 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) {
 
 size_t ngtcp2_ppe_left(const ngtcp2_ppe *ppe) {
   ngtcp2_crypto_cc *cc = ppe->cc;
+  size_t buf_left = ngtcp2_buf_left(&ppe->buf);
 
-  if (ngtcp2_buf_left(&ppe->buf) < cc->aead.max_overhead) {
+  if (buf_left <= cc->aead.max_overhead) {
     return 0;
   }
 
-  return ngtcp2_buf_left(&ppe->buf) - cc->aead.max_overhead;
-}
-
-size_t ngtcp2_ppe_pktlen(const ngtcp2_ppe *ppe) {
-  ngtcp2_crypto_cc *cc = ppe->cc;
-
-  return ngtcp2_buf_len(&ppe->buf) + cc->aead.max_overhead;
+  return buf_left - cc->aead.max_overhead;
 }
 
 size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) {
@@ -208,6 +204,10 @@ size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) {
 
   assert(ngtcp2_buf_left(buf) >= len + cc->aead.max_overhead);
 
+  if (len == 0) {
+    return 0;
+  }
+
   buf->last = ngtcp2_setmem(buf->last, 0, len);
 
   return len;
index 660b1482b56671fb18f194506cfb3b2957aa9839..9874b36800540df606054740e52435e857c8af58 100644 (file)
@@ -110,12 +110,6 @@ ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt);
  */
 size_t ngtcp2_ppe_left(const ngtcp2_ppe *ppe);
 
-/*
- * ngtcp2_ppe_pktlen returns the provisional packet length.  It
- * includes AEAD overhead.
- */
-size_t ngtcp2_ppe_pktlen(const ngtcp2_ppe *ppe);
-
 /*
  * ngtcp2_ppe_dgram_padding is equivalent to call
  * ngtcp2_ppe_dgram_padding_size(ppe, NGTCP2_MAX_UDP_PAYLOAD_SIZE).
index f7a7f5724b7ac3d0311219ee42d705bfd65c6e1b..101dcaa99f8c4b169b624a5a9cccecd432426563 100644 (file)
@@ -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);
index 3a9397eac5bb6f80637d4f238c8057e885d3f26d..14684a458a60e6b19371195426f7719ff3f5d151 100644 (file)
@@ -80,6 +80,9 @@ typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
 /* NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING indicates that the entry
    includes a packet which elicits PTO probe packets. */
 #define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100u
+/* NGTCP2_RTB_ENTRY_FLAG_SKIP indicates that the entry has the skipped
+   packet number. */
+#define NGTCP2_RTB_ENTRY_FLAG_SKIP 0x200u
 
 typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry;
 
@@ -187,10 +190,11 @@ typedef struct ngtcp2_rtb {
   /* num_lost_pkts is the number entries in ents which has
      NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set. */
   size_t num_lost_pkts;
-  /* num_lost_pmtud_pkts is the number of entries in ents which have
-     both NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED and
-     NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE flags set. */
-  size_t num_lost_pmtud_pkts;
+  /* num_lost_ignore_pkts is the number of entries in ents which have
+     NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set, and should be
+     excluded from lost byte count.  If only those packets are lost,
+     congestion event is not triggered. */
+  size_t num_lost_ignore_pkts;
 } ngtcp2_rtb;
 
 /*
@@ -258,7 +262,8 @@ int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
 /*
  * ngtcp2_rtb_remove_expired_lost_pkt removes expired lost packet.
  */
-void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
+void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb,
+                                        ngtcp2_duration timeout,
                                         ngtcp2_tstamp ts);
 
 /*
@@ -269,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.
index d2a2fe1fe1be0d7ba6d84d79aced9a9fa084f08d..52d05b20f0c83a014be68f3c7b44a3bf8b18ffa2 100644 (file)
@@ -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:
  *
index 4eaf615bd309f3f293d3ba2911a3b38478440378..003ec6b4c3f23ce07823734ecb1c1379c8dcae4a 100644 (file)
@@ -69,6 +69,13 @@ extern "C" {
  */
 #define NGTCP2_CRYPTO_ERR_VERIFY_TOKEN -203
 
+/**
+ * @macro
+ *
+ * :macro:`NGTCP2_CRYPTO_ERR_NOMEM` indicates out of memory.
+ */
+#define NGTCP2_CRYPTO_ERR_NOMEM -501
+
 /**
  * @function
  *
index bb983f5cf44be3f81646f9234316aaf68d9833b9..bc538e9d8422a825dde01e833f8056720a1a4aca 100644 (file)
@@ -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) */