## Description We saw `open_path_validation_fails_server_side` fail intermittently in [daily CI on FreeBSD](https://github.com/n0-computer/noq/actions/runs/33142246096), and matheus23 asked me to look into it. The test advanced with a single `advance_time()`, which jumps to the earliest timer pending on *either* endpoint, and assumed that jump lands on the client's 8s path-idle deadline for the blackholed path. It usually does. When the client happens to do a routine key update shortly before that deadline — PN phase exhaustion, which depends on the randomly chosen initial packet number — the server arms `KeyDiscard` at 3x PTO, and that fires about 100ms earlier. The jump lands there instead, `drive()` then stops stepping because `Connection::is_idle` discounts the idle timers that remain, and virtual time never reaches the deadline. The path-idle timer stays armed the whole time and the connection behaves correctly; the single jump in the test is the bug. The fix, as suggested by matheus23: a `drive_until_timer` helper that steps to each next wakeup and drives both endpoints until the target timer is no longer armed. `drive()` can't reach an idle timeout on its own — `is_idle` discounts exactly the timers a test would be waiting for — so this needs its own loop. The test now calls it instead of `advance_time()`. ## API Changes None, test changes only. ## Notes & open questions - I'm an agent posting from my own account (`n0-grookie`), so I left the "created by a human" box below unticked. matheus23 asked for the PR after reviewing the commits. - Measured on a seeded sweep over `StdRng::seed_from_u64()` driving the same `ConnPair` setup as the test: 82 of 20000 seeds failed before, 0 of 50000 after. Seed-dependent rather than platform-dependent — the same seeds fail on Linux, which is how I measured it. The sweep is scratch code and not in the commit; it can go in behind an `#[ignore]` if a repeatable sweep is worth having. - `drive_until_timer` panics rather than hangs if the timer is still armed after 1024 steps, and a *cancelled* timer also ends the loop — callers should keep asserting on the event they expect. Both are in the doc comment. - I went through the other `advance_time()` call sites in `src/tests`. They step to the next scheduled timer and assert on whatever arrives (`multipath.rs:2124` expects `Established`, the `mod.rs:4746` pair checks draining delays), so they don't carry this test's assumption that the jump lands on a specific deadline. Left them as they are. - No issue linked: it came out of daily CI and the fix was reviewed out of band. ## Change checklist - [x] Self-review. - [x] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. - [x] Tests if relevant. - [ ] This PR was created by a human that thought critically about the proposed change and wrote an as clear and concise description as they could. - [x] This PR isn't slop, and is carefully crafted to do have the intented effect. - [x] `cargo make` passes locally. --------- Co-authored-by: n0-grookie <322172879+n0-grookie@users.noreply.github.com>
noq
General purpose implementation of the QUIC transport
protocol in pure
Rust. Noq is built as an async-friendly API in the noq crate on top
of a sans-io protocol library in noq-proto.
Noq started out as a fork of the excellent Quinn project. The main focus of development has been towards adding support for more QUIC (draft) extensions:
Features
- Easy to use futures-based async API.
- Client and server server functionality.
- 0-RTT and 0.5-RTT data support.
- Ordered and unordered stream reads.
- Custom and zero-length connection identifiers.
- Fully pluggable crypto API with a Rustls implementation using ring or aws-lc-rs provided by default for convenience.
- Broad platform support, including Linux, Windows, macOS, android, iOS and wasm.
Standards
The noq library aims to be correct implementation of various QUIC standards:
- Supports the core QUIC specifications:
- The standardised QUIC extensions:
- Draft extensions:
- qlog: Structured Logging for Network Protocols.
- QUIC Multipath.
- With experimental qlog support.
- QUIC Address Discovery (QAD).
- Using QUIC to traverse NATs (QNT).
Getting started
Examples at https://github.com/n0-computer/noq/blob/main/noq/examples
$ cargo run --example server ./
$ cargo run --example client https://localhost:4433/Cargo.toml
This launches an HTTP 0.9 server over the QUIC transport on the loopback address serving the current working directory, with the client fetching ./Cargo.toml. By default, the server generates a self-signed certificate and stores it to disk, where the client will automatically find and trust it.
License
Copyright 2025 The quinn developers Copyright 2025 N0, INC.
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.