]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
libngtcp2: update embedded library to v1.14.0
authorJan Doskočil <jan.doskocil@nic.cz>
Fri, 25 Jul 2025 15:31:21 +0000 (17:31 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Fri, 25 Jul 2025 16:07:15 +0000 (18:07 +0200)
22 files changed:
src/contrib/Makefile.inc
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_buf.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c [new file with mode: 0644]
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h [new file with mode: 0644]
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_log.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.h
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_transport_params.c
src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_vec.h
src/contrib/libngtcp2/ngtcp2/ngtcp2.h
src/contrib/libngtcp2/ngtcp2/version.h

index bae9078bf025136208760507259cd70b93abae8c..36832c8ffadf2e02a86ce7a77e3ba127798b7563 100644 (file)
@@ -222,6 +222,8 @@ libembngtcp2_la_SOURCES = \
        contrib/libngtcp2/ngtcp2/lib/ngtcp2_window_filter.h \
        contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.c \
        contrib/libngtcp2/ngtcp2/lib/ngtcp2_dcidtr.h \
+       contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c \
+       contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h \
        contrib/libngtcp2/ngtcp2/ngtcp2.h \
        contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h \
        contrib/libngtcp2/ngtcp2/ngtcp2_crypto_gnutls.h \
index 04612f11be488869b26654d80d5a55622a230537..a2ffeb6188a57e36c290dd54d1392c893b9233e9 100644 (file)
@@ -69,7 +69,7 @@ static void bbr_on_transmit(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
 
 static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr);
 
-static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr);
+static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr);
 
 static void bbr_init_round_counting(ngtcp2_cc_bbr *bbr);
 
@@ -157,8 +157,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
                                             const ngtcp2_cc_ack *ack,
                                             ngtcp2_tstamp ts);
 
-static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                 ngtcp2_tstamp ts);
+static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
 
 static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat);
 
@@ -175,8 +174,9 @@ static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
                                                ngtcp2_conn_stat *cstat,
                                                const ngtcp2_cc_ack *ack);
 
-static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                   const ngtcp2_cc_ack *ack);
+static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
+                                     ngtcp2_conn_stat *cstat,
+                                     const ngtcp2_cc_ack *ack);
 
 static int bbr_is_time_to_probe_bw(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
                                    ngtcp2_tstamp ts);
