From a9cee2102ea5bfb5b2c50c35304333fb9fe4a3bf Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 13 Nov 2024 17:02:29 +0100 Subject: [PATCH 01/21] Move docs.rs metadata to the bottom --- quinn-proto/Cargo.toml | 6 +++--- quinn-udp/Cargo.toml | 6 +++--- quinn/Cargo.toml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index 617c41081..d2224cdda 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -10,9 +10,6 @@ keywords.workspace = true categories.workspace = true workspace = ".." -[package.metadata.docs.rs] -all-features = true - [features] default = ["rustls-ring", "log"] aws-lc-rs = ["dep:aws-lc-rs", "aws-lc-rs?/aws-lc-sys", "aws-lc-rs?/prebuilt-nasm"] @@ -66,3 +63,6 @@ wasm-bindgen-test = { workspace = true } [lints.rust] # https://rust-fuzz.github.io/book/cargo-fuzz/guide.html#cfgfuzzing unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } + +[package.metadata.docs.rs] +all-features = true diff --git a/quinn-udp/Cargo.toml b/quinn-udp/Cargo.toml index 795de3ef7..8d5f056ce 100644 --- a/quinn-udp/Cargo.toml +++ b/quinn-udp/Cargo.toml @@ -10,9 +10,6 @@ keywords.workspace = true categories.workspace = true workspace = ".." -[package.metadata.docs.rs] -all-features = true - [features] default = ["tracing", "log"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. @@ -45,3 +42,6 @@ bench = false [[bench]] name = "throughput" harness = false + +[package.metadata.docs.rs] +all-features = true diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 4b020a34e..33879db03 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -11,9 +11,6 @@ workspace = ".." edition.workspace = true rust-version.workspace = true -[package.metadata.docs.rs] -all-features = true - [features] default = ["log", "platform-verifier", "runtime-tokio", "rustls-ring"] # Enables `Endpoint::client` and `Endpoint::server` conveniences @@ -96,3 +93,6 @@ required-features = ["rustls-ring"] name = "bench" harness = false required-features = ["rustls-ring"] + +[package.metadata.docs.rs] +all-features = true From 37355ec5e7da09435e99d4a35df7ffd70d410061 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 13 Nov 2024 17:05:48 +0100 Subject: [PATCH 02/21] quinn: avoid FIPS in docs.rs builds --- quinn-proto/Cargo.toml | 3 ++- quinn/Cargo.toml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index d2224cdda..902b4a846 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -65,4 +65,5 @@ wasm-bindgen-test = { workspace = true } unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } [package.metadata.docs.rs] -all-features = true +# all non-default features except fips (cannot build on docs.rs environment) +features = ["rustls-aws-lc-rs", "rustls-ring", "platform-verifier", "log", "rustls-log"] diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 33879db03..7dfc4b033 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -95,4 +95,5 @@ harness = false required-features = ["rustls-ring"] [package.metadata.docs.rs] -all-features = true +# all non-default features except fips (cannot build on docs.rs environment) +features = ["lock_tracking", "rustls-aws-lc-rs", "rustls-ring", "runtime-tokio", "runtime-async-std", "runtime-smol", "log", "rustls-log"] From 7fa7dc220d90fa50ee0e73ae8971c99a7a3b95a4 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 13 Nov 2024 17:06:40 +0100 Subject: [PATCH 03/21] Bump versions to prepare release --- quinn-proto/Cargo.toml | 2 +- quinn/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index 902b4a846..8a91c14df 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quinn-proto" -version = "0.11.9" +version = "0.11.10" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 7dfc4b033..a061520d7 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quinn" -version = "0.11.6" +version = "0.11.7" license.workspace = true repository.workspace = true description = "Versatile QUIC transport protocol implementation" From a55c1141e96809a94fdafc131d51642c5444ed30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Kr=C3=BCger?= Date: Mon, 11 Nov 2024 09:27:45 +0100 Subject: [PATCH 04/21] chore(ci): Remove workaround for broken `cc` version --- .github/workflows/rust.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e9af88327..a2337566c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -121,11 +121,6 @@ jobs: - name: Install cargo binstall uses: cargo-bins/cargo-binstall@main - - # We need to downgrade cc to version 1.1.31 for ring Wasm compilation to work. - # See the upstream issue https://github.com/rust-lang/cc-rs/issues/1275 - - name: Use working `cc` version 1.1.31 - run: cargo update -p cc --precise 1.1.31 - name: build wasm32 tests (quinn-proto) run: cargo test -p quinn-proto --target wasm32-unknown-unknown --no-run From 2cd3b14216bcc77afc36f6132e694809626c4a12 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Wed, 13 Nov 2024 10:33:18 +0000 Subject: [PATCH 05/21] Add Solaris CI, plus disable failing Solaris tests for now (#1877) --- .github/workflows/rust.yml | 22 ++++++++++++++++++++++ quinn/src/tests.rs | 6 ++++++ 2 files changed, 28 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a2337566c..9da7d2143 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -60,6 +60,28 @@ jobs: cargo build --all-targets && cargo test && cargo test --manifest-path fuzz/Cargo.toml && cargo test -p quinn-udp --benches + test-solaris: + name: test on solaris + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: test on Solaris + uses: vmactions/solaris-vm@v1 + with: + release: "11.4-gcc" + usesh: true + mem: 4096 + copyback: false + prepare: | + source <(curl -s https://raw.githubusercontent.com/psumbera/solaris-rust/refs/heads/main/sh.rust-web-install) + echo "~~~~ rustc --version ~~~~" + rustc --version + echo "~~~~ Solaris-version ~~~~" + uname -a + run: | + export PATH=$HOME/.rust_solaris/bin:$PATH + cargo build --all-targets && cargo test && cargo test --manifest-path fuzz/Cargo.toml && cargo test -p quinn-udp --benches + test: strategy: matrix: diff --git a/quinn/src/tests.rs b/quinn/src/tests.rs index 021a1a650..ea5a65713 100755 --- a/quinn/src/tests.rs +++ b/quinn/src/tests.rs @@ -387,6 +387,7 @@ async fn zero_rtt() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "Fails on Solaris")] fn echo_v6() { run_echo(EchoArgs { client_addr: SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0), @@ -399,6 +400,7 @@ fn echo_v6() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "Sometimes hangs in poll() on Solaris")] fn echo_v4() { run_echo(EchoArgs { client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0), @@ -411,6 +413,7 @@ fn echo_v4() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "Hangs in poll() on Solaris")] fn echo_dualstack() { run_echo(EchoArgs { client_addr: SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0), @@ -423,6 +426,7 @@ fn echo_dualstack() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "Hangs in poll() on Solaris")] fn stress_receive_window() { run_echo(EchoArgs { client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0), @@ -435,6 +439,7 @@ fn stress_receive_window() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "Hangs in poll() on Solaris")] fn stress_stream_receive_window() { // Note that there is no point in running this with too many streams, // since the window is only active within a stream. @@ -449,6 +454,7 @@ fn stress_stream_receive_window() { } #[test] +#[cfg_attr(target_os = "solaris", ignore = "Hangs in poll() on Solaris")] fn stress_both_windows() { run_echo(EchoArgs { client_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0), From 83e74fe3edcaaece3bde18703ded8809ebecfa01 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sat, 16 Nov 2024 13:17:24 -0800 Subject: [PATCH 06/21] Account for probe size limits before coalescing When a datagram is a loss probe, it must be at most 1200 bytes. This limit must be accounted for before we judge whether there's enough space to coalesce another packet. --- quinn-proto/src/connection/mod.rs | 26 +++++++++++++++++--- quinn-proto/src/connection/packet_builder.rs | 13 ++-------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 6986d6314..d6368ca1b 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -32,7 +32,7 @@ use crate::{ token::ResetToken, transport_parameters::TransportParameters, Dir, Duration, EndpointConfig, Frame, Instant, Side, StreamId, Transmit, TransportError, - TransportErrorCode, VarInt, MAX_CID_SIZE, MAX_STREAM_COUNT, MIN_INITIAL_SIZE, + TransportErrorCode, VarInt, INITIAL_MTU, MAX_CID_SIZE, MAX_STREAM_COUNT, MIN_INITIAL_SIZE, TIMER_GRANULARITY, }; @@ -692,13 +692,21 @@ impl Connection { // waste large amounts of bandwidth. The exact threshold is a bit arbitrary // and might benefit from further tuning, though there's no universally // optimal value. + // + // Additionally, if this datagram is a loss probe and `segment_size` is + // larger than `INITIAL_MTU`, then padding it to `segment_size` to continue + // the GSO batch would risk failure to recover from a reduction in path + // MTU. Loss probes are the only packets for which we might grow + // `buf_capacity` by less than `segment_size`. const MAX_PADDING: usize = 16; let packet_len_unpadded = cmp::max(builder.min_size, buf.len()) - datagram_start + builder.tag_len; - if packet_len_unpadded + MAX_PADDING < segment_size { + if packet_len_unpadded + MAX_PADDING < segment_size + || datagram_start + segment_size > buf_capacity + { trace!( - "GSO truncated by demand for {} padding bytes", + "GSO truncated by demand for {} padding bytes or loss probe", segment_size - packet_len_unpadded ); builder_storage = Some(builder); @@ -741,7 +749,17 @@ impl Connection { } // Allocate space for another datagram - buf_capacity += segment_size; + let next_datagram_size_limit = match self.spaces[space_id].loss_probes { + 0 => segment_size, + _ => { + self.spaces[space_id].loss_probes -= 1; + // Clamp the datagram to at most the minimum MTU to ensure that loss probes + // can get through and enable recovery even if the path MTU has shrank + // unexpectedly. + usize::from(INITIAL_MTU) + } + }; + buf_capacity += next_datagram_size_limit; if buf.capacity() < buf_capacity { // We reserve the maximum space for sending `max_datagrams` upfront // to avoid any reallocations if more datagrams have to be appended later on. diff --git a/quinn-proto/src/connection/packet_builder.rs b/quinn-proto/src/connection/packet_builder.rs index bc1cd7ffd..868a8c7ca 100644 --- a/quinn-proto/src/connection/packet_builder.rs +++ b/quinn-proto/src/connection/packet_builder.rs @@ -1,5 +1,3 @@ -use std::cmp; - use bytes::Bytes; use rand::Rng; use tracing::{trace, trace_span}; @@ -8,7 +6,7 @@ use super::{spaces::SentPacket, Connection, SentFrames}; use crate::{ frame::{self, Close}, packet::{Header, InitialHeader, LongType, PacketNumber, PartialEncode, SpaceId, FIXED_BIT}, - ConnectionId, Instant, TransportError, TransportErrorCode, INITIAL_MTU, + ConnectionId, Instant, TransportError, TransportErrorCode, }; pub(super) struct PacketBuilder { @@ -38,7 +36,7 @@ impl PacketBuilder { space_id: SpaceId, dst_cid: ConnectionId, buffer: &mut Vec, - mut buffer_capacity: usize, + buffer_capacity: usize, datagram_start: usize, ack_eliciting: bool, conn: &mut Connection, @@ -79,13 +77,6 @@ impl PacketBuilder { } let space = &mut conn.spaces[space_id]; - - if space.loss_probes != 0 { - space.loss_probes -= 1; - // Clamp the packet size to at most the minimum MTU to ensure that loss probes can get - // through and enable recovery even if the path MTU has shrank unexpectedly. - buffer_capacity = cmp::min(buffer_capacity, datagram_start + usize::from(INITIAL_MTU)); - } let exact_number = match space_id { SpaceId::Data => conn.packet_number_filter.allocate(&mut conn.rng, space), _ => space.get_tx_number(), From 5619b152bcb3f10d0eeaec75b4a80cd986a852b3 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sat, 16 Nov 2024 13:24:00 -0800 Subject: [PATCH 07/21] Fix typo --- quinn-proto/src/connection/spaces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quinn-proto/src/connection/spaces.rs b/quinn-proto/src/connection/spaces.rs index a04fbd3d7..a97eea24b 100644 --- a/quinn-proto/src/connection/spaces.rs +++ b/quinn-proto/src/connection/spaces.rs @@ -104,7 +104,7 @@ impl PacketSpace { /// Queue data for a tail loss probe (or anti-amplification deadlock prevention) packet /// - /// Probes are sent similarly to normal packets when an expect ACK has not arrived. We never + /// Probes are sent similarly to normal packets when an expected ACK has not arrived. We never /// deem a packet lost until we receive an ACK that should have included it, but if a trailing /// run of packets (or their ACKs) are lost, this might not happen in a timely fashion. We send /// probe packets to force an ACK, and exempt them from congestion control to prevent a deadlock From b1bd28e9d4cd0124e3355ce106df85a74e8a0b61 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sat, 16 Nov 2024 13:59:42 -0800 Subject: [PATCH 08/21] Don't advertise fake GSO outside of apple_fast --- quinn-udp/src/unix.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index b8ff6e592..0432134a0 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -804,7 +804,14 @@ mod gso { use super::*; pub(super) fn max_gso_segments() -> usize { - BATCH_SIZE + #[cfg(apple_fast)] + { + BATCH_SIZE + } + #[cfg(not(apple_fast))] + { + 1 + } } pub(super) fn set_segment_size( From 46acdea438ad6f32f965cb84a93aa7f49f1d0e06 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sat, 16 Nov 2024 14:00:47 -0800 Subject: [PATCH 09/21] Enable GSO on Android --- quinn-udp/src/unix.rs | 16 +++++++++++----- quinn-udp/tests/tests.rs | 5 ++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index 0432134a0..15ce2a4b3 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -318,7 +318,7 @@ fn send( // Some network adapters and drivers do not support GSO. Unfortunately, Linux // offers no easy way for us to detect this short of an EIO or sometimes EINVAL // when we try to actually send datagrams using it. - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "android"))] if let Some(libc::EIO) | Some(libc::EINVAL) = e.raw_os_error() { // Prevent new transmits from being scheduled using GSO. Existing GSO transmits // may already be in the pipeline, so we need to tolerate additional failures. @@ -767,10 +767,16 @@ pub(crate) const BATCH_SIZE: usize = 32; #[cfg(apple_slow)] pub(crate) const BATCH_SIZE: usize = 1; -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "android"))] mod gso { use super::*; + #[cfg(not(target_os = "android"))] + const UDP_SEGMENT: libc::c_int = libc::UDP_SEGMENT; + #[cfg(target_os = "android")] + // TODO: Add this to libc + const UDP_SEGMENT: libc::c_int = 103; + /// Checks whether GSO support is available by setting the UDP_SEGMENT /// option on a socket pub(crate) fn max_gso_segments() -> usize { @@ -785,21 +791,21 @@ mod gso { // As defined in linux/udp.h // #define UDP_MAX_SEGMENTS (1 << 6UL) - match set_socket_option(&socket, libc::SOL_UDP, libc::UDP_SEGMENT, GSO_SIZE) { + match set_socket_option(&socket, libc::SOL_UDP, UDP_SEGMENT, GSO_SIZE) { Ok(()) => 64, Err(_) => 1, } } pub(crate) fn set_segment_size(encoder: &mut cmsg::Encoder, segment_size: u16) { - encoder.push(libc::SOL_UDP, libc::UDP_SEGMENT, segment_size); + encoder.push(libc::SOL_UDP, UDP_SEGMENT, segment_size); } } // On Apple platforms using the `sendmsg_x` call, UDP datagram segmentation is not // offloaded to the NIC or even the kernel, but instead done here in user space in // [`send`]) and then passed to the OS as individual `iovec`s (up to `BATCH_SIZE`). -#[cfg(not(target_os = "linux"))] +#[cfg(not(any(target_os = "linux", target_os = "android")))] mod gso { use super::*; diff --git a/quinn-udp/tests/tests.rs b/quinn-udp/tests/tests.rs index a0dd32fda..53c5a1e49 100644 --- a/quinn-udp/tests/tests.rs +++ b/quinn-udp/tests/tests.rs @@ -156,7 +156,10 @@ fn ecn_v4_mapped_v6() { } #[test] -#[cfg_attr(not(any(target_os = "linux", target_os = "windows")), ignore)] +#[cfg_attr( + not(any(target_os = "linux", target_os = "windows", target_os = "android")), + ignore +)] fn gso() { let send = UdpSocket::bind((Ipv6Addr::LOCALHOST, 0)) .or_else(|_| UdpSocket::bind((Ipv4Addr::LOCALHOST, 0))) From a694602cbd719cb1738bdaa0ca1fa72028827c44 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sat, 16 Nov 2024 21:16:44 -0800 Subject: [PATCH 10/21] Enable GRO on Android --- quinn-udp/src/unix.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index 15ce2a4b3..cf3518173 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -127,8 +127,7 @@ impl UdpSocketState { #[cfg(any(target_os = "linux", target_os = "android"))] { // opportunistically try to enable GRO. See gro::gro_segments(). - #[cfg(target_os = "linux")] - let _ = set_socket_option(&*io, libc::SOL_UDP, libc::UDP_GRO, OPTION_ON); + let _ = set_socket_option(&*io, libc::SOL_UDP, gro::UDP_GRO, OPTION_ON); // Forbid IPv4 fragmentation. Set even for IPv6 to account for IPv6 mapped IPv4 addresses. // Set `may_fragment` to `true` if this option is not supported on the platform. @@ -719,8 +718,8 @@ fn decode_recv( let pktinfo = unsafe { cmsg::decode::(cmsg) }; dst_ip = Some(IpAddr::V6(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr))); } - #[cfg(target_os = "linux")] - (libc::SOL_UDP, libc::UDP_GRO) => unsafe { + #[cfg(any(target_os = "linux", target_os = "android"))] + (libc::SOL_UDP, gro::UDP_GRO) => unsafe { stride = cmsg::decode::(cmsg) as usize; }, _ => {} @@ -828,10 +827,16 @@ mod gso { } } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "android"))] mod gro { use super::*; + #[cfg(not(target_os = "android"))] + pub(crate) const UDP_GRO: libc::c_int = libc::UDP_GRO; + #[cfg(target_os = "android")] + // TODO: Add this to libc + pub(crate) const UDP_GRO: libc::c_int = 104; + pub(crate) fn gro_segments() -> usize { let socket = match std::net::UdpSocket::bind("[::]:0") .or_else(|_| std::net::UdpSocket::bind((Ipv4Addr::LOCALHOST, 0))) @@ -847,7 +852,7 @@ mod gro { // (get_max_udp_payload_size() * gro_segments()) is large enough to hold the largest GRO // list the kernel might potentially produce. See // https://github.com/quinn-rs/quinn/pull/1354. - match set_socket_option(&socket, libc::SOL_UDP, libc::UDP_GRO, OPTION_ON) { + match set_socket_option(&socket, libc::SOL_UDP, UDP_GRO, OPTION_ON) { Ok(()) => 64, Err(_) => 1, } @@ -895,7 +900,7 @@ fn set_socket_option( const OPTION_ON: libc::c_int = 1; -#[cfg(not(target_os = "linux"))] +#[cfg(not(any(target_os = "linux", target_os = "android")))] mod gro { pub(super) fn gro_segments() -> usize { 1 From 3a9d176a7a131a1f6d9472c1a23fccdcb1275b52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:45:56 +0000 Subject: [PATCH 11/21] build(deps): bump codecov/codecov-action from 4 to 5 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v5) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 7fa7bcfdd..83da040fd 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -16,7 +16,7 @@ jobs: - uses: taiki-e/install-action@cargo-llvm-cov - run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: lcov.info From 98a1050dc61076e9084a4b05a140310db1d3c820 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 18 Nov 2024 15:16:57 +1100 Subject: [PATCH 12/21] Use `try_send` in tests Currently, the test suite uses `UdpSocketState::send`. This function never reports errors (apart from `io::ErrorKind::WouldBlock). Whilst this may make sense for production, in the tests we actually want to know whether we hit any IO errors. --- quinn-udp/tests/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quinn-udp/tests/tests.rs b/quinn-udp/tests/tests.rs index 53c5a1e49..7169ed6ae 100644 --- a/quinn-udp/tests/tests.rs +++ b/quinn-udp/tests/tests.rs @@ -193,7 +193,7 @@ fn test_send_recv(send: &Socket, recv: &Socket, transmit: Transmit) { // Reverse non-blocking flag set by `UdpSocketState` to make the test non-racy recv.set_nonblocking(false).unwrap(); - send_state.send(send.into(), &transmit).unwrap(); + send_state.try_send(send.into(), &transmit).unwrap(); let mut buf = [0; u16::MAX as usize]; let mut meta = RecvMeta::default(); From f8b8c5032e0db9d7dbc7c3452f09c7d1e2a4295d Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Mon, 18 Nov 2024 15:17:46 +0200 Subject: [PATCH 13/21] chore: Fix `cargo clippy` issues --- perf/src/bin/perf_client.rs | 2 +- perf/src/bin/perf_server.rs | 2 +- quinn-proto/src/connection/ack_frequency.rs | 4 +--- quinn-proto/src/connection/mod.rs | 16 ++++++---------- quinn-proto/src/connection/mtud.rs | 2 +- quinn-proto/src/connection/packet_crypto.rs | 2 +- quinn-proto/src/connection/spaces.rs | 2 +- quinn-proto/src/connection/streams/state.rs | 4 ++-- quinn-proto/src/connection/timer.rs | 2 +- quinn-proto/src/endpoint.rs | 6 +++--- quinn-proto/src/packet.rs | 2 +- quinn-proto/src/range_set/btree_range_set.rs | 2 +- quinn-proto/src/tests/util.rs | 4 ++-- quinn-proto/src/transport_parameters.rs | 7 +++---- quinn/examples/server.rs | 6 +++--- 15 files changed, 28 insertions(+), 35 deletions(-) diff --git a/perf/src/bin/perf_client.rs b/perf/src/bin/perf_client.rs index d081ae179..a8ceeceec 100644 --- a/perf/src/bin/perf_client.rs +++ b/perf/src/bin/perf_client.rs @@ -308,7 +308,7 @@ async fn request( let send_stream_stats = stream_stats.new_sender(&send, upload); - const DATA: [u8; 1024 * 1024] = [42; 1024 * 1024]; + static DATA: [u8; 1024 * 1024] = [42; 1024 * 1024]; while upload > 0 { let chunk_len = upload.min(DATA.len() as u64); send.write_chunk(Bytes::from_static(&DATA[..chunk_len as usize])) diff --git a/perf/src/bin/perf_server.rs b/perf/src/bin/perf_server.rs index 5d29701db..74b527aca 100644 --- a/perf/src/bin/perf_server.rs +++ b/perf/src/bin/perf_server.rs @@ -215,7 +215,7 @@ async fn drain_stream(mut stream: quinn::RecvStream) -> Result<()> { } async fn respond(mut bytes: u64, mut stream: quinn::SendStream) -> Result<()> { - const DATA: [u8; 1024 * 1024] = [42; 1024 * 1024]; + static DATA: [u8; 1024 * 1024] = [42; 1024 * 1024]; while bytes > 0 { let chunk_len = bytes.min(DATA.len() as u64); diff --git a/quinn-proto/src/connection/ack_frequency.rs b/quinn-proto/src/connection/ack_frequency.rs index 94b6805fb..ab06e45ac 100644 --- a/quinn-proto/src/connection/ack_frequency.rs +++ b/quinn-proto/src/connection/ack_frequency.rs @@ -121,9 +121,7 @@ impl AckFrequencyState { ) -> Result { if self .last_ack_frequency_frame - .map_or(false, |highest_sequence_nr| { - frame.sequence.into_inner() <= highest_sequence_nr - }) + .is_some_and(|highest_sequence_nr| frame.sequence.into_inner() <= highest_sequence_nr) { return Ok(false); } diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index d6368ca1b..babb0d757 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -973,14 +973,10 @@ impl Connection { // Send MTU probe if necessary if buf.is_empty() && self.state.is_established() { let space_id = SpaceId::Data; - let probe_size = match self + let probe_size = self .path .mtud - .poll_transmit(now, self.packet_number_filter.peek(&self.spaces[space_id])) - { - Some(next_probe_size) => next_probe_size, - None => return None, - }; + .poll_transmit(now, self.packet_number_filter.peek(&self.spaces[space_id]))?; let buf_capacity = probe_size as usize; buf.reserve(buf_capacity); @@ -1655,7 +1651,7 @@ impl Connection { None if self .path .first_packet_after_rtt_sample - .map_or(false, |x| x < (pn_space, packet)) => + .is_some_and(|x| x < (pn_space, packet)) => { persistent_congestion_start = Some(info.time_sent); } @@ -2230,7 +2226,7 @@ impl Connection { let _guard = span.enter(); let is_duplicate = |n| self.spaces[packet.header.space()].dedup.insert(n); - if number.map_or(false, is_duplicate) { + if number.is_some_and(is_duplicate) { debug!("discarding possible duplicate packet"); return; } else if self.state.is_handshake() && packet.header.is_short() { @@ -3544,13 +3540,13 @@ impl Connection { || self .prev_path .as_ref() - .map_or(false, |(_, x)| x.challenge_pending) + .is_some_and(|(_, x)| x.challenge_pending) || !self.path_responses.is_empty() || self .datagrams .outgoing .front() - .map_or(false, |x| x.size(true) <= max_size) + .is_some_and(|x| x.size(true) <= max_size) } /// Update counters to account for a packet becoming acknowledged, lost, or abandoned diff --git a/quinn-proto/src/connection/mtud.rs b/quinn-proto/src/connection/mtud.rs index c221ab48d..be1fe7eef 100644 --- a/quinn-proto/src/connection/mtud.rs +++ b/quinn-proto/src/connection/mtud.rs @@ -417,7 +417,7 @@ impl BlackHoleDetector { let end_last_burst = self .current_loss_burst .as_ref() - .map_or(false, |current| pn - current.latest_non_probe != 1); + .is_some_and(|current| pn - current.latest_non_probe != 1); if end_last_burst { self.finish_loss_burst(); diff --git a/quinn-proto/src/connection/packet_crypto.rs b/quinn-proto/src/connection/packet_crypto.rs index ffb98ea8a..0d3063aa9 100644 --- a/quinn-proto/src/connection/packet_crypto.rs +++ b/quinn-proto/src/connection/packet_crypto.rs @@ -131,7 +131,7 @@ pub(super) fn decrypt_packet_body( if crypto_update { // Validate incoming key update - if number <= rx_packet || prev_crypto.map_or(false, |x| x.update_unacked) { + if number <= rx_packet || prev_crypto.is_some_and(|x| x.update_unacked) { return Err(Some(TransportError::KEY_UPDATE_ERROR(""))); } } diff --git a/quinn-proto/src/connection/spaces.rs b/quinn-proto/src/connection/spaces.rs index a97eea24b..ed58b51c1 100644 --- a/quinn-proto/src/connection/spaces.rs +++ b/quinn-proto/src/connection/spaces.rs @@ -853,7 +853,7 @@ impl PacketNumberFilter { if space_id == SpaceId::Data && self .prev_skipped_packet_number - .map_or(false, |x| range.contains(&x)) + .is_some_and(|x| range.contains(&x)) { return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked")); } diff --git a/quinn-proto/src/connection/streams/state.rs b/quinn-proto/src/connection/streams/state.rs index a3f14b3b5..90b853b7b 100644 --- a/quinn-proto/src/connection/streams/state.rs +++ b/quinn-proto/src/connection/streams/state.rs @@ -396,7 +396,7 @@ impl StreamsState { self.send .get(&stream.id) .and_then(|s| s.as_ref()) - .map_or(false, |s| !s.is_reset()) + .is_some_and(|s| !s.is_reset()) }) } @@ -406,7 +406,7 @@ impl StreamsState { .get(&id) .and_then(|s| s.as_ref()) .and_then(|s| s.as_open_recv()) - .map_or(false, |s| s.can_send_flow_control()) + .is_some_and(|s| s.can_send_flow_control()) } pub(in crate::connection) fn write_control_frames( diff --git a/quinn-proto/src/connection/timer.rs b/quinn-proto/src/connection/timer.rs index 1bf67e023..566652d0d 100644 --- a/quinn-proto/src/connection/timer.rs +++ b/quinn-proto/src/connection/timer.rs @@ -60,6 +60,6 @@ impl TimerTable { } pub(super) fn is_expired(&self, timer: Timer, after: Instant) -> bool { - self.data[timer as usize].map_or(false, |x| x <= after) + self.data[timer as usize].is_some_and(|x| x <= after) } } diff --git a/quinn-proto/src/endpoint.rs b/quinn-proto/src/endpoint.rs index 6210aafe9..09819833c 100644 --- a/quinn-proto/src/endpoint.rs +++ b/quinn-proto/src/endpoint.rs @@ -215,11 +215,11 @@ impl Endpoint { if incoming_buffer .total_bytes .checked_add(datagram_len as u64) - .map_or(false, |n| n <= config.incoming_buffer_size) + .is_some_and(|n| n <= config.incoming_buffer_size) && self .all_incoming_buffers_total_bytes .checked_add(datagram_len as u64) - .map_or(false, |n| n <= config.incoming_buffer_size_total) + .is_some_and(|n| n <= config.incoming_buffer_size_total) { incoming_buffer.datagrams.push(event); incoming_buffer.total_bytes += datagram_len as u64; @@ -334,7 +334,7 @@ impl Endpoint { ) -> Option { if self .last_stateless_reset - .map_or(false, |last| last + self.config.min_reset_interval > now) + .is_some_and(|last| last + self.config.min_reset_interval > now) { debug!("ignoring unexpected packet within minimum stateless reset interval"); return None; diff --git a/quinn-proto/src/packet.rs b/quinn-proto/src/packet.rs index fba0b40db..1970b4679 100644 --- a/quinn-proto/src/packet.rs +++ b/quinn-proto/src/packet.rs @@ -769,7 +769,7 @@ impl PacketNumber { // The following code calculates a candidate value and makes sure it's within the packet // number window. let candidate = (expected & !mask) | truncated; - if expected.checked_sub(hwin).map_or(false, |x| candidate <= x) { + if expected.checked_sub(hwin).is_some_and(|x| candidate <= x) { candidate + win } else if candidate > expected + hwin && candidate > win { candidate - win diff --git a/quinn-proto/src/range_set/btree_range_set.rs b/quinn-proto/src/range_set/btree_range_set.rs index 85a2c538a..d8eb11de3 100644 --- a/quinn-proto/src/range_set/btree_range_set.rs +++ b/quinn-proto/src/range_set/btree_range_set.rs @@ -18,7 +18,7 @@ impl RangeSet { } pub fn contains(&self, x: u64) -> bool { - self.pred(x).map_or(false, |(_, end)| end > x) + self.pred(x).is_some_and(|(_, end)| end > x) } pub fn insert_one(&mut self, x: u64) -> bool { diff --git a/quinn-proto/src/tests/util.rs b/quinn-proto/src/tests/util.rs index 8cb47d30f..7e927e203 100644 --- a/quinn-proto/src/tests/util.rs +++ b/quinn-proto/src/tests/util.rs @@ -356,7 +356,7 @@ impl TestEndpoint { let buffer_size = self.endpoint.config().get_max_udp_payload_size() as usize; let mut buf = Vec::with_capacity(buffer_size); - while self.inbound.front().map_or(false, |x| x.0 <= now) { + while self.inbound.front().is_some_and(|x| x.0 <= now) { let (recv_time, ecn, packet) = self.inbound.pop_front().unwrap(); if let Some(event) = self .endpoint @@ -415,7 +415,7 @@ impl TestEndpoint { loop { let mut endpoint_events: Vec<(ConnectionHandle, EndpointEvent)> = vec![]; for (ch, conn) in self.connections.iter_mut() { - if self.timeout.map_or(false, |x| x <= now) { + if self.timeout.is_some_and(|x| x <= now) { self.timeout = None; conn.handle_timeout(now); } diff --git a/quinn-proto/src/transport_parameters.rs b/quinn-proto/src/transport_parameters.rs index c09c41f97..aa279d48f 100644 --- a/quinn-proto/src/transport_parameters.rs +++ b/quinn-proto/src/transport_parameters.rs @@ -146,7 +146,7 @@ impl TransportParameters { initial_max_stream_data_uni: config.stream_receive_window, max_udp_payload_size: endpoint_config.max_udp_payload_size, max_idle_timeout: config.max_idle_timeout.unwrap_or(VarInt(0)), - disable_active_migration: server_config.map_or(false, |c| !c.migration), + disable_active_migration: server_config.is_some_and(|c| !c.migration), active_connection_id_limit: if cid_gen.cid_len() == 0 { 2 // i.e. default, i.e. unsent } else { @@ -446,7 +446,7 @@ impl TransportParameters { || params.initial_max_streams_bidi.0 > MAX_STREAM_COUNT || params.initial_max_streams_uni.0 > MAX_STREAM_COUNT // https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-08.html#section-3-4 - || params.min_ack_delay.map_or(false, |min_ack_delay| { + || params.min_ack_delay.is_some_and(|min_ack_delay| { // min_ack_delay uses microseconds, whereas max_ack_delay uses milliseconds min_ack_delay.0 > params.max_ack_delay.0 * 1_000 }) @@ -458,8 +458,7 @@ impl TransportParameters { || params.stateless_reset_token.is_some())) // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2-4.38.1 || params - .preferred_address - .map_or(false, |x| x.connection_id.is_empty()) + .preferred_address.is_some_and(|x| x.connection_id.is_empty()) { return Err(Error::IllegalValue); } diff --git a/quinn/examples/server.rs b/quinn/examples/server.rs index 5f9e6f35d..b6f63160e 100644 --- a/quinn/examples/server.rs +++ b/quinn/examples/server.rs @@ -70,7 +70,7 @@ fn main() { async fn run(options: Opt) -> Result<()> { let (certs, key) = if let (Some(key_path), Some(cert_path)) = (&options.key, &options.cert) { let key = fs::read(key_path).context("failed to read private key")?; - let key = if key_path.extension().map_or(false, |x| x == "der") { + let key = if key_path.extension().is_some_and(|x| x == "der") { PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(key)) } else { rustls_pemfile::private_key(&mut &*key) @@ -78,7 +78,7 @@ async fn run(options: Opt) -> Result<()> { .ok_or_else(|| anyhow::Error::msg("no private keys found"))? }; let cert_chain = fs::read(cert_path).context("failed to read certificate chain")?; - let cert_chain = if cert_path.extension().map_or(false, |x| x == "der") { + let cert_chain = if cert_path.extension().is_some_and(|x| x == "der") { vec![CertificateDer::from(cert_chain)] } else { rustls_pemfile::certs(&mut &*cert_chain) @@ -140,7 +140,7 @@ async fn run(options: Opt) -> Result<()> { while let Some(conn) = endpoint.accept().await { if options .connection_limit - .map_or(false, |n| endpoint.open_connections() >= n) + .is_some_and(|n| endpoint.open_connections() >= n) { info!("refusing due to open connection limit"); conn.refuse(); From a16dcd27de41cac7df56dffdf9a56b8ccdc4d660 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 18 Nov 2024 15:06:19 +1100 Subject: [PATCH 14/21] Log GSO halt on info It is common to set up automated error reporting based on `ERROR` and potentially also `WARN` logs. Whilst GSO being unsupported is certainly something worthwhile logging, the `ERROR` log level seems a bit excessive and leads to unactionable errors reports. The system can still operate with `max_gso_segments == 1`. As such, this codepath "merely" indicates a state change in the system but not a fatal error. As such, logging this on INFO level seems more appropriate. --- quinn-udp/src/unix.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index cf3518173..4978fa414 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -322,7 +322,9 @@ fn send( // Prevent new transmits from being scheduled using GSO. Existing GSO transmits // may already be in the pipeline, so we need to tolerate additional failures. if state.max_gso_segments() > 1 { - crate::log::error!("got transmit error, halting segmentation offload"); + crate::log::info!( + "`libc::sendmsg` failed with {e}; halting segmentation offload" + ); state .max_gso_segments .store(1, std::sync::atomic::Ordering::Relaxed); From 95a63d7cd214e8b3eb1a4d6fac59ad1261adeeff Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 18 Nov 2024 15:07:26 +1100 Subject: [PATCH 15/21] Don't log and return Logging AND returning errors is considered an anti-pattern because it leads to duplicate logs. --- quinn-udp/src/windows.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/quinn-udp/src/windows.rs b/quinn-udp/src/windows.rs index 886f45511..223ab0fdf 100644 --- a/quinn-udp/src/windows.rs +++ b/quinn-udp/src/windows.rs @@ -14,7 +14,7 @@ use windows_sys::Win32::Networking::WinSock; use crate::{ cmsg::{self, CMsgHdr}, - log::{debug, error}, + log::debug, log_sendmsg_error, EcnCodepoint, RecvMeta, Transmit, UdpSockRef, IO_ERROR_LOG_INTERVAL, }; @@ -61,9 +61,10 @@ impl UdpSocketState { // We don't support old versions of Windows that do not enable access to `WSARecvMsg()` if WSARECVMSG_PTR.is_none() { - error!("network stack does not support WSARecvMsg function"); - - return Err(io::Error::from(io::ErrorKind::Unsupported)); + return Err(io::Error::new( + io::ErrorKind::Unsupported, + "network stack does not support WSARecvMsg function", + )); } if is_ipv4 { From c613edf3a31f7f1c28f16175ccc7061eb6a3991e Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 18 Nov 2024 16:13:03 +1100 Subject: [PATCH 16/21] Log failure to set `UDP_SEGMENT` option --- quinn-udp/src/unix.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index 4978fa414..02acdf0e0 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -794,7 +794,13 @@ mod gso { // #define UDP_MAX_SEGMENTS (1 << 6UL) match set_socket_option(&socket, libc::SOL_UDP, UDP_SEGMENT, GSO_SIZE) { Ok(()) => 64, - Err(_) => 1, + Err(_e) => { + crate::log::debug!( + "failed to set `UDP_SEGMENT` socket option ({_e}); setting `max_gso_segments = 1`" + ); + + 1 + } } } From 9386cde871c750464073772409615e90344b80e9 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 18 Nov 2024 16:15:36 +1100 Subject: [PATCH 17/21] Only set `segment_size` if it is different from the transmit length --- quinn-udp/src/unix.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index 02acdf0e0..38b322e24 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -593,7 +593,12 @@ fn prepare_msg( encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn); } - if let Some(segment_size) = transmit.segment_size { + // Only set the segment size if it is different from the size of the contents. + // Some network drivers don't like being told to do GSO even if there is effectively only a single segment. + if let Some(segment_size) = transmit + .segment_size + .filter(|segment_size| *segment_size != transmit.contents.len()) + { gso::set_segment_size(&mut encoder, segment_size as u16); } From b44294e4118a54d1033ff59a7675cf5191f36420 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 20 Nov 2024 12:57:47 +0100 Subject: [PATCH 18/21] Allow Unicode 3.0 license --- deny.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deny.toml b/deny.toml index 8998d6244..1fb8356f2 100644 --- a/deny.toml +++ b/deny.toml @@ -7,7 +7,7 @@ allow = [ "MIT", "MPL-2.0", "OpenSSL", - "Unicode-DFS-2016", + "Unicode-3.0", ] private = { ignore = true } From ff4663b69671cd8c68ba3487bb7d5f2884489f3f Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Tue, 19 Nov 2024 19:31:50 -0800 Subject: [PATCH 19/21] Preserve the time a new incoming packet was received at --- quinn-proto/src/endpoint.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/quinn-proto/src/endpoint.rs b/quinn-proto/src/endpoint.rs index 09819833c..7cf087393 100644 --- a/quinn-proto/src/endpoint.rs +++ b/quinn-proto/src/endpoint.rs @@ -284,7 +284,7 @@ impl Endpoint { return match first_decode.finish(Some(&*crypto.header.remote)) { Ok(packet) => { - self.handle_first_packet(addresses, ecn, packet, remaining, crypto, buf) + self.handle_first_packet(addresses, ecn, packet, remaining, crypto, buf, now) } Err(e) => { trace!("unable to decode initial packet: {}", e); @@ -482,6 +482,7 @@ impl Endpoint { rest: Option, crypto: Keys, buf: &mut Vec, + now: Instant, ) -> Option { if !packet.reserved_bits_valid() { debug!("dropping connection attempt with invalid reserved bits"); @@ -533,6 +534,7 @@ impl Endpoint { .insert_initial_incoming(header.dst_cid, incoming_idx); Some(DatagramEvent::NewConnection(Incoming { + received_at: now, addresses, ecn, packet: InitialPacket { @@ -644,7 +646,7 @@ impl Endpoint { src_cid, pref_addr_cid, incoming.addresses, - now, + incoming.received_at, tls, Some(server_config), transport_config, @@ -653,7 +655,7 @@ impl Endpoint { self.index.insert_initial(dst_cid, ch); match conn.handle_first_packet( - now, + incoming.received_at, incoming.addresses.remote, incoming.ecn, packet_number, @@ -1178,6 +1180,7 @@ pub enum DatagramEvent { /// An incoming connection for which the server has not yet begun its part of the handshake. pub struct Incoming { + received_at: Instant, addresses: FourTuple, ecn: Option, packet: InitialPacket, From df7f58e19b433f59e7a184e0cccc99be94fc230b Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Tue, 19 Nov 2024 19:33:56 -0800 Subject: [PATCH 20/21] Fail accept immediately on stale Incoming --- quinn-proto/src/endpoint.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/quinn-proto/src/endpoint.rs b/quinn-proto/src/endpoint.rs index 7cf087393..fc652a8bc 100644 --- a/quinn-proto/src/endpoint.rs +++ b/quinn-proto/src/endpoint.rs @@ -31,8 +31,8 @@ use crate::{ }, token::TokenDecodeError, transport_parameters::{PreferredAddress, TransportParameters}, - Instant, ResetToken, RetryToken, Side, SystemTime, Transmit, TransportConfig, TransportError, - INITIAL_MTU, MAX_CID_SIZE, MIN_INITIAL_SIZE, RESET_TOKEN_SIZE, + Duration, Instant, ResetToken, RetryToken, Side, SystemTime, Transmit, TransportConfig, + TransportError, INITIAL_MTU, MAX_CID_SIZE, MIN_INITIAL_SIZE, RESET_TOKEN_SIZE, }; /// The main entry point to the library @@ -571,6 +571,23 @@ impl Endpoint { version, .. } = incoming.packet.header; + let server_config = + server_config.unwrap_or_else(|| self.server_config.as_ref().unwrap().clone()); + + if server_config + .transport + .max_idle_timeout + .is_some_and(|timeout| { + incoming.received_at + Duration::from_millis(timeout.into()) <= now + }) + { + debug!("abandoning accept of stale initial"); + self.index.remove_initial(dst_cid); + return Err(AcceptError { + cause: ConnectionError::TimedOut, + response: None, + }); + } if self.cids_exhausted() { debug!("refusing connection"); @@ -588,9 +605,6 @@ impl Endpoint { }); } - let server_config = - server_config.unwrap_or_else(|| self.server_config.as_ref().unwrap().clone()); - if incoming .crypto .packet From a4c886c38a6e78916f683c01043b37b6d3a597cf Mon Sep 17 00:00:00 2001 From: Phoenix Kahlo Date: Wed, 20 Nov 2024 19:14:18 -0600 Subject: [PATCH 21/21] docs: Correct MSRV in README --- .github/workflows/rust.yml | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9da7d2143..edc0ce486 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -163,6 +163,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + # Note that we must also update the README when changing the MSRV - uses: dtolnay/rust-toolchain@1.70.0 - uses: Swatinem/rust-cache@v2 - run: cargo check --lib --all-features -p quinn-udp -p quinn-proto -p quinn diff --git a/README.md b/README.md index b82f9c4fd..d93c87283 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ The project was founded by [Dirkjan Ochtman](https://github.com/djc) and [rustls][rustls] and [*ring*][ring] - Application-layer datagrams for small, unreliable messages - Future-based async API -- Minimum supported Rust version of 1.66 +- Minimum supported Rust version of 1.70 ## Overview