From: Daniel Salzman Date: Mon, 22 Aug 2022 10:42:48 +0000 (+0200) Subject: contrib: upgrade embedded library libngtcp2 to v0.8.0 X-Git-Tag: v3.4.dev~385^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d64d5951ccfc2bbac7515d19db1f993d8e8fdd58;p=thirdparty%2Fknot-dns.git contrib: upgrade embedded library libngtcp2 to v0.8.0 --- diff --git a/configure.ac b/configure.ac index fdc3294671..ff7273a0d5 100644 --- a/configure.ac +++ b/configure.ac @@ -556,12 +556,12 @@ AS_IF([test "$enable_daemon" = "yes" -o "$enable_utilities" = "yes"], [ # QUIC support AC_ARG_ENABLE([quic], - AS_HELP_STRING([--enable-quic=auto|yes|no], [Support DoQ (needs libngtcp2 = 0.7.0, gnutls >= 3.7.2) [default=auto]]), + AS_HELP_STRING([--enable-quic=auto|yes|no], [Support DoQ (needs libngtcp2 = 0.8.0, gnutls >= 3.7.2) [default=auto]]), [], [enable_quic=auto]) AS_CASE([$enable_quic], - [auto], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 = 0.7.0 libngtcp2_crypto_gnutls], [enable_quic=yes], [enable_quic=no])], - [yes], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 = 0.7.0 libngtcp2_crypto_gnutls], [enable_quic=yes], + [auto], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 = 0.8.0 libngtcp2_crypto_gnutls], [enable_quic=yes], [enable_quic=no])], + [yes], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 = 0.8.0 libngtcp2_crypto_gnutls], [enable_quic=yes], AS_IF([test "$gnutls_quic" = "yes"], [enable_quic=embedded embedded_libngtcp2_CFLAGS="-I\$(top_srcdir)/src/contrib/libngtcp2 -I\$(top_srcdir)/src/contrib/libngtcp2/ngtcp2/lib" diff --git a/doc/requirements.rst b/doc/requirements.rst index 08a9a19ff7..aca5a457b7 100644 --- a/doc/requirements.rst +++ b/doc/requirements.rst @@ -109,6 +109,6 @@ recommendations. DNS-over-QUIC (DoQ) support in :doc:`knotd`, :doc:`kxdpgun`, and :doc:`kdig`: -* libngtcp2 == 0.7.0 (or embedded one via `--enable-quic`) +* libngtcp2 == 0.8.0 (or embedded one via `--enable-quic`) * gnutls >= 3.7.2 * :ref:`Mode XDP` (for knotd and kxdpgun) diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c index 6d81c31111..a3135680ca 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c @@ -4448,7 +4448,7 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( if (((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) || padded) && (!path || ngtcp2_path_eq(&conn->dcid.current.ps.path, path))) { - if (pi) { + if (pi && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE)) { conn_handle_tx_ecn(conn, pi, &rtb_entry_flags, pktns, &hd, ts); } @@ -4479,7 +4479,8 @@ ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt( nwrite); } } - } else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) { + } else if (pi && !(rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) && + conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) { conn_handle_tx_ecn(conn, pi, NULL, pktns, &hd, ts); } @@ -4706,6 +4707,10 @@ static int conn_start_pmtud(ngtcp2_conn *conn) { return 0; } +int ngtcp2_conn_start_pmtud(ngtcp2_conn *conn) { + return conn_start_pmtud(conn); +} + void ngtcp2_conn_stop_pmtud(ngtcp2_conn *conn) { if (!conn->pmtud) { return; @@ -6868,7 +6873,7 @@ static int conn_emit_pending_stream_data(ngtcp2_conn *conn, ngtcp2_strm *strm, /* Stop calling callback if application has called ngtcp2_conn_shutdown_stream_read() inside the callback. Because it doubly counts connection window. */ - if (strm->flags & (NGTCP2_STRM_FLAG_STOP_SENDING)) { + if (strm->flags & NGTCP2_STRM_FLAG_STOP_SENDING) { return 0; } @@ -11131,7 +11136,14 @@ int ngtcp2_conn_set_remote_transport_params( ngtcp2_conn *conn, const ngtcp2_transport_params *params) { int rv; - assert(!(conn->flags & NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED)); + /* We expect this function is called once per QUIC connection, but + GnuTLS server seems to call TLS extension callback twice if it + sends HelloRetryRequest. In practice, same QUIC transport + parameters are sent in the 2nd client flight, just returning 0 + would cause no harm. */ + if (conn->flags & NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED) { + return 0; + } /* Assume that ngtcp2_decode_transport_params sets default value if active_connection_id_limit is omitted. */ @@ -11174,7 +11186,8 @@ int ngtcp2_conn_set_remote_transport_params( conn->negotiated_version; ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, - "the negotiated version is %08x", conn->negotiated_version); + "the negotiated version is 0x%08x", + conn->negotiated_version); } else { rv = conn_client_validate_transport_params(conn, params); if (rv != 0) { @@ -12271,6 +12284,8 @@ int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, */ static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm, uint64_t app_error_code) { + ngtcp2_strm_set_app_error_code(strm, app_error_code); + if ((strm->flags & NGTCP2_STRM_FLAG_SENT_RST) || ngtcp2_strm_is_all_tx_data_fin_acked(strm)) { return 0; @@ -12279,7 +12294,6 @@ static int conn_shutdown_stream_write(ngtcp2_conn *conn, ngtcp2_strm *strm, /* Set this flag so that we don't accidentally send DATA to this stream. */ strm->flags |= NGTCP2_STRM_FLAG_SHUT_WR | NGTCP2_STRM_FLAG_SENT_RST; - ngtcp2_strm_set_app_error_code(strm, app_error_code); ngtcp2_strm_streamfrq_clear(strm); @@ -12327,7 +12341,7 @@ int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, int64_t stream_id, strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { - return NGTCP2_ERR_STREAM_NOT_FOUND; + return 0; } rv = conn_shutdown_stream_read(conn, strm, app_error_code); @@ -12349,7 +12363,7 @@ int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, int64_t stream_id, strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { - return NGTCP2_ERR_STREAM_NOT_FOUND; + return 0; } return conn_shutdown_stream_write(conn, strm, app_error_code); @@ -12361,7 +12375,7 @@ int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, int64_t stream_id, strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { - return NGTCP2_ERR_STREAM_NOT_FOUND; + return 0; } return conn_shutdown_stream_read(conn, strm, app_error_code); @@ -12409,7 +12423,7 @@ int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, strm = ngtcp2_conn_find_stream(conn, stream_id); if (strm == NULL) { - return NGTCP2_ERR_STREAM_NOT_FOUND; + return 0; } return conn_extend_max_stream_offset(conn, strm, datalen); @@ -12539,9 +12553,8 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, &conn->log, NGTCP2_LOG_EVENT_RCV, "ignore rtt sample because ack_delay is too large latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " ack_delay=%" PRIu64, - (uint64_t)(rtt / NGTCP2_MILLISECONDS), - (uint64_t)(cstat->min_rtt / NGTCP2_MILLISECONDS), - (uint64_t)(ack_delay / NGTCP2_MILLISECONDS)); + rtt / NGTCP2_MILLISECONDS, cstat->min_rtt / NGTCP2_MILLISECONDS, + ack_delay / NGTCP2_MILLISECONDS); return NGTCP2_ERR_INVALID_ARGUMENT; } @@ -12559,15 +12572,14 @@ int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt, cstat->smoothed_rtt = (cstat->smoothed_rtt * 7 + rtt) / 8; } - ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, - "latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 - " smoothed_rtt=%" PRIu64 " rttvar=%" PRIu64 - " ack_delay=%" PRIu64, - (uint64_t)(cstat->latest_rtt / NGTCP2_MILLISECONDS), - (uint64_t)(cstat->min_rtt / NGTCP2_MILLISECONDS), - cstat->smoothed_rtt / NGTCP2_MILLISECONDS, - cstat->rttvar / NGTCP2_MILLISECONDS, - (uint64_t)(ack_delay / NGTCP2_MILLISECONDS)); + ngtcp2_log_info( + &conn->log, NGTCP2_LOG_EVENT_RCV, + "latest_rtt=%" PRIu64 " min_rtt=%" PRIu64 " smoothed_rtt=%" PRIu64 + " rttvar=%" PRIu64 " ack_delay=%" PRIu64, + cstat->latest_rtt / NGTCP2_MILLISECONDS, + cstat->min_rtt / NGTCP2_MILLISECONDS, + cstat->smoothed_rtt / NGTCP2_MILLISECONDS, + cstat->rttvar / NGTCP2_MILLISECONDS, ack_delay / NGTCP2_MILLISECONDS); return 0; } @@ -12580,52 +12592,44 @@ void ngtcp2_conn_get_conn_stat_versioned(ngtcp2_conn *conn, *cstat = conn->cstat; } -static ngtcp2_pktns *conn_get_earliest_pktns(ngtcp2_conn *conn, - ngtcp2_tstamp *pts, - const ngtcp2_tstamp *times) { - ngtcp2_pktns *ns[] = {conn->in_pktns, conn->hs_pktns, &conn->pktns}; - ngtcp2_pktns *res = NULL; +static void conn_get_loss_time_and_pktns(ngtcp2_conn *conn, + ngtcp2_tstamp *ploss_time, + ngtcp2_pktns **ppktns) { + ngtcp2_pktns *const ns[] = {conn->hs_pktns, &conn->pktns}; + ngtcp2_conn_stat *cstat = &conn->cstat; + ngtcp2_duration *loss_time = cstat->loss_time; + ngtcp2_tstamp earliest_loss_time = loss_time[NGTCP2_PKTNS_ID_INITIAL]; + ngtcp2_pktns *pktns = conn->in_pktns; size_t i; - ngtcp2_tstamp earliest_ts = UINT64_MAX; - for (i = NGTCP2_PKTNS_ID_INITIAL; i < NGTCP2_PKTNS_ID_MAX; ++i) { + for (i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) { if (ns[i] == NULL || ns[i]->rtb.num_pto_eliciting == 0 || - (times[i] == UINT64_MAX || - (earliest_ts != UINT64_MAX && times[i] >= earliest_ts) || - (i == NGTCP2_PKTNS_ID_APPLICATION && - !(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED)))) { + loss_time[i] >= earliest_loss_time) { continue; } - earliest_ts = times[i]; - res = ns[i]; + earliest_loss_time = loss_time[i]; + pktns = ns[i]; } - if (res == NULL && !conn->server) { - if (conn->hs_pktns && conn->hs_pktns->crypto.tx.ckm) { - res = conn->hs_pktns; - } else { - res = conn->in_pktns; - } + if (ploss_time) { + *ploss_time = earliest_loss_time; } - - if (pts) { - *pts = earliest_ts; + if (ppktns) { + *ppktns = pktns; } - return res; } static ngtcp2_tstamp conn_get_earliest_pto_expiry(ngtcp2_conn *conn, - const ngtcp2_tstamp *times, - size_t pto_count, ngtcp2_tstamp ts) { ngtcp2_pktns *ns[] = {conn->in_pktns, conn->hs_pktns, &conn->pktns}; size_t i; ngtcp2_tstamp earliest_ts = UINT64_MAX, t; ngtcp2_conn_stat *cstat = &conn->cstat; + ngtcp2_tstamp *times = cstat->last_tx_pkt_ts; ngtcp2_duration duration = compute_pto(cstat->smoothed_rtt, cstat->rttvar, /* max_ack_delay = */ 0) * - (1ULL << pto_count); + (1ULL << cstat->pto_count); for (i = NGTCP2_PKTNS_ID_INITIAL; i < NGTCP2_PKTNS_ID_MAX; ++i) { if (ns[i] == NULL || ns[i]->rtb.num_pto_eliciting == 0 || @@ -12639,7 +12643,8 @@ static ngtcp2_tstamp conn_get_earliest_pto_expiry(ngtcp2_conn *conn, if (i == NGTCP2_PKTNS_ID_APPLICATION) { assert(conn->remote.transport_params); - t += conn->remote.transport_params->max_ack_delay * (1ULL << pto_count); + t += conn->remote.transport_params->max_ack_delay * + (1ULL << cstat->pto_count); } if (t < earliest_ts) { @@ -12662,7 +12667,7 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_pktns *pktns = &conn->pktns; ngtcp2_tstamp earliest_loss_time; - conn_get_earliest_pktns(conn, &earliest_loss_time, cstat->loss_time); + conn_get_loss_time_and_pktns(conn, &earliest_loss_time, NULL); if (earliest_loss_time != UINT64_MAX) { cstat->loss_detection_timer = earliest_loss_time; @@ -12689,16 +12694,14 @@ void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return; } - cstat->loss_detection_timer = conn_get_earliest_pto_expiry( - conn, cstat->last_tx_pkt_ts, cstat->pto_count, ts); + cstat->loss_detection_timer = conn_get_earliest_pto_expiry(conn, ts); timeout = cstat->loss_detection_timer > ts ? cstat->loss_detection_timer - ts : 0; ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "loss_detection_timer=%" PRIu64 " timeout=%" PRIu64, - cstat->loss_detection_timer, - (uint64_t)(timeout / NGTCP2_MILLISECONDS)); + cstat->loss_detection_timer, timeout / NGTCP2_MILLISECONDS); } int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { @@ -12707,8 +12710,7 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { ngtcp2_pktns *in_pktns = conn->in_pktns; ngtcp2_pktns *hs_pktns = conn->hs_pktns; ngtcp2_tstamp earliest_loss_time; - ngtcp2_pktns *loss_pktns = - conn_get_earliest_pktns(conn, &earliest_loss_time, cstat->loss_time); + ngtcp2_pktns *loss_pktns = NULL; conn->log.last_ts = ts; conn->qlog.last_ts = ts; @@ -12727,10 +12729,14 @@ int ngtcp2_conn_on_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts) { return 0; } + conn_get_loss_time_and_pktns(conn, &earliest_loss_time, &loss_pktns); + ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_RCV, "loss detection timer fired"); if (earliest_loss_time != UINT64_MAX) { + assert(loss_pktns); + rv = ngtcp2_conn_detect_lost_pkt(conn, loss_pktns, cstat, ts); if (rv != 0) { return rv; @@ -13368,6 +13374,16 @@ void ngtcp2_conn_untrack_retired_dcid_seq(ngtcp2_conn *conn, uint64_t seq) { } } +size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, int64_t stream_id) { + ngtcp2_strm *strm = ngtcp2_conn_find_stream(conn, stream_id); + + if (strm == NULL) { + return 0; + } + + return strm->tx.loss_count; +} + void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent, const ngtcp2_path *path, const uint8_t *data) { diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h index 79bf44c9c4..b1c6564175 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h @@ -1087,6 +1087,8 @@ ngtcp2_ssize ngtcp2_conn_write_application_close_pkt( size_t destlen, uint64_t app_error_code, const uint8_t *reason, size_t reasonlen, ngtcp2_tstamp ts); +int ngtcp2_conn_start_pmtud(ngtcp2_conn *conn); + void ngtcp2_conn_stop_pmtud(ngtcp2_conn *conn); /** diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c index 2ec782b239..afc940139e 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c @@ -60,9 +60,7 @@ void ngtcp2_pkt_chain_del(ngtcp2_pkt_chain *pc, const ngtcp2_mem *mem) { ngtcp2_mem_free(mem, pc); } -int ngtcp2_pkt_decode_version_cid(uint32_t *pversion, const uint8_t **pdcid, - size_t *pdcidlen, const uint8_t **pscid, - size_t *pscidlen, const uint8_t *data, +int ngtcp2_pkt_decode_version_cid(ngtcp2_version_cid *dest, const uint8_t *data, size_t datalen, size_t short_dcidlen) { size_t len; uint32_t version; @@ -107,11 +105,11 @@ int ngtcp2_pkt_decode_version_cid(uint32_t *pversion, const uint8_t **pdcid, return NGTCP2_ERR_INVALID_ARGUMENT; } - *pversion = version; - *pdcid = &data[6]; - *pdcidlen = dcidlen; - *pscid = &data[6 + dcidlen + 1]; - *pscidlen = scidlen; + dest->version = version; + dest->dcid = &data[6]; + dest->dcidlen = dcidlen; + dest->scid = &data[6 + dcidlen + 1]; + dest->scidlen = scidlen; if (!version) { /* VN */ @@ -131,11 +129,11 @@ int ngtcp2_pkt_decode_version_cid(uint32_t *pversion, const uint8_t **pdcid, return NGTCP2_ERR_INVALID_ARGUMENT; } - *pversion = 0; - *pdcid = &data[1]; - *pdcidlen = short_dcidlen; - *pscid = NULL; - *pscidlen = 0; + dest->version = 0; + dest->dcid = &data[1]; + dest->dcidlen = short_dcidlen; + dest->scid = NULL; + dest->scidlen = 0; return 0; } @@ -2267,8 +2265,8 @@ ngtcp2_ssize ngtcp2_pkt_write_retry( /* Retry packet is sent at most once per one connection attempt. In the first connection attempt, client has to send random DCID - which is at least 8 bytes long. */ - if (odcid->datalen < 8) { + which is at least NGTCP2_MIN_INITIAL_DCIDLEN bytes long. */ + if (odcid->datalen < NGTCP2_MIN_INITIAL_DCIDLEN) { return NGTCP2_ERR_INVALID_ARGUMENT; } diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c index c2f97bf180..644071400a 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c @@ -319,6 +319,7 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, rtb->cc_bytes_in_flight = 0; rtb->persistent_congestion_start_ts = UINT64_MAX; rtb->num_lost_pkts = 0; + rtb->num_lost_pmtud_pkts = 0; } void ngtcp2_rtb_free(ngtcp2_rtb *rtb) { @@ -361,12 +362,18 @@ static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, } } -static void rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, - ngtcp2_conn_stat *cstat) { +static size_t rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, + ngtcp2_conn_stat *cstat) { if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) { assert(rtb->num_lost_pkts); --rtb->num_lost_pkts; - return; + + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { + assert(rtb->num_lost_pmtud_pkts); + --rtb->num_lost_pmtud_pkts; + } + + return 0; } if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) { @@ -391,16 +398,33 @@ static void rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, assert(rtb->cc_bytes_in_flight >= ent->pktlen); rtb->cc_bytes_in_flight -= ent->pktlen; + + /* If PMTUD packet is lost, we do not report the lost bytes to the + caller in order to ignore loss of PMTUD packet. */ + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { + return 0; + } + + return ent->pktlen; } + + return 0; } +/* NGTCP2_RECLAIM_FLAG_NONE indicates that no flag is set. */ +#define NGTCP2_RECLAIM_FLAG_NONE 0x00u +/* NGTCP2_RECLAIM_FLAG_ON_LOSS indicates that frames are reclaimed + because of the packet loss.*/ +#define NGTCP2_RECLAIM_FLAG_ON_LOSS 0x01u + /* * rtb_reclaim_frame queues unacknowledged frames included in |ent| * for retransmission. The re-queued frames are not deleted from - * |ent|. It returns the number of frames queued. + * |ent|. It returns the number of frames queued. |flags| is bitwise + * OR of 0 or more of NGTCP2_RECLAIM_FLAG_*. */ -static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, ngtcp2_conn *conn, - ngtcp2_pktns *pktns, +static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, uint8_t flags, + ngtcp2_conn *conn, ngtcp2_pktns *pktns, ngtcp2_rtb_entry *ent) { ngtcp2_frame_chain *frc, *nfrc, **pfrc = &pktns->tx.frq; ngtcp2_frame *fr; @@ -447,6 +471,12 @@ static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, ngtcp2_conn *conn, } } + if ((flags & NGTCP2_RECLAIM_FLAG_ON_LOSS) && + ent->hd.pkt_num != strm->tx.last_lost_pkt_num) { + strm->tx.last_lost_pkt_num = ent->hd.pkt_num; + ++strm->tx.loss_count; + } + rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new( &nfrc, fr->stream.datacnt, rtb->frc_objalloc, rtb->mem); if (rv != 0) { @@ -596,7 +626,9 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it, ngtcp2_qlog_pkt_lost(rtb->qlog, ent); } - if (rtb->cc->on_pkt_lost) { + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { + ++rtb->num_lost_pmtud_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, rtb->pktns_id, ent->ts, ent->rst.lost, @@ -635,7 +667,8 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it, assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)); assert(UINT64_MAX == ent->lost_ts); - reclaimed = rtb_reclaim_frame(rtb, conn, pktns, ent); + reclaimed = + rtb_reclaim_frame(rtb, NGTCP2_RECLAIM_FLAG_ON_LOSS, conn, pktns, ent); if (reclaimed < 0) { return (int)reclaimed; } @@ -929,7 +962,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; + size_t num_lost_pkts = rtb->num_lost_pkts - rtb->num_lost_pmtud_pkts; cc_ack.prior_bytes_in_flight = cstat->bytes_in_flight; cc_ack.rtt = UINT64_MAX; @@ -1065,7 +1098,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 == 0) { + rtb->num_lost_pkts - rtb->num_lost_pmtud_pkts == 0) { rtb->cc->on_spurious_congestion(cc, cstat, ts); } @@ -1096,11 +1129,11 @@ fail: } static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, - const ngtcp2_rtb_entry *ent, uint64_t loss_delay, - ngtcp2_tstamp lost_send_time, size_t pkt_thres) { + const ngtcp2_rtb_entry *ent, ngtcp2_duration loss_delay, + size_t pkt_thres, ngtcp2_tstamp ts) { ngtcp2_tstamp loss_time; - if (ent->ts <= lost_send_time || + if (ent->ts + loss_delay <= ts || rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + (int64_t)pkt_thres) { return 1; } @@ -1149,7 +1182,6 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { ngtcp2_rtb_entry *ent; ngtcp2_duration loss_delay; - ngtcp2_tstamp lost_send_time; ngtcp2_ksl_it it; ngtcp2_tstamp latest_ts, oldest_ts; int64_t last_lost_pkt_num; @@ -1161,14 +1193,13 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, size_t ecn_pkt_lost = 0; ngtcp2_tstamp start_ts; ngtcp2_duration pto = ngtcp2_conn_compute_pto(conn, pktns); - uint64_t prior_bytes_in_flight = cstat->bytes_in_flight; + uint64_t bytes_lost = 0; ngtcp2_duration max_ack_delay; pkt_thres = ngtcp2_max(pkt_thres, NGTCP2_PKT_THRESHOLD); pkt_thres = ngtcp2_min(pkt_thres, 256); cstat->loss_time[rtb->pktns_id] = UINT64_MAX; loss_delay = compute_pkt_loss_delay(cstat); - lost_send_time = ts - loss_delay; it = ngtcp2_ksl_lower_bound(&rtb->ents, &rtb->largest_acked_tx_pkt_num); for (; !ngtcp2_ksl_it_end(&it); ngtcp2_ksl_it_next(&it)) { @@ -1178,8 +1209,7 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, break; } - if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, lost_send_time, - (size_t)pkt_thres)) { + if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, (size_t)pkt_thres, ts)) { /* All entries from ent are considered to be lost. */ latest_ts = oldest_ts = ent->ts; last_lost_pkt_num = ent->hd.pkt_num; @@ -1220,13 +1250,19 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, ++ecn_pkt_lost; } - rtb_on_remove(rtb, ent, cstat); + bytes_lost += rtb_on_remove(rtb, ent, cstat); rv = rtb_on_pkt_lost(rtb, &it, ent, cstat, conn, pktns, ts); if (rv != 0) { return rv; } } + /* If only PMTUD packets are lost, do not trigger congestion + event. */ + if (bytes_lost == 0) { + break; + } + switch (conn->tx.ecn.state) { case NGTCP2_ECN_STATE_TESTING: if (conn->tx.ecn.validation_start_ts == UINT64_MAX) { @@ -1287,9 +1323,7 @@ static int rtb_detect_lost_pkt(ngtcp2_rtb *rtb, uint64_t *ppkt_lost, ngtcp2_rtb_remove_excessive_lost_pkt(rtb, (size_t)pkt_thres); if (ppkt_lost) { - assert(prior_bytes_in_flight >= cstat->bytes_in_flight); - - *ppkt_lost = prior_bytes_in_flight - cstat->bytes_in_flight; + *ppkt_lost = bytes_lost; } return 0; @@ -1319,6 +1353,11 @@ void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) { "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); --rtb->num_lost_pkts; + + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { + --rtb->num_lost_pmtud_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, @@ -1354,6 +1393,11 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); --rtb->num_lost_pkts; + + if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE) { + --rtb->num_lost_pmtud_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, @@ -1419,6 +1463,10 @@ static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, 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_RCV, "pkn=%" PRId64 " was declared lost and has already been retransmitted", @@ -1596,7 +1644,8 @@ ngtcp2_ssize ngtcp2_rtb_reclaim_on_pto(ngtcp2_rtb *rtb, ngtcp2_conn *conn, assert(ent->frc); - reclaimed = rtb_reclaim_frame(rtb, conn, pktns, ent); + reclaimed = + rtb_reclaim_frame(rtb, NGTCP2_RECLAIM_FLAG_NONE, conn, pktns, ent); if (reclaimed < 0) { return reclaimed; } diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h index 895092ac33..a97805dbaf 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h @@ -336,6 +336,10 @@ 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; } ngtcp2_rtb; /* diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c index deca1a86b1..6f20e866ad 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c @@ -47,6 +47,8 @@ void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags, strm->tx.offset = 0; strm->tx.max_offset = max_tx_offset; strm->tx.last_max_stream_data_ts = UINT64_MAX; + strm->tx.loss_count = 0; + strm->tx.last_lost_pkt_num = -1; strm->rx.rob = NULL; strm->rx.cont_offset = 0; strm->rx.last_offset = 0; diff --git a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.h b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.h index d4dc1b2b4c..8e3cfe8354 100644 --- a/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.h +++ b/src/contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.h @@ -111,6 +111,18 @@ struct ngtcp2_strm { /* last_max_stream_data_ts is the timestamp when last MAX_STREAM_DATA frame is sent. */ ngtcp2_tstamp last_max_stream_data_ts; + /* loss_count is the number of packets that contain STREAM + frame for this stream and are declared to be lost. It may + include the spurious losses. It does not include a packet + whose contents have been reclaimed for PTO and which is + later declared to be lost. Those data are not blocked by + the flow control and will be sent immediately if no other + restrictions are applied. */ + size_t loss_count; + /* last_lost_pkt_num is the packet number of the packet that + is counted to loss_count. It is used to avoid to count + multiple STREAM frames in one lost packet. */ + int64_t last_lost_pkt_num; } tx; struct { diff --git a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h index afac27893a..ed71cb3ea0 100644 --- a/src/contrib/libngtcp2/ngtcp2/ngtcp2.h +++ b/src/contrib/libngtcp2/ngtcp2/ngtcp2.h @@ -225,7 +225,7 @@ typedef struct ngtcp2_mem { * * :macro:`NGTCP2_SECONDS` is a count of tick which corresponds to 1 second. */ -#define NGTCP2_SECONDS ((uint64_t)1000000000ULL) +#define NGTCP2_SECONDS ((ngtcp2_duration)1000000000ULL) /** * @macro @@ -233,7 +233,7 @@ typedef struct ngtcp2_mem { * :macro:`NGTCP2_MILLISECONDS` is a count of tick which corresponds * to 1 millisecond. */ -#define NGTCP2_MILLISECONDS ((uint64_t)1000000ULL) +#define NGTCP2_MILLISECONDS ((ngtcp2_duration)1000000ULL) /** * @macro @@ -241,7 +241,7 @@ typedef struct ngtcp2_mem { * :macro:`NGTCP2_MICROSECONDS` is a count of tick which corresponds * to 1 microsecond. */ -#define NGTCP2_MICROSECONDS ((uint64_t)1000ULL) +#define NGTCP2_MICROSECONDS ((ngtcp2_duration)1000ULL) /** * @macro @@ -249,7 +249,7 @@ typedef struct ngtcp2_mem { * :macro:`NGTCP2_NANOSECONDS` is a count of tick which corresponds to * 1 nanosecond. */ -#define NGTCP2_NANOSECONDS ((uint64_t)1ULL) +#define NGTCP2_NANOSECONDS ((ngtcp2_duration)1ULL) /** * @macrosection @@ -850,7 +850,7 @@ typedef struct NGTCP2_ALIGN(8) ngtcp2_pkt_info { /** * @macro * - * :macro:`NGTCP2_PKT_FLAG_LONG_FORM` indicates the Long packet + * :macro:`NGTCP2_PKT_FLAG_LONG_FORM` indicates the Long header packet * header. */ #define NGTCP2_PKT_FLAG_LONG_FORM 0x01u @@ -2287,6 +2287,37 @@ NGTCP2_EXTERN int ngtcp2_decode_transport_params_new( NGTCP2_EXTERN void ngtcp2_transport_params_del(ngtcp2_transport_params *params, const ngtcp2_mem *mem); +/** + * @struct + * + * :type:`ngtcp2_version_cid` is a convenient struct to store the + * result of `ngtcp2_pkt_decode_version_cid`. + */ +typedef struct ngtcp2_version_cid { + /** + * :member:`version` stores QUIC version. + */ + uint32_t version; + /** + * :member:`dcid` points to the Destination Connection ID. + */ + const uint8_t *dcid; + /** + * :member:`dcidlen` is the length of the Destination Connection ID + * pointed by :member:`dcid`. + */ + size_t dcidlen; + /** + * :member:`scid` points to the Source Connection ID. + */ + const uint8_t *scid; + /** + * :member:`scidlen` is the length of the Source Connection ID + * pointed by :member:`scid`. + */ + size_t scidlen; +} ngtcp2_version_cid; + /** * @function * @@ -2299,25 +2330,31 @@ NGTCP2_EXTERN void ngtcp2_transport_params_del(ngtcp2_transport_params *params, * Longer Connection ID is only valid if the version is unsupported * QUIC version. * - * If the given packet is Long packet, this function extracts the - * version from the packet and assigns it to |*pversion|. It also + * If the given packet is Long header packet, this function extracts + * the version from the packet and assigns it to + * :member:`dest->version `. It also * extracts the pointer to the Destination Connection ID and its - * length and assigns them to |*pdcid| and |*pdcidlen| respectively. - * Similarly, it extracts the pointer to the Source Connection ID and - * its length and assigns them to |*pscid| and |*pscidlen| - * respectively. - * - * If the given packet is Short packet, |*pversion| will be 0, - * |*pscid| will be ``NULL``, and |*pscidlen| will be 0. Because the - * Short packet does not have the length of Destination Connection ID, - * the caller has to pass the length in |short_dcidlen|. This - * function extracts the pointer to the Destination Connection ID and - * assigns it to |*pdcid|. |short_dcidlen| is assigned to - * |*pdcidlen|. + * length and assigns them to :member:`dest->dcid + * ` and :member:`dest->dcidlen + * ` respectively. Similarly, it extracts + * the pointer to the Source Connection ID and its length and assigns + * them to :member:`dest->scid ` and + * :member:`dest->scidlen ` respectively. + * + * If the given packet is Short header packet, :member:`dest->version + * ` will be 0, :member:`dest->scid + * ` will be ``NULL``, and + * :member:`dest->scidlen ` will be 0. + * Because the Short header packet does not have the length of + * Destination Connection ID, the caller has to pass the length in + * |short_dcidlen|. This function extracts the pointer to the + * Destination Connection ID and assigns it to :member:`dest->dcid + * `. |short_dcidlen| is assigned to + * :member:`dest->dcidlen `. * * If Version Negotiation is required, this function returns * :macro:`NGTCP2_ERR_VERSION_NEGOTIATION`. Unlike the other error - * cases, all output parameters are assigned as described above. + * cases, all fields of |dest| are assigned as described above. * * This function returns 0 if it succeeds. Otherwise, one of the * following negative error code: @@ -2327,11 +2364,10 @@ NGTCP2_EXTERN void ngtcp2_transport_params_del(ngtcp2_transport_params *params, * :macro:`NGTCP2_ERR_VERSION_NEGOTIATION` * Version Negotiation packet should be sent. */ -NGTCP2_EXTERN int -ngtcp2_pkt_decode_version_cid(uint32_t *pversion, const uint8_t **pdcid, - size_t *pdcidlen, const uint8_t **pscid, - size_t *pscidlen, const uint8_t *data, - size_t datalen, size_t short_dcidlen); +NGTCP2_EXTERN int ngtcp2_pkt_decode_version_cid(ngtcp2_version_cid *dest, + const uint8_t *data, + size_t datalen, + size_t short_dcidlen); /** * @function @@ -2372,12 +2408,12 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_decode_hd_long(ngtcp2_pkt_hd *dest, /** * @function * - * `ngtcp2_pkt_decode_hd_short` decodes QUIC short packet header in - * |pkt| of length |pktlen|. |dcidlen| is the length of DCID in - * packet header. Short packet does not encode the length of - * connection ID, thus we need the input from the outside. This - * function only parses the input just before packet number field. - * This function can handle Connection ID up to + * `ngtcp2_pkt_decode_hd_short` decodes QUIC short header packet + * header in |pkt| of length |pktlen|. |dcidlen| is the length of + * DCID in packet header. Short header packet does not encode the + * length of connection ID, thus we need the input from the outside. + * This function only parses the input just before packet number + * field. This function can handle Connection ID up to * :macro:`NGTCP2_MAX_CIDLEN`. Consider to use * `ngtcp2_pkt_decode_version_cid` to get longer Connection ID. It * stores the result in the object pointed by |dest|, and returns the @@ -2468,9 +2504,6 @@ typedef struct ngtcp2_conn ngtcp2_conn; * This callback function must return 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the library call * return immediately. - * - * TODO: Define error code for TLS stack failure. Suggestion: - * NGTCP2_ERR_CRYPTO. */ typedef int (*ngtcp2_client_initial)(ngtcp2_conn *conn, void *user_data); @@ -2488,9 +2521,6 @@ typedef int (*ngtcp2_client_initial)(ngtcp2_conn *conn, void *user_data); * The callback function must return 0 if it succeeds. If an error * occurs, return :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the * library call return immediately. - * - * TODO: Define error code for TLS stack failure. Suggestion: - * NGTCP2_ERR_CRYPTO. */ typedef int (*ngtcp2_recv_client_initial)(ngtcp2_conn *conn, const ngtcp2_cid *dcid, @@ -2612,15 +2642,15 @@ typedef int (*ngtcp2_recv_version_negotiation)(ngtcp2_conn *conn, * @functypedef * * :type:`ngtcp2_recv_retry` is invoked when Retry packet is received. - * This callback is client only. + * This callback is client use only. * * Application must regenerate packet protection key, IV, and header * protection key for Initial packets using the destination connection - * ID obtained by `ngtcp2_conn_get_dcid()` and install them by calling - * `ngtcp2_conn_install_initial_key()`. + * ID obtained by :member:`hd->scid ` and install + * them by calling `ngtcp2_conn_install_initial_key()`. * - * 0-RTT data accepted by the ngtcp2 library will be retransmitted by - * the library automatically. + * 0-RTT data accepted by the ngtcp2 library will be automatically + * retransmitted as 0-RTT data by the library. * * The callback function must return 0 if it succeeds. Returning * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` makes the library call return @@ -2643,7 +2673,7 @@ typedef int (*ngtcp2_recv_retry)(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd, * The implementation of this callback must encrypt |plaintext| using * the negotiated cipher suite and write the ciphertext into the * buffer pointed by |dest|. |dest| has enough capacity to store the - * ciphertext. + * ciphertext and any additional AEAD tag data. * * |dest| and |plaintext| may point to the same buffer. * @@ -2690,7 +2720,7 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * @functypedef * * :type:`ngtcp2_hp_mask` is invoked when the ngtcp2 library asks the - * application to produce mask to encrypt or decrypt packet header. + * application to produce a mask to encrypt or decrypt packet header. * The encryption cipher is |hp|. |hp_ctx| is the cipher context * object which is initialized with header protection key. The sample * is passed as |sample| which is :macro:`NGTCP2_HP_SAMPLELEN` bytes @@ -2699,10 +2729,11 @@ typedef int (*ngtcp2_decrypt)(uint8_t *dest, const ngtcp2_crypto_aead *aead, * The implementation of this callback must produce a mask using the * header protection cipher suite specified by QUIC specification and * write the result into the buffer pointed by |dest|. The length of - * mask must be at least :macro:`NGTCP2_HP_MASKLEN`. The library only - * uses the first :macro:`NGTCP2_HP_MASKLEN` bytes of the produced - * mask. The buffer pointed by |dest| is guaranteed to have at least - * :macro:`NGTCP2_HP_SAMPLELEN` bytes available for convenience. + * the mask must be at least :macro:`NGTCP2_HP_MASKLEN`. The library + * only uses the first :macro:`NGTCP2_HP_MASKLEN` bytes of the + * produced mask. The buffer pointed by |dest| is guaranteed to have + * at least :macro:`NGTCP2_HP_SAMPLELEN` bytes available for + * convenience. * * The callback function must return 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the library call @@ -2752,9 +2783,9 @@ typedef int (*ngtcp2_hp_mask)(uint8_t *dest, const ngtcp2_crypto_cipher *hp, * :macro:`NGTCP2_STREAM_DATA_FLAG_FIN` is nonzero, this portion of * the data is the last data in this stream. |offset| is the offset * where this data begins. The library ensures that data is passed to - * the application in the non-decreasing order of |offset|. The data - * is passed as |data| of length |datalen|. |datalen| may be 0 if and - * only if |fin| is nonzero. + * the application in the non-decreasing order of |offset| without any + * overlap. The data is passed as |data| of length |datalen|. + * |datalen| may be 0 if and only if |fin| is nonzero. * * If :macro:`NGTCP2_STREAM_DATA_FLAG_EARLY` is set in |flags|, it * indicates that a part of or whole data was received in 0RTT packet @@ -2855,10 +2886,10 @@ typedef int (*ngtcp2_stream_reset)(ngtcp2_conn *conn, int64_t stream_id, * which is called when stream data is acked, and application can free * the data. The acked range of data is [offset, offset + datalen). * For a given stream_id, this callback is called sequentially in - * increasing order of |offset|. |datalen| is normally strictly - * greater than 0. One exception is that when a packet which includes - * STREAM frame which has fin flag set, and 0 length data, this - * callback is invoked with 0 passed as |datalen|. + * increasing order of |offset| without any overlap. |datalen| is + * normally strictly greater than 0. One exception is that when a + * packet which includes STREAM frame which has fin flag set, and 0 + * length data, this callback is invoked with 0 passed as |datalen|. * * If a stream is closed prematurely and stream data is still * in-flight, this callback function is not called for those data. @@ -3211,7 +3242,8 @@ typedef int (*ngtcp2_ack_datagram)(ngtcp2_conn *conn, uint64_t dgram_id, * :type:`ngtcp2_lost_datagram` is invoked when a packet which * contains DATAGRAM frame which is identified by |dgram_id| is * declared lost. |dgram_id| is the valued passed to - * `ngtcp2_conn_writev_datagram`. + * `ngtcp2_conn_writev_datagram`. Note that the loss might be + * spurious, and DATAGRAM frame might be acknowledged later. * * The callback function must return 0 if it succeeds, or * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` which makes the library return @@ -3597,6 +3629,9 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_connection_close( * Buffer is too small. * :macro:`NGTCP2_ERR_CALLBACK_FAILURE` * Callback function failed. + * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` + * :member:`odcid->datalen ` is less than + * :macro:`NGTCP2_MIN_INITIAL_DCIDLEN`. */ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_retry( uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid, @@ -3622,7 +3657,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_pkt_write_retry( * Retry packet should be sent. * :macro:`NGTCP2_ERR_INVALID_ARGUMENT` * The packet is not acceptable for the very first packet to a new - * connection; or it failed to parse the packet header. + * connection; or the function failed to parse the packet header. */ NGTCP2_EXTERN int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, size_t pktlen); @@ -3633,7 +3668,7 @@ NGTCP2_EXTERN int ngtcp2_accept(ngtcp2_pkt_hd *dest, const uint8_t *pkt, * `ngtcp2_conn_client_new` creates new :type:`ngtcp2_conn`, and * initializes it as client. |dcid| is randomized destination * connection ID. |scid| is source connection ID. - * |client_chosen_version| is a QUIC version that a cilent chooses. + * |client_chosen_version| is a QUIC version that a client chooses. * |path| is the network path where this QUIC connection is being * established and must not be ``NULL``. |callbacks|, |settings|, and * |params| must not be ``NULL``, and the function make a copy of each @@ -3707,17 +3742,20 @@ NGTCP2_EXTERN void ngtcp2_conn_del(ngtcp2_conn *conn); * functions. * * This function returns 0 if it succeeds, or negative error codes. - * In general, if the error code which satisfies - * `ngtcp2_err_is_fatal(err) ` != 0 is returned, - * the application should just close the connection by calling - * `ngtcp2_conn_write_connection_close` or just delete the QUIC - * connection using `ngtcp2_conn_del`. It is undefined to call the - * other library functions. If :macro:`NGTCP2_ERR_RETRY` is returned, - * application must be a server and it must perform address validation - * by sending Retry packet and close the connection. If + * If :macro:`NGTCP2_ERR_RETRY` is returned, application must be a + * server and it must perform address validation by sending Retry + * packet and discard the connection state. If * :macro:`NGTCP2_ERR_DROP_CONN` is returned, server application must * drop the connection silently (without sending any CONNECTION_CLOSE - * frame) and discard connection state. + * frame) and discard connection state. If + * :macro:`NGTCP2_ERR_DRAINING` is returned, a connection has entered + * the draining state, and no further packet transmission is allowed. + * If :macro:`NGTCP2_ERR_CRYPTO` is returned, the error happened in + * TLS stack and `ngtcp2_conn_get_tls_alert` returns TLS alert if set. + * + * If any other negative errors are returned, call + * `ngtcp2_conn_write_connection_close` to get terminal packet, and + * sending it makes QUIC connection enter the closing state. */ NGTCP2_EXTERN int ngtcp2_conn_read_pkt_versioned(ngtcp2_conn *conn, const ngtcp2_path *path, @@ -3916,7 +3954,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_early_key( * @function * * `ngtcp2_conn_install_rx_key` installs packet protection keying - * materials for decrypting Short packets. |secret| of length + * materials for decrypting Short header packets. |secret| of length * |secretlen| is the decryption secret which is used to derive keying * materials passed to this function. |aead_ctx| is AEAD cipher * context object which must be initialized with a decryption key. @@ -3947,7 +3985,7 @@ NGTCP2_EXTERN int ngtcp2_conn_install_rx_key( * @function * * `ngtcp2_conn_install_tx_key` installs packet protection keying - * materials for encrypting Short packets. |secret| of length + * materials for encrypting Short header packets. |secret| of length * |secretlen| is the encryption secret which is used to derive keying * materials passed to this function. |aead_ctx| is AEAD cipher * context object which must be initialized with an encryption key. @@ -4256,8 +4294,6 @@ NGTCP2_EXTERN int ngtcp2_conn_open_uni_stream(ngtcp2_conn *conn, * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory - * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` - * Stream does not exist */ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, int64_t stream_id, @@ -4278,8 +4314,6 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream(ngtcp2_conn *conn, * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory - * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` - * Stream does not exist */ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, int64_t stream_id, @@ -4299,8 +4333,6 @@ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_write(ngtcp2_conn *conn, * * :macro:`NGTCP2_ERR_NOMEM` * Out of memory - * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` - * Stream does not exist */ NGTCP2_EXTERN int ngtcp2_conn_shutdown_stream_read(ngtcp2_conn *conn, int64_t stream_id, @@ -4602,7 +4634,7 @@ NGTCP2_EXTERN ngtcp2_ssize ngtcp2_conn_writev_datagram_versioned( * @function * * `ngtcp2_conn_is_in_closing_period` returns nonzero if |conn| is in - * closing period. + * the closing period. */ NGTCP2_EXTERN int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn); @@ -4610,7 +4642,7 @@ NGTCP2_EXTERN int ngtcp2_conn_is_in_closing_period(ngtcp2_conn *conn); * @function * * `ngtcp2_conn_is_in_draining_period` returns nonzero if |conn| is in - * draining period. + * the draining period. */ NGTCP2_EXTERN int ngtcp2_conn_is_in_draining_period(ngtcp2_conn *conn); @@ -4623,8 +4655,8 @@ NGTCP2_EXTERN int ngtcp2_conn_is_in_draining_period(ngtcp2_conn *conn); * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGTCP2_ERR_STREAM_NOT_FOUND` - * Stream was not found + * :macro:`NGTCP2_ERR_NOMEM` + * Out of memory. */ NGTCP2_EXTERN int ngtcp2_conn_extend_max_stream_offset(ngtcp2_conn *conn, int64_t stream_id, @@ -5378,6 +5410,18 @@ NGTCP2_EXTERN void ngtcp2_conn_update_pkt_tx_time(ngtcp2_conn *conn, */ NGTCP2_EXTERN size_t ngtcp2_conn_get_send_quantum(ngtcp2_conn *conn); +/** + * @function + * + * `ngtcp2_conn_get_stream_loss_count` returns the number of packets + * that contain STREAM frame for a stream identified by |stream_id| + * and are declared to be lost. The number may include the spurious + * losses. If no stream identified by |stream_id| is found, this + * function returns 0. + */ +NGTCP2_EXTERN size_t ngtcp2_conn_get_stream_loss_count(ngtcp2_conn *conn, + int64_t stream_id); + /** * @function * diff --git a/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h b/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h index 7ddba40d2a..4736b51c3c 100644 --- a/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h +++ b/src/contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h @@ -68,7 +68,7 @@ extern "C" { * `ngtcp2_crypto_ctx_tls` initializes |ctx| by extracting negotiated * ciphers and message digests from native TLS session * |tls_native_handle|. This is used for encrypting/decrypting - * Handshake and Short packets. + * Handshake and Short header packets. * * If libngtcp2_crypto_openssl is linked, |tls_native_handle| must be * a pointer to SSL object. diff --git a/src/contrib/libngtcp2/ngtcp2/version.h b/src/contrib/libngtcp2/ngtcp2/version.h index 0bde99d5b7..4172dd4346 100644 --- a/src/contrib/libngtcp2/ngtcp2/version.h +++ b/src/contrib/libngtcp2/ngtcp2/version.h @@ -36,7 +36,7 @@ * * Version number of the ngtcp2 library release. */ -#define NGTCP2_VERSION "0.7.0" +#define NGTCP2_VERSION "0.8.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 0x000700 +#define NGTCP2_VERSION_NUM 0x000800 #endif /* VERSION_H */