@@ -288,7 +288,7 @@ static void bbr_on_init(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
   bbr->full_bw_reached = 0;
 
   bbr_reset_congestion_signals(bbr);
-  bbr_reset_lower_bounds(bbr);
+  bbr_reset_shortterm_model(bbr);
   bbr_init_round_counting(bbr);
   bbr_reset_full_bw(bbr);
   bbr_init_pacing_rate(bbr, cstat);
@@ -344,7 +344,7 @@ static void bbr_reset_congestion_signals(ngtcp2_cc_bbr *bbr) {
   bbr->inflight_latest = 0;
 }
 
-static void bbr_reset_lower_bounds(ngtcp2_cc_bbr *bbr) {
+static void bbr_reset_shortterm_model(ngtcp2_cc_bbr *bbr) {
   bbr->bw_shortterm = UINT64_MAX;
   bbr->inflight_shortterm = UINT64_MAX;
 }
@@ -707,7 +707,7 @@ static void bbr_start_probe_bw_refill(ngtcp2_cc_bbr *bbr) {
   ngtcp2_log_info(bbr->cc.log, NGTCP2_LOG_EVENT_CCA,
                   "bbr start ProbeBW_REFILL");
 
-  bbr_reset_lower_bounds(bbr);
+  bbr_reset_shortterm_model(bbr);
 
   bbr->bw_probe_up_rounds = 0;
   bbr->bw_probe_up_acks = 0;
@@ -744,7 +744,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
     return;
   }
 
-  bbr_adapt_upper_bounds(bbr, cstat, ack);
+  bbr_adapt_longterm_model(bbr, cstat, ack);
 
   if (!bbr_is_in_probe_bw_state(bbr)) {
     return;
@@ -756,7 +756,7 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
       return;
     }
 
-    if (bbr_is_time_to_cruise(bbr, cstat, ts)) {
+    if (bbr_is_time_to_cruise(bbr, cstat)) {
       bbr_start_probe_bw_cruise(bbr);
     }
 
@@ -785,30 +785,22 @@ static void bbr_update_probe_bw_cycle_phase(ngtcp2_cc_bbr *bbr,
   }
 }
 
-static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                 ngtcp2_tstamp ts) {
-  (void)ts;
-
-  if (cstat->bytes_in_flight > bbr_inflight_with_headroom(bbr, cstat)) {
-    return 0;
-  }
-
-  if (cstat->bytes_in_flight <= bbr_inflight(bbr, cstat, 100)) {
-    return 1;
-  }
+static int bbr_is_time_to_cruise(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
+  uint64_t inflight = ngtcp2_min_uint64(bbr_inflight_with_headroom(bbr, cstat),
+                                        bbr_inflight(bbr, cstat, 100));
 
-  return 0;
+  return cstat->bytes_in_flight <= inflight;
 }
 
 static int bbr_is_time_to_go_down(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat) {
   if (bbr->rst->is_cwnd_limited && cstat->cwnd >= bbr->inflight_longterm) {
     bbr_reset_full_bw(bbr);
     bbr->full_bw = cstat->delivery_rate_sec;
-  } else if (bbr->full_bw_now) {
-    return 1;
+
+    return 0;
   }
 
-  return 0;
+  return bbr->full_bw_now;
 }
 
 static int bbr_has_elapsed_in_phase(ngtcp2_cc_bbr *bbr,
@@ -871,8 +863,9 @@ static void bbr_probe_inflight_longterm_upward(ngtcp2_cc_bbr *bbr,
   }
 }
 
-static void bbr_adapt_upper_bounds(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
-                                   const ngtcp2_cc_ack *ack) {
+static void bbr_adapt_longterm_model(ngtcp2_cc_bbr *bbr,
+                                     ngtcp2_conn_stat *cstat,
+                                     const ngtcp2_cc_ack *ack) {
   if (bbr->ack_phase == NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_STARTING &&
       bbr->round_start) {
     bbr->ack_phase = NGTCP2_BBR_ACK_PHASE_ACKS_PROBE_FEEDBACK;
@@ -917,7 +910,7 @@ static void bbr_pick_probe_wait(ngtcp2_cc_bbr *bbr) {
 
   bbr->rand(&rand, 1, &bbr->rand_ctx);
 
-  bbr->rounds_since_bw_probe = (uint64_t)(rand * 2 / 256);
+  bbr->rounds_since_bw_probe = (uint64_t)(rand / 128);
 
   bbr->rand(&rand, 1, &bbr->rand_ctx);
 
@@ -980,9 +973,8 @@ static void bbr_handle_lost_packet(ngtcp2_cc_bbr *bbr, ngtcp2_conn_stat *cstat,
   }
 
   rs->tx_in_flight = pkt->tx_in_flight;
-  /* bbr->rst->lost is not incremented for pkt yet */
-  assert(bbr->rst->lost + pkt->pktlen >= pkt->lost);
-  rs->lost = bbr->rst->lost + pkt->pktlen - pkt->lost;
+  assert(bbr->rst->lost >= pkt->lost);
+  rs->lost = bbr->rst->lost - pkt->lost;
   rs->is_app_limited = pkt->is_app_limited;
 
   if (bbr_is_inflight_too_high(bbr)) {
@@ -1121,7 +1113,7 @@ static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
 }
 
 static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) {
-  bbr_reset_lower_bounds(bbr);
+  bbr_reset_shortterm_model(bbr);
 
   if (bbr->full_bw_reached) {
     bbr_start_probe_bw_down(bbr, ts);
@@ -1226,12 +1218,9 @@ static uint64_t bbr_probe_rtt_cwnd(ngtcp2_cc_bbr *bbr,
 
 static void bbr_bound_cwnd_for_probe_rtt(ngtcp2_cc_bbr *bbr,
                                          ngtcp2_conn_stat *cstat) {
-  uint64_t probe_rtt_cwnd;
-
   if (bbr->state == NGTCP2_BBR_STATE_PROBE_RTT) {
-    probe_rtt_cwnd = bbr_probe_rtt_cwnd(bbr, cstat);
-
-    cstat->cwnd = ngtcp2_min_uint64(cstat->cwnd, probe_rtt_cwnd);
+    cstat->cwnd =
+      ngtcp2_min_uint64(cstat->cwnd, bbr_probe_rtt_cwnd(bbr, cstat));
   }
 }
 
@@ -1401,21 +1390,23 @@ void ngtcp2_cc_bbr_init(ngtcp2_cc_bbr *bbr, ngtcp2_log *log,
                         ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
                         ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
                         const ngtcp2_rand_ctx *rand_ctx) {
-  memset(bbr, 0, sizeof(*bbr));
-
-  bbr->cc.log = log;
-  bbr->cc.on_pkt_lost = bbr_cc_on_pkt_lost;
-  bbr->cc.congestion_event = bbr_cc_congestion_event;
-  bbr->cc.on_spurious_congestion = bbr_cc_on_spurious_congestion;
-  bbr->cc.on_persistent_congestion = bbr_cc_on_persistent_congestion;
-  bbr->cc.on_ack_recv = bbr_cc_on_ack_recv;
-  bbr->cc.on_pkt_sent = bbr_cc_on_pkt_sent;
-  bbr->cc.reset = bbr_cc_reset;
-
-  bbr->rst = rst;
-  bbr->rand = rand;
-  bbr->rand_ctx = *rand_ctx;
-  bbr->initial_cwnd = cstat->cwnd;
+  *bbr = (ngtcp2_cc_bbr){
+    .cc =
+      {
+        .log = log,
+        .on_pkt_lost = bbr_cc_on_pkt_lost,
+        .congestion_event = bbr_cc_congestion_event,
+        .on_spurious_congestion = bbr_cc_on_spurious_congestion,
+        .on_persistent_congestion = bbr_cc_on_persistent_congestion,
+        .on_ack_recv = bbr_cc_on_ack_recv,
+        .on_pkt_sent = bbr_cc_on_pkt_sent,
+        .reset = bbr_cc_reset,
+      },
+    .rst = rst,
+    .rand = rand,
+    .rand_ctx = *rand_ctx,
+    .initial_cwnd = cstat->cwnd,
+  };
 
   bbr_on_init(bbr, cstat, initial_ts);
 }
index e87adb119916ca3c8960f986928780b1f9d21858..b2bdafc3875260300619e940867accc3e585fa5d 100644 (file)
@@ -62,13 +62,17 @@ void ngtcp2_buf_reset(ngtcp2_buf *buf);
  * written to the underlying buffer.  In other words, it returns
  * buf->end - buf->last.
  */
-#define ngtcp2_buf_left(BUF) (size_t)((BUF)->end - (BUF)->last)
+static inline size_t ngtcp2_buf_left(const ngtcp2_buf *buf) {
+  return (size_t)(buf->end - buf->last);
+}
 
 /*
  * ngtcp2_buf_len returns the number of bytes left to read.  In other
  * words, it returns buf->last - buf->pos.
  */
-#define ngtcp2_buf_len(BUF) (size_t)((BUF)->last - (BUF)->pos)
+static inline size_t ngtcp2_buf_len(const ngtcp2_buf *buf) {
+  return (size_t)(buf->last - buf->pos);
+}
 
 /*
  * ngtcp2_buf_cap returns the capacity of the buffer.  In other words,
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.c
new file mode 100644 (file)
index 0000000..7e77186
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ngtcp2_callbacks.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include "ngtcp2_unreachable.h"
+
+static void callbacks_copy(ngtcp2_callbacks *dest, const ngtcp2_callbacks *src,
+                           int callbacks_version) {
+  assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
+
+  memcpy(dest, src, ngtcp2_callbackslen_version(callbacks_version));
+}
+
+const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
+  ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src) {
+  if (callbacks_version == NGTCP2_CALLBACKS_VERSION) {
+    return src;
+  }
+
+  memset(dest, 0, sizeof(*dest));
+
+  callbacks_copy(dest, src, callbacks_version);
+
+  return dest;
+}
+
+void ngtcp2_callbacks_convert_to_old(int callbacks_version,
+                                     ngtcp2_callbacks *dest,
+                                     const ngtcp2_callbacks *src) {
+  assert(callbacks_version != NGTCP2_CALLBACKS_VERSION);
+
+  callbacks_copy(dest, src, callbacks_version);
+}
+
+size_t ngtcp2_callbackslen_version(int callbacks_version) {
+  ngtcp2_callbacks callbacks;
+
+  switch (callbacks_version) {
+  case NGTCP2_CALLBACKS_VERSION:
+    return sizeof(callbacks);
+  case NGTCP2_CALLBACKS_V1:
+    return offsetof(ngtcp2_callbacks, tls_early_data_rejected) +
+           sizeof(callbacks.tls_early_data_rejected);
+  default:
+    ngtcp2_unreachable();
+  }
+}
diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_callbacks.h
new file mode 100644 (file)
index 0000000..751766b
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ngtcp2
+ *
+ * Copyright (c) 2025 ngtcp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGTCP2_CALLBACKS_H
+#define NGTCP2_CALLBACKS_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif /* defined(HAVE_CONFIG_H) */
+
+#include <ngtcp2/ngtcp2.h>
+
+/*
+ * ngtcp2_callbacks_convert_to_latest converts |src| of version
+ * |callbacks_version| to the latest version NGTCP2_CALLBACKS_VERSION.
+ *
+ * |dest| must point to the latest version.  |src| may be the older
+ * version, and if so, it may have fewer fields.  Accessing those
+ * fields causes undefined behavior.
+ *
+ * If |callbacks_version| == NGTCP2_CALLBACKS_VERSION, no conversion
+ * is made, and |src| is returned.  Otherwise, first |dest| is
+ * zero-initialized, and then all valid fields in |src| are copied
+ * into |dest|.  Finally, |dest| is returned.
+ */
+const ngtcp2_callbacks *ngtcp2_callbacks_convert_to_latest(
+  ngtcp2_callbacks *dest, int callbacks_version, const ngtcp2_callbacks *src);
+
+/*
+ * ngtcp2_callbacks_convert_to_old converts |src| of the latest
+ * version to |dest| of version |callbacks_version|.
+ *
+ * |callbacks_version| must not be the latest version
+ *  NGTCP2_CALLBACKS_VERSION.
+ *
+ * |dest| points to the older version, and it may have fewer fields.
+ * Accessing those fields causes undefined behavior.
+ *
+ * This function copies all valid fields in version
+ * |callbacks_version| from |src| to |dest|.
+ */
+void ngtcp2_callbacks_convert_to_old(int callbacks_version,
+                                     ngtcp2_callbacks *dest,
+                                     const ngtcp2_callbacks *src);
+
+/*
+ * ngtcp2_callbackslen_version returns the effective length of
+ * ngtcp2_callbacks at the version |callbacks_version|.
+ */
+size_t ngtcp2_callbackslen_version(int callbacks_version);
+
+#endif /* !defined(NGTCP2_CALLBACKS_H) */
index ad3665b6cf64d49b809e14d7487aa93e5e3cd160..c16953802afd2ada0533c0395591ef1e061e03aa 100644 (file)
@@ -59,14 +59,16 @@ ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
 static void reno_cc_reset(ngtcp2_cc_reno *reno) { reno->pending_add = 0; }
 
 void ngtcp2_cc_reno_init(ngtcp2_cc_reno *reno, ngtcp2_log *log) {
-  memset(reno, 0, sizeof(*reno));
-
-  reno->cc.log = log;
-  reno->cc.on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked;
-  reno->cc.congestion_event = ngtcp2_cc_reno_cc_congestion_event;
-  reno->cc.on_persistent_congestion =
-    ngtcp2_cc_reno_cc_on_persistent_congestion;
-  reno->cc.reset = ngtcp2_cc_reno_cc_reset;
+  *reno = (ngtcp2_cc_reno){
+    .cc =
+      {
+        .log = log,
+        .on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked,
+        .congestion_event = ngtcp2_cc_reno_cc_congestion_event,
+        .on_persistent_congestion = ngtcp2_cc_reno_cc_on_persistent_congestion,
+        .reset = ngtcp2_cc_reno_cc_reset,
+      },
+  };
 
   reno_cc_reset(reno);
 }
@@ -148,7 +150,7 @@ void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
 static void cubic_vars_reset(ngtcp2_cubic_vars *v) {
   v->cwnd_prior = 0;
   v->w_max = 0;
-  v->k = 0;
+  v->k_m = 0;
   v->epoch_start = UINT64_MAX;
   v->w_est = 0;
 
@@ -176,17 +178,18 @@ static void cubic_cc_reset(ngtcp2_cc_cubic *cubic) {
 
 void ngtcp2_cc_cubic_init(ngtcp2_cc_cubic *cubic, ngtcp2_log *log,
                           ngtcp2_rst *rst) {
-  memset(cubic, 0, sizeof(*cubic));
-
-  cubic->cc.log = log;
-  cubic->cc.on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv;
-  cubic->cc.congestion_event = ngtcp2_cc_cubic_cc_congestion_event;
-  cubic->cc.on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion;
-  cubic->cc.on_persistent_congestion =
-    ngtcp2_cc_cubic_cc_on_persistent_congestion;
-  cubic->cc.reset = ngtcp2_cc_cubic_cc_reset;
-
-  cubic->rst = rst;
+  *cubic = (ngtcp2_cc_cubic){
+    .cc =
+      {
+        .log = log,
+        .on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv,
+        .congestion_event = ngtcp2_cc_cubic_cc_congestion_event,
+        .on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion,
+        .on_persistent_congestion = ngtcp2_cc_cubic_cc_on_persistent_congestion,
+        .reset = ngtcp2_cc_cubic_cc_reset,
+      },
+    .rst = rst,
+  };
 
   cubic_cc_reset(cubic);
 }
@@ -223,23 +226,45 @@ uint64_t ngtcp2_cbrt(uint64_t n) {
 #define NGTCP2_HS_CSS_GROWTH_DIVISOR 4
 #define NGTCP2_HS_CSS_ROUNDS 5
 
-static int64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic,
-                                        const ngtcp2_conn_stat *cstat,
-                                        ngtcp2_tstamp ts) {
+static uint64_t cubic_cc_compute_w_cubic(ngtcp2_cc_cubic *cubic,
+                                         const ngtcp2_conn_stat *cstat,
+                                         ngtcp2_tstamp ts) {
   ngtcp2_duration t = ts - cubic->current.epoch_start;
-  int64_t tx = (int64_t)((t << 10) / NGTCP2_SECONDS);
-  int64_t time_delta = ngtcp2_min_int64(tx - cubic->current.k, 3600 << 10);
-  int64_t delta = ((((time_delta * time_delta) >> 10) * time_delta) >> 20) *
-                  (int64_t)cstat->max_tx_udp_payload_size * 4 / 10;
+  uint64_t tx_m = (t << 10) / NGTCP2_SECONDS;
+  int neg = tx_m < cubic->current.k_m;
+  uint64_t time_delta_m;
+  uint64_t delta;
+
+  /* Avoid signed bit-shift */
+  if (neg) {
+    time_delta_m = cubic->current.k_m - tx_m;
+  } else {
+    time_delta_m = tx_m - cubic->current.k_m;
+  }
+
+  time_delta_m = ngtcp2_min_uint64(time_delta_m, 3600 << 10);
+
+  delta = ((((time_delta_m * time_delta_m) >> 10) * time_delta_m) >> 10) *
+          cstat->max_tx_udp_payload_size * 4 / 10;
+  delta >>= 10;
+
+  if (neg) {
+    if (cubic->current.w_max < delta) {
+      /* Negative w_cubic is not interesting. */
+      return 0;
+    }
 
-  return (int64_t)cubic->current.w_max + delta;
+    return cubic->current.w_max - delta;
+  }
+
+  return cubic->current.w_max + delta;
 }
 
 void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
                                     const ngtcp2_cc_ack *ack,
                                     ngtcp2_tstamp ts) {
   ngtcp2_cc_cubic *cubic = ngtcp2_struct_of(cc, ngtcp2_cc_cubic, cc);
-  int64_t w_cubic, w_cubic_next;
+  uint64_t w_cubic, w_cubic_next;
   uint64_t target, m;
   ngtcp2_duration rtt_thresh;
   int round_start;
@@ -346,13 +371,12 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
     cubic, cstat,
     ts - cubic->current.app_limited_duration + cstat->smoothed_rtt);
 
-  if (w_cubic_next < (int64_t)cstat->cwnd) {
+  if (w_cubic_next < cstat->cwnd) {
     target = cstat->cwnd;
-  } else if (2 * w_cubic_next > 3 * (int64_t)cstat->cwnd) {
+  } else if (2 * w_cubic_next > 3 * cstat->cwnd) {
     target = cstat->cwnd * 3 / 2;
   } else {
-    assert(w_cubic_next >= 0);
-    target = (uint64_t)w_cubic_next;
+    target = w_cubic_next;
   }
 
   m = ack->bytes_delivered * cstat->max_tx_udp_payload_size +
@@ -365,19 +389,19 @@ void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
     cubic->current.w_est += m / cstat->cwnd;
   }
 
-  if ((int64_t)cubic->current.w_est > w_cubic) {
+  if (cubic->current.w_est > w_cubic) {
     cstat->cwnd = cubic->current.w_est;
   } else {
     m = (target - cstat->cwnd) * cstat->max_tx_udp_payload_size +
         cubic->current.pending_bytes_delivered;
-    cstat->cwnd += m / cstat->cwnd;
     cubic->current.pending_bytes_delivered = m % cstat->cwnd;
+    cstat->cwnd += m / cstat->cwnd;
   }
 
   ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
                   "%" PRIu64 " bytes acked, cubic-ca cwnd=%" PRIu64
-                  " k=%" PRIi64 " target=%" PRIu64 " w_est=%" PRIu64,
-                  ack->bytes_delivered, cstat->cwnd, cubic->current.k, target,
+                  " k_m=%" PRIu64 " target=%" PRIu64 " w_est=%" PRIu64,
+                  ack->bytes_delivered, cstat->cwnd, cubic->current.k_m, target,
                   cubic->current.w_est);
 }
 
@@ -413,6 +437,9 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
     cubic->current.w_max = cstat->cwnd;
   }
 
+  cubic->current.w_max =
+    ngtcp2_max_uint64(cubic->current.w_max, 2 * cstat->max_tx_udp_payload_size);
+
   cstat->ssthresh = cstat->cwnd * 7 / 10;
 
   if (cubic->rst->rs.delivered * 2 < cstat->cwnd) {
@@ -430,17 +457,12 @@ void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
 
   cubic->current.w_est = cstat->cwnd;
 
-  if (cstat->cwnd < cubic->current.w_max) {
-    cwnd_delta = cubic->current.w_max - cstat->cwnd;
-  } else {
-    cwnd_delta = cstat->cwnd - cubic->current.w_max;
-  }
+  assert(cubic->current.w_max >= cstat->cwnd);
 
-  cubic->current.k = (int64_t)ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 /
-                                          cstat->max_tx_udp_payload_size);
-  if (cstat->cwnd >= cubic->current.w_max) {
-    cubic->current.k = -cubic->current.k;
-  }
+  cwnd_delta = cubic->current.w_max - cstat->cwnd;
+
+  cubic->current.k_m =
+    ngtcp2_cbrt((cwnd_delta << 30) * 10 / 4 / cstat->max_tx_udp_payload_size);
 
   ngtcp2_log_info(cubic->cc.log, NGTCP2_LOG_EVENT_CCA,
                   "reduce cwnd because of packet loss cwnd=%" PRIu64,
index 296a1a433f1b547dcabe3fa9d73e3b0d2aaa19b0..e4e19e1aa6b9455da4682e75a03f1b0b5da5a9da 100644 (file)
@@ -329,7 +329,8 @@ void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
 typedef struct ngtcp2_cubic_vars {
   uint64_t cwnd_prior;
   uint64_t w_max;
-  int64_t k;
+  /* CUBIC K with 10 bits extra precision. */
+  uint64_t k_m;
   ngtcp2_tstamp epoch_start;
   uint64_t w_est;
 
index 6abebee33a8aba069c7ab442a3584d34ce8b2a29..393c2281f1ae132548036df5c53289ce9e429098 100644 (file)
@@ -39,6 +39,7 @@
 #include "ngtcp2_net.h"
 #include "ngtcp2_transport_params.h"
 #include "ngtcp2_settings.h"
+#include "ngtcp2_callbacks.h"
 #include "ngtcp2_tstamp.h"
 #include "ngtcp2_frame_chain.h"
 
@@ -283,6 +284,33 @@ static int conn_call_remove_connection_id(ngtcp2_conn *conn,
   return 0;
 }
 
+static int conn_call_begin_path_validation(ngtcp2_conn *conn,
+                                           const ngtcp2_pv *pv) {
+  int rv;
+  uint32_t flags = NGTCP2_PATH_VALIDATION_FLAG_NONE;
+  const ngtcp2_path *old_path = NULL;
+
+  if (!pv || !conn->callbacks.begin_path_validation) {
+    return 0;
+  }
+
+  if (pv->flags & NGTCP2_PV_FLAG_PREFERRED_ADDR) {
+    flags |= NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR;
+  }
+
+  if (pv->flags & NGTCP2_PV_FLAG_FALLBACK_PRESENT) {
+    old_path = &pv->fallback_dcid.ps.path;
+  }
+
+  rv = conn->callbacks.begin_path_validation(conn, flags, &pv->dcid.ps.path,
+                                             old_path, conn->user_data);
+  if (rv != 0) {
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+
 static int conn_call_path_validation(ngtcp2_conn *conn, const ngtcp2_pv *pv,
                                      ngtcp2_path_validation_result res) {
   int rv;
@@ -668,13 +696,13 @@ static int conn_call_recv_tx_key(ngtcp2_conn *conn,
   return 0;
 }
 
+// pktns_init initializes |pktns|.  It assumes that the object pointed
+// by |pktns| is zero-cleared.
 static void pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id,
                        ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num,
                        ngtcp2_log *log, ngtcp2_qlog *qlog,
                        ngtcp2_objalloc *rtb_entry_objalloc,
                        ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
-  memset(pktns, 0, sizeof(*pktns));
-
   ngtcp2_gaptr_init(&pktns->rx.pngap, mem);
 
   pktns->tx.last_pkt_num = initial_pkt_num - 1;
@@ -696,7 +724,7 @@ static int pktns_new(ngtcp2_pktns **ppktns, ngtcp2_pktns_id pktns_id,
                      ngtcp2_log *log, ngtcp2_qlog *qlog,
                      ngtcp2_objalloc *rtb_entry_objalloc,
                      ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem) {
-  *ppktns = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pktns));
+  *ppktns = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_pktns));
   if (*ppktns == NULL) {
     return NGTCP2_ERR_NOMEM;
   }
@@ -1109,13 +1137,16 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
   uint32_t *preferred_versions;
   ngtcp2_settings settingsbuf;
   ngtcp2_transport_params paramsbuf;
-  (void)callbacks_version;
+  ngtcp2_callbacks callbacksbuf;
+  uint64_t map_seed;
   (void)settings_version;
 
   settings =
     ngtcp2_settings_convert_to_latest(&settingsbuf, settings_version, settings);
   params = ngtcp2_transport_params_convert_to_latest(
     &paramsbuf, transport_params_version, params);
+  callbacks = ngtcp2_callbacks_convert_to_latest(&callbacksbuf,
+                                                 callbacks_version, callbacks);
 
   assert(settings->max_window <= NGTCP2_MAX_VARINT);
   assert(settings->max_stream_window <= NGTCP2_MAX_VARINT);
@@ -1217,7 +1248,8 @@ static int conn_new(ngtcp2_conn **pconn, const ngtcp2_cid *dcid,
 
   ngtcp2_pq_init(&(*pconn)->scid.used, retired_ts_less, mem);
 
-  ngtcp2_map_init(&(*pconn)->strms, mem);
+  callbacks->rand((uint8_t *)&map_seed, sizeof(map_seed), &settings->rand_ctx);
+  ngtcp2_map_init(&(*pconn)->strms, map_seed, mem);
 
   ngtcp2_pq_init(&(*pconn)->tx.strmq, cycle_less, mem);
 
@@ -3090,6 +3122,7 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
   ngtcp2_strm *strm;
   int pkt_empty = 1;
   uint64_t ndatalen = 0;
+  uint64_t wdatalen;
   int send_stream = 0;
   int stream_blocked = 0;
   int send_datagram = 0;
@@ -3780,10 +3813,12 @@ static ngtcp2_ssize conn_write_pkt(ngtcp2_conn *conn, ngtcp2_pkt_info *pi,
   left = ngtcp2_ppe_left(ppe);
 
   if (*pfrc == NULL && send_stream && ngtcp2_pq_empty(&conn->tx.strmq) &&
-      (ndatalen = ngtcp2_pkt_stream_max_datalen(
+      (wdatalen = ngtcp2_pkt_stream_max_datalen(
          vmsg->stream.strm->stream_id, vmsg->stream.strm->tx.offset, ndatalen,
          left)) != (size_t)-1 &&
-      (ndatalen || datalen == 0)) {
+      (wdatalen == ndatalen || wdatalen >= NGTCP2_MIN_STREAM_DATALEN) &&
+      (wdatalen || datalen == 0)) {
+    ndatalen = wdatalen;
     datacnt = ngtcp2_vec_copy_at_most(data, NGTCP2_MAX_STREAM_DATACNT,
                                       vmsg->stream.data, vmsg->stream.datacnt,
                                       (size_t)ndatalen);
@@ -5786,7 +5821,7 @@ static int conn_recv_path_response(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
 
   conn->pv = npv;
 
-  return 0;
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 /*
@@ -6543,6 +6578,7 @@ static int is_unrecoverable_error(int liberr) {
   case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
   case NGTCP2_ERR_TRANSPORT_PARAM:
   case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE:
+  case NGTCP2_ERR_INTERNAL:
     return 1;
   }
 
@@ -7056,23 +7092,23 @@ static int conn_recv_stream(ngtcp2_conn *conn, const ngtcp2_stream *fr) {
     fin = (strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) &&
           rx_offset == strm->rx.last_offset;
 
-    if (fin || datalen) {
-      if (fin) {
-        sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
-      }
-      if (!conn_is_tls_handshake_completed(conn)) {
-        sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
-      }
-      rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data,
-                                      (size_t)datalen);
-      if (rv != 0) {
-        return rv;
-      }
+    assert(fin || datalen);
 
-      rv = conn_emit_pending_stream_data(conn, strm, rx_offset);
-      if (rv != 0) {
-        return rv;
-      }
+    if (fin) {
+      sdflags |= NGTCP2_STREAM_DATA_FLAG_FIN;
+    }
+    if (!conn_is_tls_handshake_completed(conn)) {
+      sdflags |= NGTCP2_STREAM_DATA_FLAG_0RTT;
+    }
+    rv = conn_call_recv_stream_data(conn, strm, sdflags, offset, data,
+                                    (size_t)datalen);
+    if (rv != 0) {
+      return rv;
+    }
+
+    rv = conn_emit_pending_stream_data(conn, strm, rx_offset);
+    if (rv != 0) {
+      return rv;
     }
   } else if (fr->datacnt && !(strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING)) {
     rv = ngtcp2_strm_recv_reordering(strm, fr->data[0].base, fr->data[0].len,
@@ -8030,7 +8066,12 @@ static int conn_select_preferred_addr(ngtcp2_conn *conn) {
 
   conn->pv = pv;
 
-  return conn_call_activate_dcid(conn, &pv->dcid);
+  rv = conn_call_activate_dcid(conn, &pv->dcid);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 /*
@@ -8421,7 +8462,7 @@ static int conn_recv_non_probing_pkt_on_new_path(ngtcp2_conn *conn,
 
   conn->pv = pv;
 
-  return 0;
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 /*
@@ -13138,7 +13179,12 @@ int ngtcp2_conn_initiate_immediate_migration(ngtcp2_conn *conn,
     conn->pv = pv;
   }
 
-  return conn_call_activate_dcid(conn, &conn->dcid.current);
+  rv = conn_call_activate_dcid(conn, &conn->dcid.current);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path,
@@ -13178,7 +13224,12 @@ int ngtcp2_conn_initiate_migration(ngtcp2_conn *conn, const ngtcp2_path *path,
 
   conn->pv = pv;
 
-  return conn_call_activate_dcid(conn, &pv->dcid);
+  rv = conn_call_activate_dcid(conn, &pv->dcid);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return conn_call_begin_path_validation(conn, conn->pv);
 }
 
 uint64_t ngtcp2_conn_get_max_data_left(ngtcp2_conn *conn) {
@@ -13454,7 +13505,7 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close(
   ngtcp2_crypto_km ckm;
   ngtcp2_crypto_cc cc;
   ngtcp2_ppe ppe;
-  ngtcp2_frame fr = {0};
+  ngtcp2_frame fr;
   int rv;
 
   ngtcp2_pkt_hd_init(&hd, NGTCP2_PKT_FLAG_LONG_FORM, NGTCP2_PKT_INITIAL, dcid,
@@ -13485,11 +13536,12 @@ ngtcp2_ssize ngtcp2_pkt_write_connection_close(
     return NGTCP2_ERR_NOBUF;
   }
 
-  fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
-  fr.connection_close.error_code = error_code;
-  fr.connection_close.frame_type = 0;
-  fr.connection_close.reasonlen = reasonlen;
-  fr.connection_close.reason = (uint8_t *)reason;
+  fr.connection_close = (ngtcp2_connection_close){
+    .type = NGTCP2_FRAME_CONNECTION_CLOSE,
+    .error_code = error_code,
+    .reasonlen = reasonlen,
+    .reason = (uint8_t *)reason,
+  };
 
   rv = ngtcp2_ppe_encode_frame(&ppe, &fr);
   if (rv != 0) {
index de78bcb8070f53183cd2c4480e456935617b66f0..d5c3f61d2acc7bc690db530d4c151198a5cd6e6f 100644 (file)
@@ -292,8 +292,11 @@ void ngtcp2_ksl_clear(ngtcp2_ksl *ksl);
 /*
  * ngtcp2_ksl_nth_node returns the |n|th node under |blk|.
  */
-#define ngtcp2_ksl_nth_node(KSL, BLK, N)                                       \
-  ((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
+static inline ngtcp2_ksl_node *ngtcp2_ksl_nth_node(const ngtcp2_ksl *ksl,
+                                                   const ngtcp2_ksl_blk *blk,
+                                                   size_t n) {
+  return (ngtcp2_ksl_node *)(void *)(blk->nodes + ksl->nodelen * n);
+}
 
 #ifndef WIN32
 /*
@@ -315,18 +318,21 @@ void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
  * |it| points to.  It is undefined to call this function when
  * ngtcp2_ksl_it_end(it) returns nonzero.
  */
-#define ngtcp2_ksl_it_get(IT)                                                  \
-  ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data
+static inline void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it) {
+  return ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->data;
+}
 
 /*
  * ngtcp2_ksl_it_next advances the iterator by one.  It is undefined
  * if this function is called when ngtcp2_ksl_it_end(it) returns
  * nonzero.
  */
-#define ngtcp2_ksl_it_next(IT)                                                 \
-  (++(IT)->i == (IT)->blk->n && (IT)->blk->next                                \
-     ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0)                              \
-     : 0)
+static inline void ngtcp2_ksl_it_next(ngtcp2_ksl_it *it) {
+  if (++it->i == it->blk->n && it->blk->next) {
+    it->blk = it->blk->next;
+    it->i = 0;
+  }
+}
 
 /*
  * ngtcp2_ksl_it_prev moves backward the iterator by one.  It is
@@ -339,8 +345,9 @@ void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it);
  * ngtcp2_ksl_it_end returns nonzero if |it| points to the one beyond
  * the last node.
  */
-#define ngtcp2_ksl_it_end(IT)                                                  \
-  ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
+static inline int ngtcp2_ksl_it_end(const ngtcp2_ksl_it *it) {
+  return it->blk->n == it->i && it->blk->next == NULL;
+}
 
 /*
  * ngtcp2_ksl_it_begin returns nonzero if |it| points to the first
@@ -354,8 +361,9 @@ int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it);
  * It is undefined to call this function when ngtcp2_ksl_it_end(it)
  * returns nonzero.
  */
-#define ngtcp2_ksl_it_key(IT)                                                  \
-  ((ngtcp2_ksl_key *)ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
+static inline ngtcp2_ksl_key *ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it) {
+  return (ngtcp2_ksl_key *)ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->key;
+}
 
 /*
  * ngtcp2_ksl_range_compar is an implementation of ngtcp2_ksl_compar.
index fc4eb443517d4032dd43c19be4ef7ed4a3f3b424..e006c22e4e7ff004d29c8c29914b9705149d4f9a 100644 (file)
@@ -594,9 +594,9 @@ void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) {
     return;
   }
 
-  memset(&shd, 0, sizeof(shd));
-
-  shd.type = NGTCP2_PKT_STATELESS_RESET;
+  shd = (ngtcp2_pkt_hd){
+    .type = NGTCP2_PKT_STATELESS_RESET,
+  };
 
   log->log_printf(
     log->user_data, (NGTCP2_LOG_PKT " token=0x%s randlen=%zu"),
index 5e4726e63ff7eff33ebc41d3035859aa9414295c..246c779f2908ca701efb54246d003b8761ef4493 100644 (file)
 
 #define NGTCP2_INITIAL_HASHBITS 4
 
-void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
+void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem) {
   map->mem = mem;
   map->hashbits = 0;
   map->table = NULL;
+  map->seed = seed;
   map->size = 0;
 }
 
@@ -77,8 +78,14 @@ int ngtcp2_map_each(const ngtcp2_map *map, int (*func)(void *data, void *ptr),
   return 0;
 }
 
-static size_t hash(ngtcp2_map_key_type key, size_t bits) {
-  return (size_t)((key * 11400714819323198485llu) >> (64 - bits));
+static size_t map_hash(const ngtcp2_map *map, ngtcp2_map_key_type key) {
+  /* hasher from
+     https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
+     We do not perform finalization here because we use top bits
+     anyway. */
+  key += map->seed;
+  key *= 0xf1357aea2e62a9c5ull;
+  return (size_t)((key * 11400714819323198485llu) >> (64 - map->hashbits));
 }
 
 static void map_bucket_swap(ngtcp2_map_bucket *a, ngtcp2_map_bucket *b) {
@@ -109,28 +116,28 @@ void ngtcp2_map_print_distance(const ngtcp2_map *map) {
       continue;
     }
 
-    idx = hash(bkt->key, map->hashbits);
+    idx = map_hash(map, bkt->key);
     fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
-            hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl);
+            map_hash(map, bkt->key), bkt->key, idx, bkt->psl);
   }
 }
 #endif /* !defined(WIN32) */
 
-static int insert(ngtcp2_map_bucket *table, size_t hashbits,
-                  ngtcp2_map_key_type key, void *data) {
-  size_t idx = hash(key, hashbits);
+static int map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
+  size_t idx = map_hash(map, key);
   ngtcp2_map_bucket b = {
     .key = key,
     .data = data,
   };
   ngtcp2_map_bucket *bkt;
-  size_t mask = (1u << hashbits) - 1;
+  size_t mask = (1u << map->hashbits) - 1;
 
   for (;;) {
-    bkt = &table[idx];
+    bkt = &map->table[idx];
 
     if (bkt->data == NULL) {
       *bkt = b;
+      ++map->size;
       return 0;
     }
 
@@ -151,15 +158,19 @@ static int insert(ngtcp2_map_bucket *table, size_t hashbits,
 
 static int map_resize(ngtcp2_map *map, size_t new_hashbits) {
   size_t i;
-  ngtcp2_map_bucket *new_table;
   ngtcp2_map_bucket *bkt;
   size_t tablelen;
   int rv;
+  ngtcp2_map new_map = {
+    .table = ngtcp2_mem_calloc(map->mem, 1u << new_hashbits,
+                               sizeof(ngtcp2_map_bucket)),
+    .mem = map->mem,
+    .seed = map->seed,
+    .hashbits = new_hashbits,
+  };
   (void)rv;
 
-  new_table =
-    ngtcp2_mem_calloc(map->mem, 1u << new_hashbits, sizeof(ngtcp2_map_bucket));
-  if (new_table == NULL) {
+  if (new_map.table == NULL) {
     return NGTCP2_ERR_NOMEM;
   }
 
@@ -172,15 +183,15 @@ static int map_resize(ngtcp2_map *map, size_t new_hashbits) {
         continue;
       }
 
-      rv = insert(new_table, new_hashbits, bkt->key, bkt->data);
+      rv = map_insert(&new_map, bkt->key, bkt->data);
 
       assert(0 == rv);
     }
   }
 
   ngtcp2_mem_free(map->mem, map->table);
+  map->table = new_map.table;
   map->hashbits = new_hashbits;
-  map->table = new_table;
 
   return 0;
 }
@@ -190,10 +201,10 @@ int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
 
   assert(data);
 
-  /* Load factor is 0.75 */
+  /* Load factor is 7/8 */
   /* Under the very initial condition, that is map->size == 0 and
-     map->hashbits == 0, 4 > 3 still holds nicely. */
-  if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) {
+     map->hashbits == 0, 8 > 7 still holds nicely. */
+  if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) {
     if (map->hashbits) {
       rv = map_resize(map, map->hashbits + 1);
       if (rv != 0) {
@@ -207,13 +218,11 @@ int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
     }
   }
 
-  rv = insert(map->table, map->hashbits, key, data);
+  rv = map_insert(map, key, data);
   if (rv != 0) {
     return rv;
   }
 
-  ++map->size;
-
   return 0;
 }
 
@@ -227,7 +236,7 @@ void *ngtcp2_map_find(const ngtcp2_map *map, ngtcp2_map_key_type key) {
     return NULL;
   }
 
-  idx = hash(key, map->hashbits);
+  idx = map_hash(map, key);
   mask = (1u << map->hashbits) - 1;
 
   for (;;) {
@@ -256,7 +265,7 @@ int ngtcp2_map_remove(ngtcp2_map *map, ngtcp2_map_key_type key) {
     return NGTCP2_ERR_INVALID_ARGUMENT;
   }
 
-  idx = hash(key, map->hashbits);
+  idx = map_hash(map, key);
   mask = (1u << map->hashbits) - 1;
 
   for (;;) {
index 9d882fb20088d8754da35d605f14ab908bcbdf21..0c1a76552aa4c4edee287cd85f7d51c635ffe564 100644 (file)
@@ -47,6 +47,7 @@ typedef struct ngtcp2_map_bucket {
 typedef struct ngtcp2_map {
   ngtcp2_map_bucket *table;
   const ngtcp2_mem *mem;
+  uint64_t seed;
   size_t size;
   size_t hashbits;
 } ngtcp2_map;
@@ -54,7 +55,7 @@ typedef struct ngtcp2_map {
 /*
  * ngtcp2_map_init initializes the map |map|.
  */
-void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem);
+void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem);
 
 /*
  * ngtcp2_map_free deallocates any resources allocated for |map|.  The
index 756076e7a7f258b53d5ecedd28e8a16be8fc633f..ec72708e0426e7e70acd024e509ab6356d011dcb 100644 (file)
    v2. */
 #define NGTCP2_PKT_TYPE_RETRY_V2 0x0
 
+/* NGTCP2_MIN_STREAM_DATALEN is the minimum length of STREAM frame to
+   avoid too small frame.  It is not always enforced for various
+   reasons.  For example, due to flow control, we might have fewer
+   bytes available to send.  Therefore, it is only applied when the
+   length of data to send is larger than this limit. */
+#define NGTCP2_MIN_STREAM_DATALEN 256
+
 typedef struct ngtcp2_pkt_retry {
   ngtcp2_cid odcid;
   uint8_t *token;
index d490524805b1e9c87cd9df17dd7069f72f37355c..73efb5255fcf44b95c0f645bccd30f8512701383 100644 (file)
@@ -110,7 +110,9 @@ void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len);
 void *ngtcp2_ringbuf_get(const ngtcp2_ringbuf *rb, size_t offset);
 
 /* ngtcp2_ringbuf_len returns the number of elements stored. */
-#define ngtcp2_ringbuf_len(RB) ((RB)->len)
+static inline size_t ngtcp2_ringbuf_len(const ngtcp2_ringbuf *rb) {
+  return rb->len;
+}
 
 /* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
 int ngtcp2_ringbuf_full(const ngtcp2_ringbuf *rb);
index 181691f3e69401e6929c4b3a7a7d17cd4842dc59..6f44c8ac8de673932560b89ccdde056a61c1d716 100644 (file)
@@ -38,7 +38,6 @@ void ngtcp2_rs_init(ngtcp2_rs *rs) {
   rs->prior_ts = UINT64_MAX;
   rs->tx_in_flight = 0;
   rs->lost = 0;
-  rs->prior_lost = 0;
   rs->send_elapsed = 0;
   rs->ack_elapsed = 0;
   rs->last_end_seq = -1;
@@ -58,7 +57,6 @@ void ngtcp2_rst_reset(ngtcp2_rst *rst) {
   rst->app_limited = 0;
   rst->is_cwnd_limited = 0;
   rst->lost = 0;
-  rst->valid_after_seq = rst->last_seq;
 }
 
 void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
@@ -89,7 +87,6 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
   rs->interval = ngtcp2_max_uint64(rs->send_elapsed, rs->ack_elapsed);
 
   rs->delivered = rst->delivered - rs->prior_delivered;
-  rs->lost = rst->lost - rs->prior_lost;
 
   if (rs->interval < cstat->min_rtt) {
     rs->interval = UINT64_MAX;
@@ -103,31 +100,23 @@ void ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
   cstat->delivery_rate_sec = rs->delivered * NGTCP2_SECONDS / rs->interval;
 }
 
-static int rst_is_newest_pkt(const ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
-                             const ngtcp2_rs *rs) {
-  return ent->ts > rst->first_sent_ts ||
-         (ent->ts == rst->first_sent_ts && ent->rst.end_seq > rs->last_end_seq);
+static int is_newest_pkt(const ngtcp2_rtb_entry *ent, const ngtcp2_rs *rs) {
+  return ent->rst.end_seq > rs->last_end_seq;
 }
 
 void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
                                    ngtcp2_tstamp ts) {
   ngtcp2_rs *rs = &rst->rs;
 
-  if (ent->rst.end_seq <= rst->valid_after_seq) {
-    return;
-  }
-
   rst->delivered += ent->pktlen;
   rst->delivered_ts = ts;
 
-  if (rs->prior_ts == UINT64_MAX || rst_is_newest_pkt(rst, ent, rs)) {
+  if (rs->prior_ts == UINT64_MAX || is_newest_pkt(ent, rs)) {
     rs->prior_delivered = ent->rst.delivered;
     rs->prior_ts = ent->rst.delivered_ts;
     rs->is_app_limited = ent->rst.is_app_limited;
     rs->send_elapsed = ent->ts - ent->rst.first_sent_ts;
     rs->ack_elapsed = rst->delivered_ts - ent->rst.delivered_ts;
-    rs->tx_in_flight = ent->rst.tx_in_flight;
-    rs->prior_lost = ent->rst.lost;
     rs->last_end_seq = ent->rst.end_seq;
     rst->first_sent_ts = ent->ts;
   }
index c2580306cc59fe13a969d7aaf668c50373e41caa..1bb624de79b53f885fee71ee5a78bdd15b58e387 100644 (file)
@@ -48,7 +48,6 @@ typedef struct ngtcp2_rs {
   ngtcp2_tstamp prior_ts;
   uint64_t tx_in_flight;
   uint64_t lost;
-  uint64_t prior_lost;
   ngtcp2_duration send_elapsed;
   ngtcp2_duration ack_elapsed;
   int64_t last_end_seq;
@@ -73,10 +72,6 @@ typedef struct ngtcp2_rst {
      across all packet number spaces, we can replace this with a
      packet number. */
   int64_t last_seq;
-  /* valid_after_seq is the sequence number, and ignore a packet if
-     the sequence number of the packet is less than or equal to this
-     number. */
-  int64_t valid_after_seq;
   int is_cwnd_limited;
 } ngtcp2_rst;
 
index 101dcaa99f8c4b169b624a5a9cccecd432426563..b50f482bc7e8c0d17591adf532771bc292e84eea 100644 (file)
@@ -43,16 +43,19 @@ ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent)
 static void rtb_entry_init(ngtcp2_rtb_entry *ent, const ngtcp2_pkt_hd *hd,
                            ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
                            size_t pktlen, uint16_t flags) {
-  memset(ent, 0, sizeof(*ent));
-
-  ent->hd.pkt_num = hd->pkt_num;
-  ent->hd.type = hd->type;
-  ent->hd.flags = hd->flags;
-  ent->frc = frc;
-  ent->ts = ts;
-  ent->lost_ts = UINT64_MAX;
-  ent->pktlen = pktlen;
-  ent->flags = flags;
+  *ent = (ngtcp2_rtb_entry){
+    .hd =
+      {
+        .pkt_num = hd->pkt_num,
+        .type = hd->type,
+        .flags = hd->flags,
+      },
+    .frc = frc,
+    .ts = ts,
+    .lost_ts = UINT64_MAX,
+    .pktlen = pktlen,
+    .flags = flags,
+  };
 }
 
 int ngtcp2_rtb_entry_objalloc_new(ngtcp2_rtb_entry **pent,
@@ -451,13 +454,17 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
   if (ent->flags &
       (NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE | NGTCP2_RTB_ENTRY_FLAG_SKIP)) {
     ++rtb->num_lost_ignore_pkts;
-  } else if (rtb->cc->on_pkt_lost) {
-    cc->on_pkt_lost(cc, cstat,
-                    ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
-                                       pktns->id, ent->ts, ent->rst.lost,
-                                       ent->rst.tx_in_flight,
-                                       ent->rst.is_app_limited),
-                    ts);
+  } else if (ent->hd.pkt_num >= rtb->cc_pkt_num) {
+    rtb->rst->lost += ent->pktlen;
+
+    if (rtb->cc->on_pkt_lost) {
+      cc->on_pkt_lost(cc, cstat,
+                      ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen,
+                                         pktns->id, ent->ts, ent->rst.lost,
+                                         ent->rst.tx_in_flight,
+                                         ent->rst.is_app_limited),
+                      ts);
+    }
   }
 
   if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED) {
@@ -704,6 +711,8 @@ static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
   ngtcp2_cc *cc = rtb->cc;
   ngtcp2_cc_pkt pkt;
 
+  assert(ent->hd.pkt_num >= rtb->cc_pkt_num);
+
   ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts);
 
   if (cc->on_pkt_acked) {
@@ -843,7 +852,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
     }
 
     rtb_remove(rtb, &it, &acked_ent, ent, cstat);
-    ++num_acked;
   }
 
   for (i = 0; i < fr->rangecnt; ++i) {
@@ -873,7 +881,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
       }
 
       rtb_remove(rtb, &it, &acked_ent, ent, cstat);
-      ++num_acked;
     }
   }
 
@@ -882,7 +889,8 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
       ngtcp2_max_uint64(pkt_ts - largest_pkt_sent_ts, NGTCP2_NANOSECONDS);
 
     rv = ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
-    if (rv == 0 && cc->new_rtt_sample) {
+    if (rv == 0 && cc->new_rtt_sample &&
+        rtb->largest_acked_tx_pkt_num >= rtb->cc_pkt_num) {
       cc->new_rtt_sample(cc, cstat, ts);
     }
   }
@@ -904,9 +912,12 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
 
         cc_ack.bytes_delivered += ent->pktlen;
         cc_ack.pkt_delivered = ent->rst.delivered;
+
+        rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
+
+        ++num_acked;
       }
 
-      rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
       acked_ent = ent->next;
       ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
                                     rtb->frc_objalloc, rtb->mem);
@@ -921,6 +932,7 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
     for (ent = acked_ent; ent; ent = acked_ent) {
       rtb_on_pkt_acked(rtb, ent, cstat, pktns, ts);
       acked_ent = ent->next;
+      ++num_acked;
       ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
                                     rtb->frc_objalloc, rtb->mem);
     }
@@ -942,8 +954,6 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
     }
   }
 
-  rtb->rst->lost += cc_ack.bytes_lost;
-
   cc_ack.largest_pkt_sent_ts = largest_pkt_sent_ts;
   if (num_acked && cc->on_ack_recv) {
     cc->on_ack_recv(cc, cstat, &cc_ack, ts);
index 8ea969c4addbdc0f3604c427eb2ac30070168def..70ec6ee2fe9ea73c33e4c0839dcd6fb999f6e4c2 100644 (file)
@@ -120,7 +120,7 @@ uint64_t ngtcp2_strm_rx_offset(const ngtcp2_strm *strm) {
 /* strm_rob_heavily_fragmented returns nonzero if the number of gaps
    in |rob| exceeds the limit. */
 static int strm_rob_heavily_fragmented(const ngtcp2_rob *rob) {
-  return ngtcp2_ksl_len(&rob->gapksl) >= 5000;
+  return ngtcp2_ksl_len(&rob->gapksl) >= 1000;
 }
 
 int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
@@ -138,11 +138,16 @@ int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
     }
   }
 
+  rv = ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
+  if (rv != 0) {
+    return rv;
+  }
+
   if (strm_rob_heavily_fragmented(strm->rx.rob)) {
     return NGTCP2_ERR_INTERNAL;
   }
 
-  return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
+  return 0;
 }
 
 void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) {
@@ -196,6 +201,8 @@ int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
     if (rv != 0) {
       return rv;
     }
+  } else if (ngtcp2_ksl_len(strm->tx.streamfrq) >= 1000) {
+    return NGTCP2_ERR_INTERNAL;
   }
 
   return ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
@@ -398,7 +405,11 @@ int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
   datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
 
   /* datalen could be zero if 0 length STREAM has been sent */
-  if (left == 0 && datalen) {
+  /* We might see more data in the queue, then left < datalen could be
+     true.  We only see the first one for now. */
+  if ((fr->type == NGTCP2_FRAME_STREAM &&
+       (left < datalen && left < NGTCP2_MIN_STREAM_DATALEN)) ||
+      (left == 0 && datalen)) {
     rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc);
     if (rv != 0) {
       assert(ngtcp2_err_is_fatal(rv));
@@ -737,7 +748,16 @@ int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len) {
     }
   }
 
-  return ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
+  rv = ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
+  if (rv != 0) {
+    return rv;
+  }
+
+  if (ngtcp2_ksl_len(&strm->tx.acked_offset->gap) >= 1000) {
+    return NGTCP2_ERR_INTERNAL;
+  }
+
+  return 0;
 }
 
 void ngtcp2_strm_set_app_error_code(ngtcp2_strm *strm,
index ca517532e3a695ef94f4afcebbdbc1f182f108cc..d652ece4e07a887e43755212d53a77d688a4ebfc 100644 (file)
@@ -523,12 +523,12 @@ int ngtcp2_transport_params_decode_versioned(int transport_params_version,
   }
 
   /* Set default values */
-  memset(params, 0, sizeof(*params));
-  params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE;
-  params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
-  params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
-  params->active_connection_id_limit =
-    NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
+  *params = (ngtcp2_transport_params){
+    .max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE,
+    .ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT,
+    .max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY,
+    .active_connection_id_limit = NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT,
+  };
 
   p = end = data;
 
index 55e735d164edcb951faa2d77d24ee9a2294fa388..d90a3204a9f2b471b95a9314d70b48967d966e29 100644 (file)
 
 #include "ngtcp2_mem.h"
 
-/*
- * ngtcp2_vec_lit is a convenient macro to fill the object pointed by
- * |DEST| with the literal string |LIT|.
- */
-#define ngtcp2_vec_lit(DEST, LIT)                                              \
-  ((DEST)->base = (uint8_t *)(LIT), (DEST)->len = sizeof(LIT) - 1, (DEST))
-
 /*
  * ngtcp2_vec_init initializes |vec| with the given parameters.  It
  * returns |vec|.
index d7a27b9213b0d584f2969090c81715d51d2ae871..b0cc867cde0b20111aef1d40dda9beb1758198be 100644 (file)
@@ -2971,6 +2971,28 @@ typedef int (*ngtcp2_update_key)(
  */
 #define NGTCP2_PATH_VALIDATION_FLAG_NEW_TOKEN 0x02u
 
+/**
+ * @functypedef
+ *
+ * :type:`ngtcp2_begin_path_validation` is a callback function which
+ * is called when the path validation has started.  |flags| is zero or
+ * more of :macro:`NGTCP2_PATH_VALIDATION_FLAG_*
+ * <NGTCP2_PATH_VALIDATION_FLAG_NONE>`.  |path| is the path that is
+ * being validated.  |fallback_path|, if not NULL, is the path that is
+ * used when this validation fails.
+ *
+ * Currently, the flags may only contain
+ * :macro:`NGTCP2_PATH_VALIDATION_FLAG_PREFERRED_ADDR`.
+ *
+ * The callback function must return 0 if it succeeds.  Returning
+ * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return
+ * immediately.
+ */
+typedef int (*ngtcp2_begin_path_validation)(ngtcp2_conn *conn, uint32_t flags,
+                                            const ngtcp2_path *path,
+                                            const ngtcp2_path *fallback_path,
+                                            void *user_data);
+
 /**
  * @functypedef
  *
@@ -3262,7 +3284,8 @@ typedef int (*ngtcp2_tls_early_data_rejected)(ngtcp2_conn *conn,
                                               void *user_data);
 
 #define NGTCP2_CALLBACKS_V1 1
-#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V1
+#define NGTCP2_CALLBACKS_V2 2
+#define NGTCP2_CALLBACKS_VERSION NGTCP2_CALLBACKS_V2
 
 /**
  * @struct
@@ -3527,6 +3550,13 @@ typedef struct ngtcp2_callbacks {
    * is only used by client.
    */
   ngtcp2_tls_early_data_rejected tls_early_data_rejected;
+  /* The following fields have been added since NGTCP2_CALLBACKS_V2. */
+  /**
+   * :member:`begin_path_validation` is a callback function which is
+   * invoked when a path validation has started.  This field is
+   * available since v1.14.0.
+   */
+  ngtcp2_begin_path_validation begin_path_validation;
 } ngtcp2_callbacks;
 
 /**
index 5a261a24308fc66c7218c431ab38edc888999cef..533f6d5ef6c55d1dd1372e3a062f9316e9e076de 100644 (file)
@@ -36,7 +36,7 @@
  *
  * Version number of the ngtcp2 library release.
  */
-#define NGTCP2_VERSION "1.13.0"
+#define NGTCP2_VERSION "1.14.0"
 
 /**
  * @macro
@@ -46,6 +46,6 @@
  * number, 8 bits for minor and 8 bits for patch. Version 1.2.3
  * becomes 0x010203.
  */
-#define NGTCP2_VERSION_NUM 0x010d00
+#define NGTCP2_VERSION_NUM 0x010e00
 
 #endif /* !defined(NGTCP2_VERSION_H) */