From ecae4ad100481d1efc248ec214b8105502106ec2 Mon Sep 17 00:00:00 2001 From: Damien Deville Date: Wed, 27 Aug 2025 15:32:18 +0200 Subject: [PATCH 01/71] quinn: track callers in runtime spawn abstraction --- quinn/src/runtime.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/quinn/src/runtime.rs b/quinn/src/runtime.rs index 9a7bb6906..c583affc1 100644 --- a/quinn/src/runtime.rs +++ b/quinn/src/runtime.rs @@ -17,6 +17,7 @@ pub trait Runtime: Send + Sync + Debug + 'static { /// Construct a timer that will expire at `i` fn new_timer(&self, i: Instant) -> Pin>; /// Drive `future` to completion in the background + #[track_caller] fn spawn(&self, future: Pin + Send>>); /// Convert `t` into the socket type used by this runtime #[cfg(not(wasm_browser))] From a9d4377db23110f4ed011c4c1f571d2e5005db84 Mon Sep 17 00:00:00 2001 From: Damien Deville Date: Wed, 27 Aug 2025 15:35:34 +0200 Subject: [PATCH 02/71] perf: add a feature to enable profiling with tokio-console --- Cargo.lock | 638 ++++++++++++++++++++++++++++++++++++++++++- perf/Cargo.toml | 7 + perf/src/bin/perf.rs | 18 +- 3 files changed, 643 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dfbc2268a..2ea09e6ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -268,12 +268,45 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -324,6 +357,53 @@ dependencies = [ "fs_extra", ] +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.75" @@ -339,6 +419,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -594,6 +680,46 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console-api" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8030735ecb0d128428b64cd379809817e620a40e5001c54465b99ec5feec2857" +dependencies = [ + "futures-core", + "prost", + "prost-types", + "tonic", + "tracing-core", +] + +[[package]] +name = "console-subscriber" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6539aa9c6a4cd31f4b1c040f860a1eac9aa80e7df6b05d506a6e7179936d6a01" +dependencies = [ + "console-api", + "crossbeam-channel", + "crossbeam-utils", + "futures-task", + "hdrhistogram", + "humantime", + "hyper-util", + "parking_lot", + "prost", + "prost-types", + "serde", + "serde_json", + "thread_local", + "tokio", + "tokio-stream", + "tonic", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -625,6 +751,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "criterion" version = "0.7.0" @@ -657,6 +792,15 @@ dependencies = [ "itertools 0.13.0", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -819,7 +963,7 @@ checksum = "18c1ddb9231d8554c2d6bdf4cfaabf0c59251658c68b6c95cd52dd0c513a912a" dependencies = [ "getrandom 0.3.3", "libm", - "rand", + "rand 0.9.2", "siphasher", ] @@ -829,6 +973,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -884,6 +1038,30 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "fuzz" version = "0.1.0" @@ -944,6 +1122,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.11.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.6.0" @@ -954,6 +1151,12 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.5" @@ -966,7 +1169,10 @@ version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" dependencies = [ + "base64 0.21.7", "byteorder", + "flate2", + "nom", "num-traits", ] @@ -997,6 +1203,115 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2 0.6.0", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "icu_collections" version = "2.0.0" @@ -1110,6 +1425,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.11.0" @@ -1117,7 +1442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.5", ] [[package]] @@ -1155,6 +1480,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1284,6 +1618,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.27" @@ -1308,12 +1652,24 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minicov" version = "0.3.7" @@ -1439,13 +1795,36 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "pem" version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ - "base64", + "base64 0.22.1", "serde", ] @@ -1462,6 +1841,7 @@ dependencies = [ "anyhow", "bytes", "clap", + "console-subscriber", "hdrhistogram", "quinn", "quinn-proto", @@ -1470,7 +1850,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "socket2", + "socket2 0.6.0", "tokio", "tracing", "tracing-subscriber", @@ -1576,6 +1956,38 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost", +] + [[package]] name = "qlog" version = "0.15.2" @@ -1605,13 +2017,13 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rand", + "rand 0.9.2", "rcgen", "rustc-hash 2.1.1", "rustls", "rustls-pemfile", "smol", - "socket2", + "socket2 0.6.0", "thiserror 2.0.16", "tokio", "tracing", @@ -1635,7 +2047,7 @@ dependencies = [ "lazy_static", "lru-slab", "qlog", - "rand", + "rand 0.9.2", "rand_pcg", "rcgen", "ring", @@ -1661,7 +2073,7 @@ dependencies = [ "libc", "log", "once_cell", - "socket2", + "socket2 0.6.0", "tokio", "tracing", "windows-sys 0.60.2", @@ -1682,14 +2094,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -1699,7 +2132,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -1717,7 +2159,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b48ac3f7ffaab7fac4d2376632268aa5f89abdb55f7ebf8f4d11fffccb2320f7" dependencies = [ - "rand_core", + "rand_core 0.9.3", ] [[package]] @@ -1733,6 +2175,15 @@ dependencies = [ "yasna", ] +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.6" @@ -1962,6 +2413,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "3.3.0" @@ -2011,7 +2468,7 @@ version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ - "indexmap", + "indexmap 2.11.0", "itoa", "memchr", "ryu", @@ -2103,6 +2560,16 @@ dependencies = [ "futures-lite", ] +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.0" @@ -2142,6 +2609,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "synstructure" version = "0.13.2" @@ -2277,14 +2750,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", + "bytes", "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", "slab", - "socket2", + "socket2 0.6.0", "tokio-macros", + "tracing", "windows-sys 0.59.0", ] @@ -2299,6 +2774,106 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "socket2 0.5.10", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.41" @@ -2307,9 +2882,21 @@ checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.34" @@ -2317,6 +2904,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", + "valuable", ] [[package]] @@ -2338,6 +2926,7 @@ dependencies = [ "matchers", "nu-ansi-term", "once_cell", + "parking_lot", "regex", "sharded-slab", "thread_local", @@ -2346,6 +2935,12 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -2382,6 +2977,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "value-bag" version = "1.11.1" @@ -2398,6 +2999,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/perf/Cargo.toml b/perf/Cargo.toml index ae2f5753e..08cec0302 100644 --- a/perf/Cargo.toml +++ b/perf/Cargo.toml @@ -17,11 +17,18 @@ default = ["json-output", "qlog"] json-output = ["serde", "serde_json"] # Enable qlog support qlog = ["quinn/qlog"] +# Enable tokio-console https://github.com/tokio-rs/console +# See https://docs.rs/console-subscriber/latest/console_subscriber/struct.Builder.html#method.with_default_env +# for useful environment variables in particular to change listen addr and port +# WARNING: it requires special compilation flags +# RUSTFLAGS="--cfg tokio_unstable" cargo build -r -p perf -F tokio-console +tokio-console = ["console-subscriber"] [dependencies] anyhow = { workspace = true } bytes = { workspace = true } clap = { workspace = true } +console-subscriber = { version = "0.4.1", features = ["parking_lot"], optional = true } hdrhistogram = { workspace = true } quinn = { path = "../quinn" } quinn-proto = { path = "../quinn-proto" } diff --git a/perf/src/bin/perf.rs b/perf/src/bin/perf.rs index 54c6ff797..8eb384387 100644 --- a/perf/src/bin/perf.rs +++ b/perf/src/bin/perf.rs @@ -1,6 +1,6 @@ use clap::{Parser, Subcommand}; use tracing::error; -use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt}; +use tracing_subscriber::{EnvFilter, Layer, fmt, layer::SubscriberExt, util::SubscriberInitExt}; use perf::{client, server}; @@ -23,13 +23,19 @@ enum Commands { async fn main() { let opt = Cli::parse(); - tracing_subscriber::registry() + let registry = tracing_subscriber::registry(); + + #[cfg(feature = "tokio-console")] + let registry = registry.with(console_subscriber::spawn()); + + registry .with( - EnvFilter::try_from_default_env() - .or_else(|_| EnvFilter::try_new("warn")) - .unwrap(), + fmt::layer().with_filter( + EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new("warn")) + .unwrap(), + ), ) - .with(fmt::layer()) .init(); let r = match opt.command { From 3182456dd79e02bbaab3d11f5b5663fef4bc18ca Mon Sep 17 00:00:00 2001 From: stormshield-gt Date: Wed, 27 Nov 2024 20:05:34 +0100 Subject: [PATCH 03/71] add a feature to expose key share handshake data --- quinn-proto/Cargo.toml | 5 +++++ quinn-proto/src/crypto/rustls.rs | 11 +++++++++++ quinn/Cargo.toml | 5 +++++ 3 files changed, 21 insertions(+) diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index 3c29d498f..914d8d400 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -36,6 +36,11 @@ rustls-log = ["rustls?/logging"] # Enable qlog support qlog = ["dep:qlog"] +# Internal (PRIVATE!) features used to aid testing. +# Don't rely on these whatsoever. They may disappear at any time. + +__rustls-post-quantum-test = [] + [dependencies] arbitrary = { workspace = true, optional = true } aws-lc-rs = { workspace = true, optional = true } diff --git a/quinn-proto/src/crypto/rustls.rs b/quinn-proto/src/crypto/rustls.rs index 231025b3c..b45ad3e84 100644 --- a/quinn-proto/src/crypto/rustls.rs +++ b/quinn-proto/src/crypto/rustls.rs @@ -6,6 +6,8 @@ use bytes::BytesMut; #[cfg(feature = "ring")] use ring::aead; pub use rustls::Error; +#[cfg(feature = "__rustls-post-quantum-test")] +use rustls::NamedGroup; use rustls::{ self, CipherSuite, client::danger::ServerCertVerifier, @@ -65,6 +67,12 @@ impl crypto::Session for TlsSession { Connection::Client(_) => None, Connection::Server(ref session) => session.server_name().map(|x| x.into()), }, + #[cfg(feature = "__rustls-post-quantum-test")] + negotiated_key_exchange_group: self + .inner + .negotiated_key_exchange_group() + .expect("key exchange group is negotiated") + .name(), })) } @@ -257,6 +265,9 @@ pub struct HandshakeData { /// /// Always `None` for outgoing connections pub server_name: Option, + /// The key exchange group negotiated with the peer + #[cfg(feature = "__rustls-post-quantum-test")] + pub negotiated_key_exchange_group: NamedGroup, } /// A QUIC-compatible TLS client configuration diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 505e406ff..a40490bb8 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -46,6 +46,11 @@ rustls-log = ["rustls?/logging"] # Enable qlog support qlog = ["proto/qlog"] +# Internal (PRIVATE!) features used to aid testing. +# Don't rely on these whatsoever. They may disappear at any time. + +__rustls-post-quantum-test = ["dep:rustls-post-quantum", "rustls-aws-lc-rs", "proto/__rustls-post-quantum-test"] + [dependencies] async-io = { workspace = true, optional = true } async-std = { workspace = true, optional = true } From 69a343b8a60f8948b9b4472ce8313bf0da500145 Mon Sep 17 00:00:00 2001 From: stormshield-gt Date: Wed, 27 Nov 2024 20:06:23 +0100 Subject: [PATCH 04/71] make post quantum test run in the CI --- .github/workflows/rust.yml | 4 +- quinn/Cargo.toml | 6 +- quinn/tests/many_connections.rs | 10 ++- quinn/tests/post_quantum.rs | 124 ++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 quinn/tests/post_quantum.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7c5926d2e..dd23c71f9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -142,9 +142,11 @@ jobs: # Prevent feature unification from selecting *ring* as the crypto provider - run: RUST_BACKTRACE=1 cargo test --locked --manifest-path quinn-proto/Cargo.toml --no-default-features --features rustls-aws-lc-rs - run: RUST_BACKTRACE=1 cargo test --locked --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs,runtime-tokio + - run: RUST_BACKTRACE=1 cargo test --locked --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs,runtime-tokio,__rustls-post-quantum-test # FIPS - run: RUST_BACKTRACE=1 cargo test --locked --manifest-path quinn-proto/Cargo.toml --no-default-features --features rustls-aws-lc-rs-fips - run: RUST_BACKTRACE=1 cargo test --locked --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs-fips,runtime-tokio + - run: RUST_BACKTRACE=1 cargo test --locked --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs-fips,__rustls-post-quantum-test,runtime-tokio wasm_test: name: test wasm32-unknown-unknown @@ -283,7 +285,7 @@ jobs: env: RUSTFLAGS: -Dwarnings # skip FIPS features outside of Linux - SKIP_FEATURES: ${{ matrix.os != 'ubuntu-latest' && 'rustls-aws-lc-rs-fips,aws-lc-rs-fips' || '' }} + SKIP_FEATURES: ${{ matrix.os != 'ubuntu-latest' && 'rustls-aws-lc-rs-fips,aws-lc-rs-fips,__rustls-post-quantum-test' || '' }} steps: - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index a40490bb8..2a94463ac 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -49,7 +49,7 @@ qlog = ["proto/qlog"] # Internal (PRIVATE!) features used to aid testing. # Don't rely on these whatsoever. They may disappear at any time. -__rustls-post-quantum-test = ["dep:rustls-post-quantum", "rustls-aws-lc-rs", "proto/__rustls-post-quantum-test"] +__rustls-post-quantum-test = ["rustls/prefer-post-quantum", "rustls-aws-lc-rs", "proto/__rustls-post-quantum-test"] [dependencies] async-io = { workspace = true, optional = true } @@ -110,6 +110,10 @@ required-features = ["rustls-ring"] name = "connection" required-features = ["rustls-ring"] +[[test]] +name = "post_quantum" +required-features = ["__rustls-post-quantum-test"] + [[bench]] name = "bench" harness = false diff --git a/quinn/tests/many_connections.rs b/quinn/tests/many_connections.rs index dc5274227..acd08cbe8 100644 --- a/quinn/tests/many_connections.rs +++ b/quinn/tests/many_connections.rs @@ -19,12 +19,10 @@ struct Shared { #[test] #[ignore] fn connect_n_nodes_to_1_and_send_1mb_data() { - tracing::subscriber::set_global_default( - tracing_subscriber::FmtSubscriber::builder() - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .finish(), - ) - .unwrap(); + let _ = tracing_subscriber::FmtSubscriber::builder() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .with_test_writer() + .try_init(); let runtime = Builder::new_current_thread().enable_all().build().unwrap(); let _guard = runtime.enter(); diff --git a/quinn/tests/post_quantum.rs b/quinn/tests/post_quantum.rs new file mode 100644 index 000000000..8983794b1 --- /dev/null +++ b/quinn/tests/post_quantum.rs @@ -0,0 +1,124 @@ +#![cfg(feature = "rustls-aws-lc-rs")] + +use std::{ + error::Error, + net::{Ipv4Addr, SocketAddr}, + sync::Arc, +}; + +use rustls::{ + NamedGroup, + pki_types::{CertificateDer, PrivatePkcs8KeyDer}, +}; +use tracing::info; + +use quinn::{ + Endpoint, + crypto::rustls::{HandshakeData, QuicClientConfig, QuicServerConfig}, +}; + +#[tokio::test] +async fn post_quantum_key_worst_case_header() { + check_post_quantum_key_exchange(1274).await; +} + +#[tokio::test] +async fn post_quantum_key_exchange_large_mtu() { + check_post_quantum_key_exchange(1433).await; +} + +async fn check_post_quantum_key_exchange(min_mtu: u16) { + let _ = tracing_subscriber::FmtSubscriber::builder() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .with_test_writer() + .try_init(); + + let server_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 0)); + + let (endpoint, server_cert) = make_server_endpoint(server_addr, min_mtu).unwrap(); + let server_addr = endpoint.local_addr().unwrap(); + // accept a single connection + let jh = tokio::spawn(async move { + let incoming_conn = endpoint.accept().await.unwrap(); + let conn = incoming_conn.await.unwrap(); + info!( + "[server] connection accepted: addr={}", + conn.remote_address() + ); + assert_eq!( + conn.handshake_data() + .unwrap() + .downcast::() + .unwrap() + .negotiated_key_exchange_group, + NamedGroup::X25519MLKEM768 + ) + }); + + let endpoint = + make_client_endpoint(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)), server_cert).unwrap(); + // connect to server + let connection = endpoint + .connect(server_addr, "localhost") + .unwrap() + .await + .unwrap(); + info!("[client] connected: addr={}", connection.remote_address()); + + // Waiting for a stream will complete with an error when the server closes the connection + let _ = connection.accept_uni().await; + + // Make sure the server has a chance to clean up + endpoint.wait_idle().await; + jh.await.unwrap(); +} + +fn make_client_endpoint( + bind_addr: SocketAddr, + server_cert: CertificateDer<'static>, +) -> Result> { + let mut certs = rustls::RootCertStore::empty(); + certs.add(server_cert)?; + let rustls_config = rustls::ClientConfig::builder_with_provider(Arc::new( + rustls::crypto::aws_lc_rs::default_provider(), + )) + .with_safe_default_protocol_versions() + .unwrap() + .with_root_certificates(certs) + .with_no_client_auth(); + + let client_cfg = + quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(rustls_config).unwrap())); + let mut endpoint = Endpoint::client(bind_addr)?; + endpoint.set_default_client_config(client_cfg); + Ok(endpoint) +} + +fn make_server_endpoint( + bind_addr: SocketAddr, + min_mtu: u16, +) -> Result<(Endpoint, CertificateDer<'static>), Box> { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); + let key = PrivatePkcs8KeyDer::from(cert.signing_key.serialize_der()); + let cert = CertificateDer::from(cert.cert); + let mut server_config = quinn::ServerConfig::with_crypto(Arc::new( + QuicServerConfig::try_from( + rustls::ServerConfig::builder_with_provider(Arc::new( + rustls::crypto::aws_lc_rs::default_provider(), + )) + .with_safe_default_protocol_versions() + .unwrap() + .with_no_client_auth() + .with_single_cert(vec![cert.clone()], key.into()) + .unwrap(), + ) + .unwrap(), + )); + + let transport_config = Arc::get_mut(&mut server_config.transport).unwrap(); + transport_config.max_concurrent_uni_streams(0_u8.into()); + transport_config.min_mtu(min_mtu); + + let endpoint = Endpoint::server(server_config, bind_addr)?; + Ok((endpoint, cert)) +} From c9be8ecad91ef79e2f8bb17b70d07fa7d05618ee Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Fri, 29 Aug 2025 22:59:52 +0200 Subject: [PATCH 05/71] Update tracing-subscriber to 0.3.20 --- Cargo.lock | 46 ++++++++++++---------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2ea09e6ff..553f4854b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1645,11 +1645,11 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "matchers" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -1718,12 +1718,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "overload", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1783,12 +1782,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking" version = "2.2.1" @@ -2203,17 +2196,8 @@ checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.10", - "regex-syntax 0.8.6", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -2224,15 +2208,9 @@ checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.6", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.6" @@ -2919,15 +2897,15 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", "once_cell", "parking_lot", - "regex", + "regex-automata", "sharded-slab", "thread_local", "time", From e4f0550b29cfaa2ade9752ae7aea8b801c7d3699 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Sun, 31 Aug 2025 10:32:30 +0200 Subject: [PATCH 06/71] perf: move main() above Cli --- perf/src/bin/perf.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/perf/src/bin/perf.rs b/perf/src/bin/perf.rs index 8eb384387..221cc12aa 100644 --- a/perf/src/bin/perf.rs +++ b/perf/src/bin/perf.rs @@ -4,30 +4,13 @@ use tracing_subscriber::{EnvFilter, Layer, fmt, layer::SubscriberExt, util::Subs use perf::{client, server}; -#[derive(Parser)] -#[clap(long_about = None)] -struct Cli { - #[command(subcommand)] - command: Commands, -} - -#[derive(Subcommand)] -enum Commands { - /// Run as a perf server - Server(server::Opt), - /// Run as a perf client - Client(client::Opt), -} - #[tokio::main(flavor = "current_thread")] async fn main() { let opt = Cli::parse(); let registry = tracing_subscriber::registry(); - #[cfg(feature = "tokio-console")] let registry = registry.with(console_subscriber::spawn()); - registry .with( fmt::layer().with_filter( @@ -46,3 +29,18 @@ async fn main() { error!("{:#}", e); } } + +#[derive(Parser)] +#[clap(long_about = None)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Run as a perf server + Server(server::Opt), + /// Run as a perf client + Client(client::Opt), +} From d3862a01bc2bf848d42e1d7a7c44a73a0a5614c4 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 31 Aug 2025 16:40:34 -0700 Subject: [PATCH 07/71] Bump versions for upcoming breaking changes --- Cargo.lock | 6 +++--- docs/book/Cargo.toml | 2 +- quinn-proto/Cargo.toml | 2 +- quinn-udp/Cargo.toml | 2 +- quinn/Cargo.toml | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 553f4854b..6293525bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1995,7 +1995,7 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.9" +version = "0.12.0" dependencies = [ "anyhow", "async-io", @@ -2028,7 +2028,7 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.12.0" dependencies = [ "arbitrary", "assert_matches", @@ -2059,7 +2059,7 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.6.0" dependencies = [ "cfg_aliases", "criterion", diff --git a/docs/book/Cargo.toml b/docs/book/Cargo.toml index cc4dfad5d..484f57050 100644 --- a/docs/book/Cargo.toml +++ b/docs/book/Cargo.toml @@ -11,6 +11,6 @@ categories.workspace = true [dependencies] anyhow.workspace = true bytes = { workspace = true } -quinn = { version = "0.11.7", path = "../../quinn" } +quinn = { version = "0.12.0", path = "../../quinn" } rcgen.workspace = true rustls.workspace = true diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index 914d8d400..9412dada1 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quinn-proto" -version = "0.11.13" +version = "0.12.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/quinn-udp/Cargo.toml b/quinn-udp/Cargo.toml index 7b5ed74c5..f55c1b5af 100644 --- a/quinn-udp/Cargo.toml +++ b/quinn-udp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quinn-udp" -version = "0.5.14" +version = "0.6.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 2a94463ac..0609806b8 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quinn" -version = "0.11.9" +version = "0.12.0" license.workspace = true repository.workspace = true description = "Versatile QUIC transport protocol implementation" @@ -59,13 +59,13 @@ bytes = { workspace = true } futures-io = { workspace = true, optional = true } rustc-hash = { workspace = true } pin-project-lite = { workspace = true } -proto = { package = "quinn-proto", path = "../quinn-proto", version = "0.11.12", default-features = false } +proto = { package = "quinn-proto", path = "../quinn-proto", version = "0.12.0", default-features = false } rustls = { workspace = true, optional = true } smol = { workspace = true, optional = true } thiserror = { workspace = true } tracing = { workspace = true } tokio = { workspace = true } -udp = { package = "quinn-udp", path = "../quinn-udp", version = "0.5", default-features = false, features = ["tracing"] } +udp = { package = "quinn-udp", path = "../quinn-udp", version = "0.6", default-features = false, features = ["tracing"] } [target.'cfg(not(all(target_family = "wasm", target_os = "unknown")))'.dependencies] socket2 = { workspace = true } From 50a0ef321ea4e6f6143d5665118c76e90453dc15 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 31 Aug 2025 13:09:16 -0700 Subject: [PATCH 08/71] Update obsolete rustls API guidance --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 02546bde4..a4edbff08 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,8 @@ for servers, and relying on the default configuration for clients. For some cases, including peer-to-peer, trust-on-first-use, deliberately insecure applications, or any case where servers are not identified by domain name, this isn't practical. Arbitrary certificate validation logic can be -implemented by enabling the `dangerous_configuration` feature of `rustls` and -constructing a Quinn `ClientConfig` with an overridden certificate verifier by -hand. +implemented by customizing the `rustls` configuration; see the +[insecure_connection.rs][insecure] example for details. When operating your own certificate authority doesn't make sense, [rcgen][rcgen] can be used to generate self-signed certificates on demand. To support @@ -125,3 +124,4 @@ crates will always be at least 6 months old at the time of release. [examples]: https://github.com/djc/quinn/tree/main/quinn/examples [documentation]: https://quinn-rs.github.io/quinn/networking-introduction.html [sans-io]: https://sans-io.readthedocs.io/how-to-sans-io.html +[insecure]: https://github.com/quinn-rs/quinn/blob/main/quinn/examples/insecure_connection.rs From d845f4009de02ab710b6b23c3b7e4d2fc63b5742 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 19 Aug 2025 10:15:26 +0200 Subject: [PATCH 09/71] quinn: drop async-std support --- Cargo.lock | 102 ++-------------------------------- deny.toml | 3 - quinn/Cargo.toml | 2 - quinn/src/lib.rs | 2 - quinn/src/runtime.rs | 17 ++---- quinn/src/runtime/async_io.rs | 42 ++------------ 6 files changed, 16 insertions(+), 152 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6293525bc..8945f5bc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,17 +103,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - [[package]] name = "async-channel" version = "2.5.0" @@ -151,21 +140,6 @@ dependencies = [ "futures-lite", ] -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.5.0", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - [[package]] name = "async-io" version = "2.5.0" @@ -190,7 +164,7 @@ version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] @@ -212,14 +186,14 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-io", "async-lock", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener 5.4.1", + "event-listener", "futures-lite", "rustix 1.0.8", ] @@ -242,32 +216,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "async-std" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - [[package]] name = "async-stream" version = "0.3.6" @@ -488,7 +436,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-task", "futures-io", "futures-lite", @@ -928,12 +876,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "event-listener" version = "5.4.1" @@ -951,7 +893,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener", "pin-project-lite", ] @@ -1110,18 +1052,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "h2" version = "0.4.12" @@ -1537,15 +1467,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1633,9 +1554,6 @@ name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -dependencies = [ - "value-bag", -] [[package]] name = "lru-slab" @@ -1999,7 +1917,6 @@ version = "0.12.0" dependencies = [ "anyhow", "async-io", - "async-std", "bencher", "bytes", "cfg_aliases", @@ -2527,7 +2444,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "async-channel 2.5.0", + "async-channel", "async-executor", "async-fs", "async-io", @@ -2961,12 +2878,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "value-bag" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" - [[package]] name = "walkdir" version = "2.5.0" @@ -3009,7 +2920,6 @@ checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", - "rustversion", "wasm-bindgen-macro", ] diff --git a/deny.toml b/deny.toml index 0f9717efa..12d201934 100644 --- a/deny.toml +++ b/deny.toml @@ -16,6 +16,3 @@ private = { ignore = true } name = "ring" expression = "ISC AND MIT AND OpenSSL" license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] - -[advisories] -ignore = ["RUSTSEC-2025-0052"] diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 0609806b8..8b8e04618 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -36,7 +36,6 @@ rustls-ring = ["dep:rustls", "ring", "proto/rustls-ring", "proto/ring"] # Outside wasm*-unknown-unknown targets, this enables `Endpoint::client` and `Endpoint::server` conveniences. ring = ["proto/ring"] runtime-tokio = ["tokio/time", "tokio/rt", "tokio/net"] -runtime-async-std = ["async-io", "async-std"] runtime-smol = ["async-io", "smol"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. @@ -53,7 +52,6 @@ __rustls-post-quantum-test = ["rustls/prefer-post-quantum", "rustls-aws-lc-rs", [dependencies] async-io = { workspace = true, optional = true } -async-std = { workspace = true, optional = true } bytes = { workspace = true } # Enables futures::io::{AsyncRead, AsyncWrite} support for streams futures-io = { workspace = true, optional = true } diff --git a/quinn/src/lib.rs b/quinn/src/lib.rs index 82becdb1d..0aff67922 100644 --- a/quinn/src/lib.rs +++ b/quinn/src/lib.rs @@ -81,8 +81,6 @@ pub use crate::connection::{ pub use crate::endpoint::{Accept, Endpoint, EndpointStats}; pub use crate::incoming::{Incoming, IncomingFuture, RetryError}; pub use crate::recv_stream::{ReadError, ReadExactError, ReadToEndError, RecvStream, ResetError}; -#[cfg(feature = "runtime-async-std")] -pub use crate::runtime::AsyncStdRuntime; #[cfg(feature = "runtime-smol")] pub use crate::runtime::SmolRuntime; #[cfg(feature = "runtime-tokio")] diff --git a/quinn/src/runtime.rs b/quinn/src/runtime.rs index c583affc1..48c27c8f9 100644 --- a/quinn/src/runtime.rs +++ b/quinn/src/runtime.rs @@ -116,11 +116,7 @@ impl UdpPollHelper { /// Construct a [`UdpPoller`] that calls `make_fut` to get the future to poll, storing it until /// it yields [`Poll::Ready`], then creating a new one on the next /// [`poll_writable`](UdpPoller::poll_writable) - #[cfg(any( - feature = "runtime-async-std", - feature = "runtime-smol", - feature = "runtime-tokio", - ))] + #[cfg(any(feature = "runtime-smol", feature = "runtime-tokio",))] fn new(make_fut: MakeFut) -> Self { Self { make_fut, @@ -174,17 +170,12 @@ pub fn default_runtime() -> Option> { } } - #[cfg(feature = "runtime-async-std")] - { - return Some(Arc::new(AsyncStdRuntime)); - } - - #[cfg(all(feature = "runtime-smol", not(feature = "runtime-async-std")))] + #[cfg(feature = "runtime-smol")] { return Some(Arc::new(SmolRuntime)); } - #[cfg(not(any(feature = "runtime-async-std", feature = "runtime-smol")))] + #[cfg(not(feature = "runtime-smol"))] None } @@ -197,5 +188,5 @@ pub use self::tokio::TokioRuntime; #[cfg(feature = "async-io")] mod async_io; // Due to MSRV, we must specify `self::` where there's crate/module ambiguity -#[cfg(any(feature = "runtime-smol", feature = "runtime-async-std"))] +#[cfg(feature = "runtime-smol")] pub use self::async_io::*; diff --git a/quinn/src/runtime/async_io.rs b/quinn/src/runtime/async_io.rs index ab26bdb71..5ebcd3230 100644 --- a/quinn/src/runtime/async_io.rs +++ b/quinn/src/runtime/async_io.rs @@ -4,15 +4,15 @@ use std::{ task::{Context, Poll}, time::Instant, }; -#[cfg(any(feature = "runtime-smol", feature = "runtime-async-std"))] +#[cfg(feature = "runtime-smol")] use std::{io, sync::Arc, task::ready}; -#[cfg(any(feature = "runtime-smol", feature = "runtime-async-std"))] +#[cfg(feature = "runtime-smol")] use async_io::Async; use async_io::Timer; use super::AsyncTimer; -#[cfg(any(feature = "runtime-smol", feature = "runtime-async-std"))] +#[cfg(feature = "runtime-smol")] use super::{AsyncUdpSocket, Runtime, UdpPollHelper}; #[cfg(feature = "runtime-smol")] @@ -45,36 +45,6 @@ mod smol { } } -#[cfg(feature = "runtime-async-std")] -// Due to MSRV, we must specify `self::` where there's crate/module ambiguity -pub use self::async_std::AsyncStdRuntime; - -#[cfg(feature = "runtime-async-std")] -mod async_std { - use super::*; - - /// A Quinn runtime for async-std - #[derive(Debug)] - pub struct AsyncStdRuntime; - - impl Runtime for AsyncStdRuntime { - fn new_timer(&self, t: Instant) -> Pin> { - Box::pin(Timer::at(t)) - } - - fn spawn(&self, future: Pin + Send>>) { - ::async_std::task::spawn(future); - } - - fn wrap_udp_socket( - &self, - sock: std::net::UdpSocket, - ) -> io::Result> { - Ok(Arc::new(UdpSocket::new(sock)?)) - } - } -} - impl AsyncTimer for Timer { fn reset(mut self: Pin<&mut Self>, t: Instant) { self.set_at(t) @@ -85,14 +55,14 @@ impl AsyncTimer for Timer { } } -#[cfg(any(feature = "runtime-smol", feature = "runtime-async-std"))] +#[cfg(feature = "runtime-smol")] #[derive(Debug)] struct UdpSocket { io: Async, inner: udp::UdpSocketState, } -#[cfg(any(feature = "runtime-smol", feature = "runtime-async-std"))] +#[cfg(feature = "runtime-smol")] impl UdpSocket { fn new(sock: std::net::UdpSocket) -> io::Result { Ok(Self { @@ -102,7 +72,7 @@ impl UdpSocket { } } -#[cfg(any(feature = "runtime-smol", feature = "runtime-async-std"))] +#[cfg(feature = "runtime-smol")] impl AsyncUdpSocket for UdpSocket { fn create_io_poller(self: Arc) -> Pin> { Box::pin(UdpPollHelper::new(move || { From 0e5834ca32916ff804ee731dcaa4e779c72bcbd3 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 1 Sep 2025 10:00:37 +0200 Subject: [PATCH 10/71] Remove more traces of async-std --- .github/workflows/codecov.yml | 2 +- Cargo.toml | 1 - quinn/Cargo.toml | 2 +- quinn/src/runtime.rs | 5 ++--- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index e00778632..8a9ddab56 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -27,7 +27,7 @@ jobs: # | paste -sd ',' - run: | cargo llvm-cov \ - --features="arbitrary,async-io,async-std,aws-lc-rs,bloom,direct-log,fast-apple-datapath,futures-io,json-output,lock_tracking,log,platform-verifier,qlog,ring,runtime-async-std,runtime-smol,runtime-tokio,rustls,rustls-aws-lc-rs,rustls-log,rustls-ring,serde,serde_json,smol,tracing" \ + --features="arbitrary,async-io,aws-lc-rs,bloom,direct-log,fast-apple-datapath,futures-io,json-output,lock_tracking,log,platform-verifier,qlog,ring,runtime-smol,runtime-tokio,rustls,rustls-aws-lc-rs,rustls-log,rustls-ring,serde,serde_json,smol,tracing" \ --workspace --lcov --output-path lcov.info - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/Cargo.toml b/Cargo.toml index dcb32cd5c..9dce26b74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ categories = ["network-programming", "asynchronous"] anyhow = "1.0.22" arbitrary = { version = "1.0.1", features = ["derive"] } async-io = "2" -async-std = "1.11" assert_matches = "1.1" aws-lc-rs = { version = "1.9", default-features = false } bencher = "0.1.5" diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 8b8e04618..9b7dbaf40 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -119,4 +119,4 @@ required-features = ["rustls-ring"] [package.metadata.docs.rs] # 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"] +features = ["lock_tracking", "rustls-aws-lc-rs", "rustls-ring", "runtime-tokio", "runtime-smol", "log", "rustls-log"] diff --git a/quinn/src/runtime.rs b/quinn/src/runtime.rs index 48c27c8f9..e2ba7c60a 100644 --- a/quinn/src/runtime.rs +++ b/quinn/src/runtime.rs @@ -158,9 +158,8 @@ impl Debug for UdpPollHelper { /// Automatically select an appropriate runtime from those enabled at compile time /// /// If `runtime-tokio` is enabled and this function is called from within a Tokio runtime context, -/// then `TokioRuntime` is returned. Otherwise, if `runtime-async-std` is enabled, `AsyncStdRuntime` -/// is returned. Otherwise, if `runtime-smol` is enabled, `SmolRuntime` is returned. -/// Otherwise, `None` is returned. +/// then `TokioRuntime` is returned. Otherwise, if `runtime-smol` is enabled, `SmolRuntime` is +/// returned. Otherwise, `None` is returned. #[allow(clippy::needless_return)] // Be sure we return the right thing pub fn default_runtime() -> Option> { #[cfg(feature = "runtime-tokio")] From e89d7585d4e68bbe1bd5fb740e3d6894457b01b6 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 31 Aug 2025 14:55:06 -0700 Subject: [PATCH 11/71] Strongly typed burst interval --- quinn-proto/src/connection/pacing.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/quinn-proto/src/connection/pacing.rs b/quinn-proto/src/connection/pacing.rs index 2e469948c..bf709aa87 100644 --- a/quinn-proto/src/connection/pacing.rs +++ b/quinn-proto/src/connection/pacing.rs @@ -129,7 +129,7 @@ impl Pacer { fn optimal_capacity(smoothed_rtt: Duration, window: u64, mtu: u16) -> u64 { let rtt = smoothed_rtt.as_nanos().max(1); - let capacity = ((window as u128 * BURST_INTERVAL_NANOS) / rtt) as u64; + let capacity = ((window as u128 * BURST_INTERVAL.as_nanos()) / rtt) as u64; // Small bursts are less efficient (no GSO), could increase latency and don't effectively // use the channel's buffer capacity. Large bursts might block the connection on sending. @@ -142,7 +142,7 @@ fn optimal_capacity(smoothed_rtt: Duration, window: u64, mtu: u16) -> u64 { /// 2ms is chosen here since framework timers might have 1ms precision. /// If kernel-level pacing is supported later a higher time here might be /// more applicable. -const BURST_INTERVAL_NANOS: u128 = 2_000_000; // 2ms +const BURST_INTERVAL: Duration = Duration::from_millis(2); /// Allows some usage of GSO, and doesn't slow down the handshake. const MIN_BURST_SIZE: u64 = 10; @@ -187,7 +187,7 @@ mod tests { let pacer = Pacer::new(rtt, window, mtu, now); assert_eq!( pacer.capacity, - (window as u128 * BURST_INTERVAL_NANOS / rtt.as_nanos()) as u64 + (window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, pacer.capacity); @@ -210,7 +210,7 @@ mod tests { let mut pacer = Pacer::new(rtt, window, mtu, now); assert_eq!( pacer.capacity, - (window as u128 * BURST_INTERVAL_NANOS / rtt.as_nanos()) as u64 + (window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, pacer.capacity); let initial_tokens = pacer.tokens; @@ -218,21 +218,21 @@ mod tests { pacer.delay(rtt, mtu as u64, mtu, window * 2, now); assert_eq!( pacer.capacity, - (2 * window as u128 * BURST_INTERVAL_NANOS / rtt.as_nanos()) as u64 + (2 * window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, initial_tokens); pacer.delay(rtt, mtu as u64, mtu, window / 2, now); assert_eq!( pacer.capacity, - (window as u128 / 2 * BURST_INTERVAL_NANOS / rtt.as_nanos()) as u64 + (window as u128 / 2 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, initial_tokens / 2); pacer.delay(rtt, mtu as u64, mtu * 2, window, now); assert_eq!( pacer.capacity, - (window as u128 * BURST_INTERVAL_NANOS / rtt.as_nanos()) as u64 + (window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); pacer.delay(rtt, mtu as u64, 20_000, window, now); @@ -259,7 +259,7 @@ mod tests { pacer.on_transmit(mtu); } - let pace_duration = Duration::from_nanos((BURST_INTERVAL_NANOS * 4 / 5) as u64); + let pace_duration = Duration::from_nanos((BURST_INTERVAL.as_nanos() * 4 / 5) as u64); assert_eq!( pacer From 719fc367f3cbc4a110d6c324dca9d94dc626f9d8 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Mon, 1 Sep 2025 12:18:51 -0700 Subject: [PATCH 12/71] Rename BURST_INTERVAL to TARGET_BURST_INTERVAL --- quinn-proto/src/connection/pacing.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/quinn-proto/src/connection/pacing.rs b/quinn-proto/src/connection/pacing.rs index bf709aa87..ca9909005 100644 --- a/quinn-proto/src/connection/pacing.rs +++ b/quinn-proto/src/connection/pacing.rs @@ -129,7 +129,7 @@ impl Pacer { fn optimal_capacity(smoothed_rtt: Duration, window: u64, mtu: u16) -> u64 { let rtt = smoothed_rtt.as_nanos().max(1); - let capacity = ((window as u128 * BURST_INTERVAL.as_nanos()) / rtt) as u64; + let capacity = ((window as u128 * TARGET_BURST_INTERVAL.as_nanos()) / rtt) as u64; // Small bursts are less efficient (no GSO), could increase latency and don't effectively // use the channel's buffer capacity. Large bursts might block the connection on sending. @@ -142,7 +142,7 @@ fn optimal_capacity(smoothed_rtt: Duration, window: u64, mtu: u16) -> u64 { /// 2ms is chosen here since framework timers might have 1ms precision. /// If kernel-level pacing is supported later a higher time here might be /// more applicable. -const BURST_INTERVAL: Duration = Duration::from_millis(2); +const TARGET_BURST_INTERVAL: Duration = Duration::from_millis(2); /// Allows some usage of GSO, and doesn't slow down the handshake. const MIN_BURST_SIZE: u64 = 10; @@ -187,7 +187,7 @@ mod tests { let pacer = Pacer::new(rtt, window, mtu, now); assert_eq!( pacer.capacity, - (window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 + (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, pacer.capacity); @@ -210,7 +210,7 @@ mod tests { let mut pacer = Pacer::new(rtt, window, mtu, now); assert_eq!( pacer.capacity, - (window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 + (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, pacer.capacity); let initial_tokens = pacer.tokens; @@ -218,21 +218,21 @@ mod tests { pacer.delay(rtt, mtu as u64, mtu, window * 2, now); assert_eq!( pacer.capacity, - (2 * window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 + (2 * window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, initial_tokens); pacer.delay(rtt, mtu as u64, mtu, window / 2, now); assert_eq!( pacer.capacity, - (window as u128 / 2 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 + (window as u128 / 2 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); assert_eq!(pacer.tokens, initial_tokens / 2); pacer.delay(rtt, mtu as u64, mtu * 2, window, now); assert_eq!( pacer.capacity, - (window as u128 * BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 + (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64 ); pacer.delay(rtt, mtu as u64, 20_000, window, now); @@ -259,7 +259,7 @@ mod tests { pacer.on_transmit(mtu); } - let pace_duration = Duration::from_nanos((BURST_INTERVAL.as_nanos() * 4 / 5) as u64); + let pace_duration = Duration::from_nanos((TARGET_BURST_INTERVAL.as_nanos() * 4 / 5) as u64); assert_eq!( pacer From ecb72da1880ba0c1a4ef76bea1175b1bb40dacfc Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 31 Aug 2025 14:52:14 -0700 Subject: [PATCH 13/71] Limit pacing batch size to 10ms of traffic --- quinn-proto/src/connection/pacing.rs | 35 ++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/quinn-proto/src/connection/pacing.rs b/quinn-proto/src/connection/pacing.rs index ca9909005..d4ff8e174 100644 --- a/quinn-proto/src/connection/pacing.rs +++ b/quinn-proto/src/connection/pacing.rs @@ -128,23 +128,34 @@ impl Pacer { /// Too long burst intervals make pacing less effective. fn optimal_capacity(smoothed_rtt: Duration, window: u64, mtu: u16) -> u64 { let rtt = smoothed_rtt.as_nanos().max(1); + let mtu = u64::from(mtu); - let capacity = ((window as u128 * TARGET_BURST_INTERVAL.as_nanos()) / rtt) as u64; + let target_capacity = ((window as u128 * TARGET_BURST_INTERVAL.as_nanos()) / rtt) as u64; + // Never restrict capacity below one MTU. + let max_capacity = Ord::max( + ((window as u128 * MAX_BURST_INTERVAL.as_nanos()) / rtt) as u64, + mtu, + ); - // Small bursts are less efficient (no GSO), could increase latency and don't effectively - // use the channel's buffer capacity. Large bursts might block the connection on sending. - capacity.clamp(MIN_BURST_SIZE * mtu as u64, MAX_BURST_SIZE * mtu as u64) + // Batch the greater of `TARGET_BURST_INTERVAL` or `MIN_BURST_SIZE` worth of traffic at a + // time. To avoid inducing excessive latency, limit that result to at most `MAX_BURST_INTERVAL` + // worth of traffic. + Ord::min( + max_capacity, + target_capacity.clamp(MIN_BURST_SIZE * mtu, MAX_BURST_SIZE * mtu), + ) } -/// The burst interval -/// -/// The capacity will we refilled in 4/5 of that time. -/// 2ms is chosen here since framework timers might have 1ms precision. -/// If kernel-level pacing is supported later a higher time here might be -/// more applicable. +/// Period of traffic to batch together on a reasonably fast connection const TARGET_BURST_INTERVAL: Duration = Duration::from_millis(2); -/// Allows some usage of GSO, and doesn't slow down the handshake. +/// Maximum period of traffic to batch together on a slow connection +/// +/// Takes precedence over [`MIN_BURST_SIZE`]. +const MAX_BURST_INTERVAL: Duration = Duration::from_millis(10); + +/// Minimum number of datagrams to batch together, so long as we won't have to wait for more than +/// [`MAX_BURST_INTERVAL`] const MIN_BURST_SIZE: u64 = 10; /// Creating 256 packets took 1ms in a benchmark, so larger bursts don't make sense. @@ -196,7 +207,7 @@ mod tests { assert_eq!(pacer.tokens, pacer.capacity); let pacer = Pacer::new(rtt, 1, mtu, now); - assert_eq!(pacer.capacity, MIN_BURST_SIZE * mtu as u64); + assert_eq!(pacer.capacity, mtu as u64); assert_eq!(pacer.tokens, pacer.capacity); } From 2f5df7c35016c5692ec45b739c7ba01b11bb5212 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 31 Aug 2025 15:36:44 -0700 Subject: [PATCH 14/71] Reduce pacing in fragile tests --- quinn-proto/src/tests/mod.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/quinn-proto/src/tests/mod.rs b/quinn-proto/src/tests/mod.rs index 1ecb39812..d4645e35c 100644 --- a/quinn-proto/src/tests/mod.rs +++ b/quinn-proto/src/tests/mod.rs @@ -685,10 +685,17 @@ fn test_zero_rtt_incoming_limit(configure_server: const EXPECTED_DROPPED: u64 = 4; let _guard = subscribe(); + + let mut transport = TransportConfig::default(); + // Assume a low-latency connection so pacing doesn't interfere with the test + transport.initial_rtt(Duration::from_millis(10)); + let transport = Arc::new(transport); + let mut server_config = server_config(); configure_server(&mut server_config); let mut pair = Pair::new(Arc::new(EndpointConfig::default()), server_config); - let config = client_config(); + let mut config = client_config(); + config.transport_config(transport); // Establish normal connection let client_ch = pair.begin_connect(config.clone()); @@ -2185,9 +2192,14 @@ fn handshake_anti_deadlock_probe() { #[test] fn server_can_send_3_inital_packets() { let _guard = subscribe(); + let mut transport = TransportConfig::default(); + // Assume a low-latency connection so pacing doesn't interfere with the test + transport.initial_rtt(Duration::from_millis(10)); + let transport = Arc::new(transport); let (cert, key) = big_cert_and_key(); - let server = server_config_with_cert(cert.clone(), key); + let mut server = server_config_with_cert(cert.clone(), key); + server.transport_config(transport); let client = client_config_with_certs(vec![cert]); let mut pair = Pair::new(Default::default(), server); @@ -2716,7 +2728,8 @@ fn setup_ack_frequency_test(max_ack_delay: Duration) -> (Pair, ConnectionHandle, Arc::get_mut(&mut client_config.transport) .unwrap() .ack_frequency_config(Some(ack_freq_config)) - .mtu_discovery_config(None); // To keep traffic cleaner + .mtu_discovery_config(None) // To keep traffic cleaner + .initial_rtt(Duration::from_millis(10)); // To avoid delays from pacing let mut pair = Pair::default_with_deterministic_pns(); pair.latency = Duration::from_millis(10); // Need latency to avoid an RTT = 0 From 1c44dba9563850483db6132872afd6eb01327373 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 31 Aug 2025 15:59:33 -0700 Subject: [PATCH 15/71] Improve numerical stability of Pacer::delay --- quinn-proto/src/connection/pacing.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/quinn-proto/src/connection/pacing.rs b/quinn-proto/src/connection/pacing.rs index d4ff8e174..39815606b 100644 --- a/quinn-proto/src/connection/pacing.rs +++ b/quinn-proto/src/connection/pacing.rs @@ -89,13 +89,14 @@ impl Pacer { } let elapsed_rtts = time_elapsed.as_secs_f64() / smoothed_rtt.as_secs_f64(); - let new_tokens = window as f64 * 1.25 * elapsed_rtts; - self.tokens = self - .tokens - .saturating_add(new_tokens as _) - .min(self.capacity); + let new_tokens = (window as f64 * 1.25 * elapsed_rtts).round() as u64; + self.tokens = self.tokens.saturating_add(new_tokens).min(self.capacity); - self.prev = now; + // In the unlikely event that we're getting polled faster than tokens are generated, ensure + // that `elapsed_rtts` can grow until we make progress. + if new_tokens > 0 { + self.prev = now; + } // if we can already send a packet, there is no need for delay if self.tokens >= bytes_to_send { @@ -109,7 +110,7 @@ impl Pacer { // divisions come before multiplications to prevent overflow // this is the time at which the pacing window becomes empty - Some(self.prev + (unscaled_delay / 5) * 4) + Some(now + (unscaled_delay / 5) * 4) } } From 80b8ffdb4b410df83f0921a6d39d0b782a7e84d4 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 2 Sep 2025 13:40:08 +0200 Subject: [PATCH 16/71] Use newer rustls-pki-types PEM parser API --- Cargo.lock | 11 ----------- Cargo.toml | 1 - perf/Cargo.toml | 1 - perf/src/server.rs | 25 +++++++++++-------------- quinn/Cargo.toml | 1 - quinn/examples/server.rs | 21 ++++++++++++--------- 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8945f5bc9..883e91edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1758,7 +1758,6 @@ dependencies = [ "quinn-proto", "rcgen", "rustls", - "rustls-pemfile", "serde", "serde_json", "socket2 0.6.0", @@ -1931,7 +1930,6 @@ dependencies = [ "rcgen", "rustc-hash 2.1.1", "rustls", - "rustls-pemfile", "smol", "socket2 0.6.0", "thiserror 2.0.16", @@ -2220,15 +2218,6 @@ dependencies = [ "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.12.0" diff --git a/Cargo.toml b/Cargo.toml index 9dce26b74..aa5825413 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,6 @@ rcgen = "0.14" ring = "0.17" rustc-hash = "2" rustls = { version = "0.23.5", default-features = false, features = ["std"] } -rustls-pemfile = "2" rustls-platform-verifier = "0.6" rustls-pki-types = "1.7" serde = { version = "1.0", features = ["derive"] } diff --git a/perf/Cargo.toml b/perf/Cargo.toml index 08cec0302..2cdb1586c 100644 --- a/perf/Cargo.toml +++ b/perf/Cargo.toml @@ -34,7 +34,6 @@ quinn = { path = "../quinn" } quinn-proto = { path = "../quinn-proto" } rcgen = { workspace = true } rustls = { workspace = true } -rustls-pemfile = { workspace = true } serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } socket2 = { workspace = true } diff --git a/perf/src/server.rs b/perf/src/server.rs index 040b942f7..18d1a4d8e 100644 --- a/perf/src/server.rs +++ b/perf/src/server.rs @@ -1,10 +1,10 @@ -use std::{fs, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; +use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; use anyhow::{Context, Result}; use bytes::Bytes; use clap::Parser; use quinn::{TokioRuntime, crypto::rustls::QuicServerConfig}; -use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer}; +use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, pem::PemObject}; use tracing::{debug, error, info}; use crate::{CommonOpt, PERF_CIPHER_SUITES, noprotection::NoProtectionServerConfig}; @@ -28,20 +28,17 @@ pub struct Opt { pub async fn run(opt: Opt) -> Result<()> { let (key, cert) = match (&opt.key, &opt.cert) { - (Some(key), Some(cert)) => { - let key = fs::read(key).context("reading key")?; - let cert = fs::read(cert).expect("reading cert"); - ( - PrivatePkcs8KeyDer::from(key), - rustls_pemfile::certs(&mut cert.as_ref()) - .collect::>() - .context("parsing cert")?, - ) - } + (Some(key), Some(cert)) => ( + PrivateKeyDer::from_pem_file(key).context("reading private key")?, + CertificateDer::pem_file_iter(cert) + .context("reading certificate chain file")? + .collect::>() + .context("reading certificate chain")?, + ), _ => { let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); ( - PrivatePkcs8KeyDer::from(cert.signing_key.serialize_der()), + PrivatePkcs8KeyDer::from(cert.signing_key.serialize_der()).into(), vec![CertificateDer::from(cert.cert)], ) } @@ -57,7 +54,7 @@ pub async fn run(opt: Opt) -> Result<()> { .with_protocol_versions(&[&rustls::version::TLS13]) .unwrap() .with_no_client_auth() - .with_single_cert(cert, key.into()) + .with_single_cert(cert, key) .unwrap(); crypto.alpn_protocols = vec![b"perf".to_vec()]; diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 9b7dbaf40..d40232aff 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -78,7 +78,6 @@ bencher = { workspace = true } directories-next = { workspace = true } rand = { workspace = true } rcgen = { workspace = true } -rustls-pemfile = { workspace = true } clap = { workspace = true } tokio = { workspace = true, features = ["rt", "rt-multi-thread", "time", "macros"] } tracing-subscriber = { workspace = true } diff --git a/quinn/examples/server.rs b/quinn/examples/server.rs index 298562f3e..3f0b6740f 100644 --- a/quinn/examples/server.rs +++ b/quinn/examples/server.rs @@ -13,7 +13,7 @@ use std::{ use anyhow::{Context, Result, anyhow, bail}; use clap::Parser; use proto::crypto::rustls::QuicServerConfig; -use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; +use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, pem::PemObject}; use tracing::{error, info, info_span}; use tracing_futures::Instrument as _; @@ -69,19 +69,22 @@ fn main() { #[tokio::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().is_some_and(|x| x == "der") { - PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(key)) + PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( + fs::read(key_path).context("failed to read private key file")?, + )) } else { - rustls_pemfile::private_key(&mut &*key) - .context("malformed PKCS #1 private key")? - .ok_or_else(|| anyhow::Error::msg("no private keys found"))? + PrivateKeyDer::from_pem_file(key_path) + .context("failed to read PEM from private key file")? }; - let cert_chain = fs::read(cert_path).context("failed to read certificate chain")?; + let cert_chain = if cert_path.extension().is_some_and(|x| x == "der") { - vec![CertificateDer::from(cert_chain)] + vec![CertificateDer::from( + fs::read(cert_path).context("failed to read certificate chain file")?, + )] } else { - rustls_pemfile::certs(&mut &*cert_chain) + CertificateDer::pem_file_iter(cert_path) + .context("failed to read PEM from certificate chain file")? .collect::>() .context("invalid PEM-encoded certificate")? }; From 377af28843a8e05e6c2d73798f1e9cbc30796531 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 22 Jul 2024 09:48:58 +0200 Subject: [PATCH 17/71] refactor!: rename log feature to tracing-log Previously `quinn*` would provide the `log` feature to log events via `log` if no `tracing` subscriber exists. Later https://github.com/quinn-rs/quinn/pull/1923 allowed `quinn-udp` to log via `log` directly, making `tracing` an optional dependency. For that, it introduced the `direct-log` feature, a workaround name in order to not introduce a breaking change. This commit cleans up the above, renaming the `log` feature to `tracing-log` and the `direct-log` to `log`. This is a breaking change and thus `quinn-udp` is bumped to `v0.6.0`. See https://github.com/quinn-rs/quinn/pull/1921 for the full history. --- .github/workflows/codecov.yml | 2 +- .github/workflows/rust.yml | 2 +- quinn-proto/Cargo.toml | 4 ++-- quinn-udp/Cargo.toml | 6 +++--- quinn-udp/src/lib.rs | 12 ++++++------ quinn/Cargo.toml | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 8a9ddab56..210355eb4 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -27,7 +27,7 @@ jobs: # | paste -sd ',' - run: | cargo llvm-cov \ - --features="arbitrary,async-io,aws-lc-rs,bloom,direct-log,fast-apple-datapath,futures-io,json-output,lock_tracking,log,platform-verifier,qlog,ring,runtime-smol,runtime-tokio,rustls,rustls-aws-lc-rs,rustls-log,rustls-ring,serde,serde_json,smol,tracing" \ + --features="arbitrary,async-io,aws-lc-rs,bloom,log,fast-apple-datapath,futures-io,json-output,lock_tracking,tracing-log,platform-verifier,qlog,ring,runtime-smol,runtime-tokio,rustls,rustls-aws-lc-rs,rustls-log,rustls-ring,serde,serde_json,smol,tracing" \ --workspace --lcov --output-path lcov.info - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index dd23c71f9..dde8bc727 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -163,7 +163,7 @@ jobs: - run: cargo test --locked -p quinn-proto --target wasm32-unknown-unknown --no-run - run: cargo check --locked -p quinn-udp --target wasm32-unknown-unknown --no-default-features --features=tracing,log - - run: cargo rustc --locked -p quinn --target wasm32-unknown-unknown --no-default-features --features=log,platform-verifier,rustls-ring --crate-type=cdylib + - run: cargo rustc --locked -p quinn --target wasm32-unknown-unknown --no-default-features --features=tracing-log,platform-verifier,rustls-ring --crate-type=cdylib # If the Wasm file contains any 'import "env"' declarations, then # some non-Wasm-compatible code made it into the final code. diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index 9412dada1..1b038eaf8 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -13,7 +13,7 @@ workspace = ".." [features] # NOTE: Please keep this in sync with the feature list in `.github/workflows/codecov.yml`, see # comment in that file for more information. -default = ["rustls-ring", "log", "bloom"] +default = ["rustls-ring", "tracing-log", "bloom"] aws-lc-rs = ["dep:aws-lc-rs", "aws-lc-rs?/aws-lc-sys", "aws-lc-rs?/prebuilt-nasm"] aws-lc-rs-fips = ["aws-lc-rs", "aws-lc-rs?/fips"] # Enables BloomTokenLog, and uses it by default @@ -30,7 +30,7 @@ ring = ["dep:ring"] # Provides `ClientConfig::with_platform_verifier()` convenience method platform-verifier = ["dep:rustls-platform-verifier"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. -log = ["tracing/log"] +tracing-log = ["tracing/log"] # Enable rustls logging rustls-log = ["rustls?/logging"] # Enable qlog support diff --git a/quinn-udp/Cargo.toml b/quinn-udp/Cargo.toml index f55c1b5af..75348be1a 100644 --- a/quinn-udp/Cargo.toml +++ b/quinn-udp/Cargo.toml @@ -13,10 +13,10 @@ workspace = ".." [features] # NOTE: Please keep this in sync with the feature list in `.github/workflows/codecov.yml`, see # comment in that file for more information. -default = ["tracing", "log"] +default = ["tracing", "tracing-log"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. -log = ["tracing/log"] -direct-log = ["dep:log"] +tracing-log = ["tracing/log"] +log = ["dep:log"] # Use private Apple APIs to send multiple packets in a single syscall. fast-apple-datapath = [] diff --git a/quinn-udp/src/lib.rs b/quinn-udp/src/lib.rs index 0f69070f6..f93578b9a 100644 --- a/quinn-udp/src/lib.rs +++ b/quinn-udp/src/lib.rs @@ -56,13 +56,13 @@ mod imp; #[allow(unused_imports, unused_macros)] mod log { - #[cfg(all(feature = "direct-log", not(feature = "tracing")))] + #[cfg(all(feature = "log", not(feature = "tracing-log")))] pub(crate) use log::{debug, error, info, trace, warn}; - #[cfg(feature = "tracing")] + #[cfg(feature = "tracing-log")] pub(crate) use tracing::{debug, error, info, trace, warn}; - #[cfg(not(any(feature = "direct-log", feature = "tracing")))] + #[cfg(not(any(feature = "log", feature = "tracing-log")))] mod no_op { macro_rules! trace ( ($($tt:tt)*) => {{}} ); macro_rules! debug ( ($($tt:tt)*) => {{}} ); @@ -73,7 +73,7 @@ mod log { pub(crate) use {debug, error, info, log_warn as warn, trace}; } - #[cfg(not(any(feature = "direct-log", feature = "tracing")))] + #[cfg(not(any(feature = "log", feature = "tracing-log")))] pub(crate) use no_op::*; } @@ -154,7 +154,7 @@ const IO_ERROR_LOG_INTERVAL: Duration = std::time::Duration::from_secs(60); /// /// Logging will only be performed if at least [`IO_ERROR_LOG_INTERVAL`] /// has elapsed since the last error was logged. -#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))] +#[cfg(all(not(wasm_browser), any(feature = "tracing-log", feature = "log")))] fn log_sendmsg_error( last_send_error: &Mutex, err: impl core::fmt::Debug, @@ -177,7 +177,7 @@ fn log_sendmsg_error( } // No-op -#[cfg(not(any(wasm_browser, feature = "tracing", feature = "direct-log")))] +#[cfg(not(any(wasm_browser, feature = "tracing-log", feature = "log")))] fn log_sendmsg_error(_: &Mutex, _: impl core::fmt::Debug, _: &Transmit) {} /// A borrowed UDP socket diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index d40232aff..81869bcfc 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -15,7 +15,7 @@ rust-version.workspace = true [features] # NOTE: Please keep this in sync with the feature list in `.github/workflows/codecov.yml`, see # comment in that file for more information. -default = ["log", "platform-verifier", "runtime-tokio", "rustls-ring", "bloom"] +default = ["tracing-log", "platform-verifier", "runtime-tokio", "rustls-ring", "bloom"] # Enables `Endpoint::client` and `Endpoint::server` conveniences aws-lc-rs = ["proto/aws-lc-rs"] aws-lc-rs-fips = ["proto/aws-lc-rs-fips"] @@ -39,7 +39,7 @@ runtime-tokio = ["tokio/time", "tokio/rt", "tokio/net"] runtime-smol = ["async-io", "smol"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. -log = ["tracing/log", "proto/log", "udp/log"] +tracing-log = ["tracing/log", "proto/tracing-log", "udp/tracing-log"] # Enable rustls logging rustls-log = ["rustls?/logging"] # Enable qlog support @@ -118,4 +118,4 @@ required-features = ["rustls-ring"] [package.metadata.docs.rs] # all non-default features except fips (cannot build on docs.rs environment) -features = ["lock_tracking", "rustls-aws-lc-rs", "rustls-ring", "runtime-tokio", "runtime-smol", "log", "rustls-log"] +features = ["lock_tracking", "rustls-aws-lc-rs", "rustls-ring", "runtime-tokio", "runtime-smol", "tracing-log", "rustls-log"] From aa2d7736ded46ff09d14fd84eaedc485439efb10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Kr=C3=BCger?= Date: Thu, 5 Jun 2025 14:35:42 +0200 Subject: [PATCH 18/71] Refactor `UdpPoller` into `UdpSender` and use it in favor of `AsyncUdpSocket` in connections --- quinn/src/connection.rs | 51 ++++----- quinn/src/endpoint.rs | 89 +++++++++++----- quinn/src/lib.rs | 6 +- quinn/src/runtime.rs | 189 ++++++++++++++++++++++------------ quinn/src/runtime/async_io.rs | 28 +++-- quinn/src/runtime/tokio.rs | 27 +++-- 6 files changed, 244 insertions(+), 146 deletions(-) diff --git a/quinn/src/connection.rs b/quinn/src/connection.rs index ca2014b6d..ab3777d71 100644 --- a/quinn/src/connection.rs +++ b/quinn/src/connection.rs @@ -20,7 +20,7 @@ use crate::{ ConnectionEvent, Duration, Instant, VarInt, mutex::Mutex, recv_stream::RecvStream, - runtime::{AsyncTimer, AsyncUdpSocket, Runtime, UdpPoller}, + runtime::{AsyncTimer, Runtime, UdpSender}, send_stream::SendStream, udp_transmit, }; @@ -43,7 +43,7 @@ impl Connecting { conn: proto::Connection, endpoint_events: mpsc::UnboundedSender<(ConnectionHandle, EndpointEvent)>, conn_events: mpsc::UnboundedReceiver, - socket: Arc, + sender: Pin>, runtime: Arc, ) -> Self { let (on_handshake_data_send, on_handshake_data_recv) = oneshot::channel(); @@ -55,7 +55,7 @@ impl Connecting { conn_events, on_handshake_data_send, on_connected_send, - socket, + sender, runtime.clone(), ); @@ -882,7 +882,7 @@ impl ConnectionRef { conn_events: mpsc::UnboundedReceiver, on_handshake_data: oneshot::Sender<()>, on_connected: oneshot::Sender, - socket: Arc, + sender: Pin>, runtime: Arc, ) -> Self { Self(Arc::new(ConnectionInner { @@ -902,8 +902,7 @@ impl ConnectionRef { stopped: FxHashMap::default(), error: None, ref_count: 0, - io_poller: socket.clone().create_io_poller(), - socket, + sender, runtime, send_buffer: Vec::new(), buffered_transmit: None, @@ -983,8 +982,7 @@ pub(crate) struct State { pub(crate) error: Option, /// Number of live handles that can be used to initiate or handle I/O; excludes the driver ref_count: usize, - socket: Arc, - io_poller: Pin>, + sender: Pin>, runtime: Arc, send_buffer: Vec, /// We buffer a transmit when the underlying I/O would block @@ -997,7 +995,7 @@ impl State { let mut transmits = 0; let max_datagrams = self - .socket + .sender .max_transmit_segments() .min(MAX_TRANSMIT_SEGMENTS); @@ -1024,28 +1022,18 @@ impl State { } }; - if self.io_poller.as_mut().poll_writable(cx)?.is_pending() { - // Retry after a future wakeup - self.buffered_transmit = Some(t); - return Ok(false); - } - let len = t.size; - let retry = match self - .socket - .try_send(&udp_transmit(&t, &self.send_buffer[..len])) + match self + .sender + .as_mut() + .poll_send(&udp_transmit(&t, &self.send_buffer[..len]), cx) { - Ok(()) => false, - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => true, - Err(e) => return Err(e), - }; - if retry { - // We thought the socket was writable, but it wasn't. Retry so that either another - // `poll_writable` call determines that the socket is indeed not writable and - // registers us for a wakeup, or the send succeeds if this really was just a - // transient failure. - self.buffered_transmit = Some(t); - continue; + Poll::Pending => { + self.buffered_transmit = Some(t); + return Ok(false); + } + Poll::Ready(Err(e)) => return Err(e), + Poll::Ready(Ok(())) => {} } if transmits >= MAX_TRANSMIT_DATAGRAMS { @@ -1075,9 +1063,8 @@ impl State { ) -> Result<(), ConnectionError> { loop { match self.conn_events.poll_recv(cx) { - Poll::Ready(Some(ConnectionEvent::Rebind(socket))) => { - self.socket = socket; - self.io_poller = self.socket.clone().create_io_poller(); + Poll::Ready(Some(ConnectionEvent::Rebind(sender))) => { + self.sender = sender; self.inner.local_address_changed(); } Poll::Ready(Some(ConnectionEvent::Proto(event))) => { diff --git a/quinn/src/endpoint.rs b/quinn/src/endpoint.rs index d6879d22f..d1bdd23b3 100644 --- a/quinn/src/endpoint.rs +++ b/quinn/src/endpoint.rs @@ -2,21 +2,20 @@ use std::{ collections::VecDeque, fmt, future::Future, - io, - io::IoSliceMut, + io::{self, IoSliceMut}, mem, net::{SocketAddr, SocketAddrV6}, pin::Pin, str, sync::{Arc, Mutex}, - task::{Context, Poll, Waker}, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, }; #[cfg(all(not(wasm_browser), any(feature = "aws-lc-rs", feature = "ring")))] use crate::runtime::default_runtime; use crate::{ Instant, - runtime::{AsyncUdpSocket, Runtime}, + runtime::{AsyncUdpSocket, Runtime, UdpSender}, udp_transmit, }; use bytes::{Bytes, BytesMut}; @@ -225,12 +224,12 @@ impl Endpoint { .inner .connect(self.runtime.now(), config, addr, server_name)?; - let socket = endpoint.socket.clone(); + let sender = endpoint.socket.clone().create_sender(); endpoint.stats.outgoing_handshakes += 1; Ok(endpoint .recv_state .connections - .insert(ch, conn, socket, self.runtime.clone())) + .insert(ch, conn, sender, self.runtime.clone())) } /// Switch to a new UDP socket @@ -256,7 +255,9 @@ impl Endpoint { // Update connection socket references for sender in inner.recv_state.connections.senders.values() { // Ignoring errors from dropped connections - let _ = sender.send(ConnectionEvent::Rebind(inner.socket.clone())); + let _ = sender.send(ConnectionEvent::Rebind( + inner.socket.clone().create_sender(), + )); } if let Some(driver) = inner.driver.take() { // Ensure the driver can register for wake-ups from the new socket @@ -425,16 +426,16 @@ impl EndpointInner { { Ok((handle, conn)) => { state.stats.accepted_handshakes += 1; - let socket = state.socket.clone(); + let sender = state.socket.clone().create_sender(); let runtime = state.runtime.clone(); Ok(state .recv_state .connections - .insert(handle, conn, socket, runtime)) + .insert(handle, conn, sender, runtime)) } Err(error) => { if let Some(transmit) = error.response { - respond(transmit, &response_buffer, &*state.socket); + respond(transmit, &response_buffer, &mut state.sender); } Err(error.cause) } @@ -446,14 +447,14 @@ impl EndpointInner { state.stats.refused_handshakes += 1; let mut response_buffer = Vec::new(); let transmit = state.inner.refuse(incoming, &mut response_buffer); - respond(transmit, &response_buffer, &*state.socket); + respond(transmit, &response_buffer, &mut state.sender); } pub(crate) fn retry(&self, incoming: proto::Incoming) -> Result<(), proto::RetryError> { let mut state = self.state.lock().unwrap(); let mut response_buffer = Vec::new(); let transmit = state.inner.retry(incoming, &mut response_buffer)?; - respond(transmit, &response_buffer, &*state.socket); + respond(transmit, &response_buffer, &mut state.sender); Ok(()) } @@ -467,6 +468,7 @@ impl EndpointInner { #[derive(Debug)] pub(crate) struct State { socket: Arc, + sender: Pin>, /// During an active migration, abandoned_socket receives traffic /// until the first packet arrives on the new socket. prev_socket: Option>, @@ -494,16 +496,26 @@ impl State { self.recv_state.recv_limiter.start_cycle(get_time); if let Some(socket) = &self.prev_socket { // We don't care about the `PollProgress` from old sockets. - let poll_res = - self.recv_state - .poll_socket(cx, &mut self.inner, &**socket, &*self.runtime, now); + let poll_res = self.recv_state.poll_socket( + cx, + &mut self.inner, + &**socket, + &mut self.sender, + &*self.runtime, + now, + ); if poll_res.is_err() { self.prev_socket = None; } }; - let poll_res = - self.recv_state - .poll_socket(cx, &mut self.inner, &*self.socket, &*self.runtime, now); + let poll_res = self.recv_state.poll_socket( + cx, + &mut self.inner, + &*self.socket, + &mut self.sender, + &*self.runtime, + now, + ); self.recv_state.recv_limiter.finish_cycle(get_time); let poll_res = poll_res?; if poll_res.received_connection_packet { @@ -555,7 +567,11 @@ impl Drop for State { } } -fn respond(transmit: proto::Transmit, response_buffer: &[u8], socket: &dyn AsyncUdpSocket) { +fn respond( + transmit: proto::Transmit, + response_buffer: &[u8], + sender: &mut Pin>, +) { // Send if there's kernel buffer space; otherwise, drop it // // As an endpoint-generated packet, we know this is an @@ -576,7 +592,29 @@ fn respond(transmit: proto::Transmit, response_buffer: &[u8], socket: &dyn Async // to transmit. This is morally equivalent to the packet getting // lost due to congestion further along the link, which // similarly relies on peer retries for recovery. - _ = socket.try_send(&udp_transmit(&transmit, &response_buffer[..transmit.size])); + + // Copied from rust 1.85's std::task::Waker::noop() implementation for backwards compatibility + const NOOP: RawWaker = { + const VTABLE: RawWakerVTable = RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| NOOP, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + RawWaker::new(std::ptr::null(), &VTABLE) + }; + // SAFETY: Copied from rust stdlib, the NOOP waker is thread-safe and doesn't violate the RawWakerVTable contract, + // it doesn't access the data pointer at all. + let waker = unsafe { Waker::from_raw(NOOP) }; + let mut cx = Context::from_waker(&waker); + _ = sender.as_mut().poll_send( + &udp_transmit(&transmit, &response_buffer[..transmit.size]), + &mut cx, + ); } #[inline] @@ -603,7 +641,7 @@ impl ConnectionSet { &mut self, handle: ConnectionHandle, conn: proto::Connection, - socket: Arc, + sender: Pin>, runtime: Arc, ) -> Connecting { let (send, recv) = mpsc::unbounded_channel(); @@ -615,7 +653,7 @@ impl ConnectionSet { .unwrap(); } self.senders.insert(handle, send); - Connecting::new(handle, conn, self.sender.clone(), recv, socket, runtime) + Connecting::new(handle, conn, self.sender.clone(), recv, sender, runtime) } fn is_empty(&self) -> bool { @@ -681,6 +719,7 @@ impl EndpointRef { ) -> Self { let (sender, events) = mpsc::unbounded_channel(); let recv_state = RecvState::new(sender, socket.max_receive_segments(), &inner); + let sender = socket.clone().create_sender(); Self(Arc::new(EndpointInner { shared: Shared { incoming: Notify::new(), @@ -688,6 +727,7 @@ impl EndpointRef { }, state: Mutex::new(State { socket, + sender, prev_socket: None, inner, ipv6, @@ -770,6 +810,7 @@ impl RecvState { cx: &mut Context, endpoint: &mut proto::Endpoint, socket: &dyn AsyncUdpSocket, + sender: &mut Pin>, runtime: &dyn Runtime, now: Instant, ) -> Result { @@ -809,7 +850,7 @@ impl RecvState { } else { let transmit = endpoint.refuse(incoming, &mut response_buffer); - respond(transmit, &response_buffer, socket); + respond(transmit, &response_buffer, sender); } } Some(DatagramEvent::ConnectionEvent(handle, event)) => { @@ -823,7 +864,7 @@ impl RecvState { .send(ConnectionEvent::Proto(event)); } Some(DatagramEvent::Response(transmit)) => { - respond(transmit, &response_buffer, socket); + respond(transmit, &response_buffer, sender); } None => {} } diff --git a/quinn/src/lib.rs b/quinn/src/lib.rs index 0aff67922..64f4800bb 100644 --- a/quinn/src/lib.rs +++ b/quinn/src/lib.rs @@ -41,7 +41,7 @@ #![warn(unreachable_pub)] #![warn(clippy::use_self)] -use std::sync::Arc; +use std::pin::Pin; mod connection; mod endpoint; @@ -85,7 +85,7 @@ pub use crate::recv_stream::{ReadError, ReadExactError, ReadToEndError, RecvStre pub use crate::runtime::SmolRuntime; #[cfg(feature = "runtime-tokio")] pub use crate::runtime::TokioRuntime; -pub use crate::runtime::{AsyncTimer, AsyncUdpSocket, Runtime, UdpPoller, default_runtime}; +pub use crate::runtime::{AsyncTimer, AsyncUdpSocket, Runtime, UdpSender, default_runtime}; pub use crate::send_stream::{SendStream, StoppedError, WriteError}; #[cfg(test)] @@ -98,7 +98,7 @@ enum ConnectionEvent { reason: bytes::Bytes, }, Proto(proto::ConnectionEvent), - Rebind(Arc), + Rebind(Pin>), } fn udp_transmit<'a>(t: &proto::Transmit, buffer: &'a [u8]) -> udp::Transmit<'a> { diff --git a/quinn/src/runtime.rs b/quinn/src/runtime.rs index e2ba7c60a..a78fbbd81 100644 --- a/quinn/src/runtime.rs +++ b/quinn/src/runtime.rs @@ -1,5 +1,5 @@ use std::{ - fmt::Debug, + fmt::{self, Debug}, future::Future, io::{self, IoSliceMut}, net::SocketAddr, @@ -40,23 +40,17 @@ pub trait AsyncTimer: Send + Debug + 'static { /// Abstract implementation of a UDP socket for runtime independence pub trait AsyncUdpSocket: Send + Sync + Debug + 'static { - /// Create a [`UdpPoller`] that can register a single task for write-readiness notifications + /// Create a [`UdpSender`] that can register a single task for write-readiness notifications + /// and send a transmit, if ready. /// /// A `poll_send` method on a single object can usually store only one [`Waker`] at a time, /// i.e. allow at most one caller to wait for an event. This method allows any number of - /// interested tasks to construct their own [`UdpPoller`] object. They can all then wait for the - /// same event and be notified concurrently, because each [`UdpPoller`] can store a separate + /// interested tasks to construct their own [`UdpSender`] object. They can all then wait for the + /// same event and be notified concurrently, because each [`UdpSender`] can store a separate /// [`Waker`]. /// /// [`Waker`]: std::task::Waker - fn create_io_poller(self: Arc) -> Pin>; - - /// Send UDP datagrams from `transmits`, or return `WouldBlock` and clear the underlying - /// socket's readiness, or return an I/O error - /// - /// If this returns [`io::ErrorKind::WouldBlock`], [`UdpPoller::poll_writable`] must be called - /// to register the calling task to be woken when a send should be attempted again. - fn try_send(&self, transmit: &Transmit) -> io::Result<()>; + fn create_sender(self: Arc) -> Pin>; /// Receive UDP datagrams, or register to be woken if receiving may succeed in the future fn poll_recv( @@ -69,11 +63,6 @@ pub trait AsyncUdpSocket: Send + Sync + Debug + 'static { /// Look up the local IP address and port used by this socket fn local_addr(&self) -> io::Result; - /// Maximum number of datagrams that a [`Transmit`] may encode - fn max_transmit_segments(&self) -> usize { - 1 - } - /// Maximum number of datagrams that might be described by a single [`RecvMeta`] fn max_receive_segments(&self) -> usize { 1 @@ -88,71 +77,141 @@ pub trait AsyncUdpSocket: Send + Sync + Debug + 'static { } } -/// An object polled to detect when an associated [`AsyncUdpSocket`] is writable +/// An object for asynchronously writing to an associated [`AsyncUdpSocket`]. /// -/// Any number of `UdpPoller`s may exist for a single [`AsyncUdpSocket`]. Each `UdpPoller` is -/// responsible for notifying at most one task when that socket becomes writable. -pub trait UdpPoller: Send + Sync + Debug + 'static { - /// Check whether the associated socket is likely to be writable +/// Any number of [`UdpSender`]s may exist for a single [`AsyncUdpSocket`]. Each [`UdpSender`] is +/// responsible for notifying at most one task for send readiness. +pub trait UdpSender: Send + Sync + Debug + 'static { + /// Send a UDP datagram, or register to be woken if sending may succeed in the future. /// - /// Must be called after [`AsyncUdpSocket::try_send`] returns [`io::ErrorKind::WouldBlock`] to - /// register the task associated with `cx` to be woken when a send should be attempted - /// again. Unlike in [`Future::poll`], a [`UdpPoller`] may be reused indefinitely no matter how - /// many times `poll_writable` returns [`Poll::Ready`]. - fn poll_writable(self: Pin<&mut Self>, cx: &mut Context) -> Poll>; + /// Usually implementations of this will poll the socket for writability before trying to + /// write to them, and retry both if writing fails. + /// + /// Quinn will create multiple [`UdpSender`]s, one for each task it's using it from. Thus it's + /// important to poll the underlying socket in a way that doesn't overwrite wakers. + /// + /// A single [`UdpSender`] will be re-used, even if `poll_send` returns `Poll::Ready` once, + /// unlike [`Future::poll`], so calling it again after readiness should not panic. + fn poll_send( + self: Pin<&mut Self>, + transmit: &Transmit, + cx: &mut Context, + ) -> Poll>; + + /// Maximum number of datagrams that a [`Transmit`] may encode. + fn max_transmit_segments(&self) -> usize { + 1 + } } pin_project_lite::pin_project! { - /// Helper adapting a function `MakeFut` that constructs a single-use future `Fut` into a - /// [`UdpPoller`] that may be reused indefinitely - struct UdpPollHelper { - make_fut: MakeFut, + /// A helper for constructing [`UdpSender`]s from an underlying `Socket` type. + /// + /// This struct implements [`UdpSender`] if `MakeWritableFn` produces a `WritableFut`. + /// + /// Also serves as a trick, since `WritableFut` doesn't need to be a named future, + /// it can be an anonymous async block, as long as `MakeWritableFn` produces that + /// anonymous async block type. + /// + /// The `UdpSenderHelper` generic type parameters don't need to named, as it will be + /// used in its dyn-compatible form as a `Pin>`. + struct UdpSenderHelper { + socket: Socket, + make_writable_fut_fn: MakeWritableFutFn, #[pin] - fut: Option, + writable_fut: Option, } } -impl UdpPollHelper { - /// Construct a [`UdpPoller`] that calls `make_fut` to get the future to poll, storing it until - /// it yields [`Poll::Ready`], then creating a new one on the next - /// [`poll_writable`](UdpPoller::poll_writable) - #[cfg(any(feature = "runtime-smol", feature = "runtime-tokio",))] - fn new(make_fut: MakeFut) -> Self { - Self { - make_fut, - fut: None, - } - } -} - -impl UdpPoller for UdpPollHelper -where - MakeFut: Fn() -> Fut + Send + Sync + 'static, - Fut: Future> + Send + Sync + 'static, +impl Debug + for UdpSenderHelper { - fn poll_writable(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - let mut this = self.project(); - if this.fut.is_none() { - this.fut.set(Some((this.make_fut)())); + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("UdpSender") + } +} + +impl + UdpSenderHelper +{ + /// Create helper that implements [`UdpSender`] from a socket. + /// + /// Additionally you need to provide what is essentially an async function + /// that resolves once the socket is write-ready. + /// + /// See also the bounds on this struct's [`UdpSender`] implementation. + #[cfg(any(feature = "runtime-smol", feature = "runtime-tokio",))] + fn new(inner: Socket, make_fut: MakeWritableFutFn) -> Self { + Self { + socket: inner, + make_writable_fut_fn: make_fut, + writable_fut: None, } - // We're forced to `unwrap` here because `Fut` may be `!Unpin`, which means we can't safely - // obtain an `&mut Fut` after storing it in `self.fut` when `self` is already behind `Pin`, - // and if we didn't store it then we wouldn't be able to keep it alive between - // `poll_writable` calls. - let result = this.fut.as_mut().as_pin_mut().unwrap().poll(cx); - if result.is_ready() { + } +} + +impl super::UdpSender + for UdpSenderHelper +where + Socket: UdpSenderHelperSocket, + MakeWritableFutFn: Fn(&Socket) -> WritableFut + Send + Sync + 'static, + WritableFut: Future> + Send + Sync + 'static, +{ + fn poll_send( + self: Pin<&mut Self>, + transmit: &udp::Transmit, + cx: &mut Context, + ) -> Poll> { + let mut this = self.project(); + loop { + if this.writable_fut.is_none() { + this.writable_fut + .set(Some((this.make_writable_fut_fn)(this.socket))); + } + // We're forced to `unwrap` here because `Fut` may be `!Unpin`, which means we can't safely + // obtain an `&mut WritableFut` after storing it in `self.writable_fut` when `self` is already behind `Pin`, + // and if we didn't store it then we wouldn't be able to keep it alive between + // `poll_send` calls. + let result = + std::task::ready!(this.writable_fut.as_mut().as_pin_mut().unwrap().poll(cx)); + // Polling an arbitrary `Future` after it becomes ready is a logic error, so arrange for // a new `Future` to be created on the next call. - this.fut.set(None); + this.writable_fut.set(None); + + // If .writable() fails, propagate the error + result?; + + match this.socket.try_send(transmit) { + // We thought the socket was writable, but it wasn't, then retry so that either another + // `writable().await` call determines that the socket is indeed not writable and + // registers us for a wakeup, or the send succeeds if this really was just a + // transient failure. + Err(e) if e.kind() == io::ErrorKind::WouldBlock => continue, + // In all other cases, either propagate the error or we're Ok + result => return Poll::Ready(result), + } } - result + } + + fn max_transmit_segments(&self) -> usize { + self.socket.max_transmit_segments() } } -impl Debug for UdpPollHelper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("UdpPollHelper").finish_non_exhaustive() - } +/// Parts of the [`UdpSender`] trait that aren't asynchronous or require storing wakers. +/// +/// This trait is used by [`UdpSenderHelper`] to help construct [`UdpSender`]s. +trait UdpSenderHelperSocket: Send + Sync + 'static { + /// Try to send a transmit, if the socket happens to be write-ready. + /// + /// If not write-ready, this is allowed to return [`std::io::ErrorKind::WouldBlock`]. + /// + /// The [`UdpSenderHelper`] will use this to implement [`UdpSender::poll_send`]. + fn try_send(&self, transmit: &udp::Transmit) -> io::Result<()>; + + /// See [`UdpSender::max_transmit_segments`]. + fn max_transmit_segments(&self) -> usize; } /// Automatically select an appropriate runtime from those enabled at compile time diff --git a/quinn/src/runtime/async_io.rs b/quinn/src/runtime/async_io.rs index 5ebcd3230..546647e3a 100644 --- a/quinn/src/runtime/async_io.rs +++ b/quinn/src/runtime/async_io.rs @@ -13,7 +13,7 @@ use async_io::Timer; use super::AsyncTimer; #[cfg(feature = "runtime-smol")] -use super::{AsyncUdpSocket, Runtime, UdpPollHelper}; +use super::{AsyncUdpSocket, Runtime, UdpSender, UdpSenderHelper, UdpSenderHelperSocket}; #[cfg(feature = "runtime-smol")] // Due to MSRV, we must specify `self::` where there's crate/module ambiguity @@ -73,17 +73,27 @@ impl UdpSocket { } #[cfg(feature = "runtime-smol")] -impl AsyncUdpSocket for UdpSocket { - fn create_io_poller(self: Arc) -> Pin> { - Box::pin(UdpPollHelper::new(move || { - let socket = self.clone(); - async move { socket.io.writable().await } - })) +impl UdpSenderHelperSocket for Arc { + fn max_transmit_segments(&self) -> usize { + self.inner.max_gso_segments() } fn try_send(&self, transmit: &udp::Transmit) -> io::Result<()> { self.inner.send((&self.io).into(), transmit) } +} + +#[cfg(feature = "runtime-smol")] +impl AsyncUdpSocket for UdpSocket { + fn create_sender(self: Arc) -> Pin> { + Box::pin(UdpSenderHelper::new( + Arc::clone(&self), + |socket: &Arc| { + let socket = socket.clone(); + async move { socket.io.writable().await } + }, + )) + } fn poll_recv( &self, @@ -107,10 +117,6 @@ impl AsyncUdpSocket for UdpSocket { self.inner.may_fragment() } - fn max_transmit_segments(&self) -> usize { - self.inner.max_gso_segments() - } - fn max_receive_segments(&self) -> usize { self.inner.gro_segments() } diff --git a/quinn/src/runtime/tokio.rs b/quinn/src/runtime/tokio.rs index 0e423660d..6bbfad4d6 100644 --- a/quinn/src/runtime/tokio.rs +++ b/quinn/src/runtime/tokio.rs @@ -12,7 +12,7 @@ use tokio::{ time::{Sleep, sleep_until}, }; -use super::{AsyncTimer, AsyncUdpSocket, Runtime, UdpPollHelper}; +use super::{AsyncTimer, AsyncUdpSocket, Runtime, UdpSenderHelper, UdpSenderHelperSocket}; /// A Quinn runtime for Tokio #[derive(Debug)] @@ -54,12 +54,9 @@ struct UdpSocket { inner: udp::UdpSocketState, } -impl AsyncUdpSocket for UdpSocket { - fn create_io_poller(self: Arc) -> Pin> { - Box::pin(UdpPollHelper::new(move || { - let socket = self.clone(); - async move { socket.io.writable().await } - })) +impl UdpSenderHelperSocket for Arc { + fn max_transmit_segments(&self) -> usize { + self.inner.max_gso_segments() } fn try_send(&self, transmit: &udp::Transmit) -> io::Result<()> { @@ -67,6 +64,18 @@ impl AsyncUdpSocket for UdpSocket { self.inner.send((&self.io).into(), transmit) }) } +} + +impl AsyncUdpSocket for UdpSocket { + fn create_sender(self: Arc) -> Pin> { + Box::pin(UdpSenderHelper::new( + Arc::clone(&self), + |socket: &Arc| { + let socket = socket.clone(); + async move { socket.io.writable().await } + }, + )) + } fn poll_recv( &self, @@ -92,10 +101,6 @@ impl AsyncUdpSocket for UdpSocket { self.inner.may_fragment() } - fn max_transmit_segments(&self) -> usize { - self.inner.max_gso_segments() - } - fn max_receive_segments(&self) -> usize { self.inner.gro_segments() } From fe596df2c4402afe2c72a7bb5628ec0fc6298021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Kr=C3=BCger?= Date: Tue, 3 Jun 2025 16:11:44 +0200 Subject: [PATCH 19/71] Store a `Box` instead of `Arc`ing it, make `poll_recv` take `&mut self` --- quinn/src/endpoint.rs | 28 +++++++++++++--------------- quinn/src/runtime.rs | 6 +++--- quinn/src/runtime/async_io.rs | 35 ++++++++++++++++------------------- quinn/src/runtime/tokio.rs | 31 ++++++++++++++----------------- 4 files changed, 46 insertions(+), 54 deletions(-) diff --git a/quinn/src/endpoint.rs b/quinn/src/endpoint.rs index d1bdd23b3..761a2fc5f 100644 --- a/quinn/src/endpoint.rs +++ b/quinn/src/endpoint.rs @@ -129,7 +129,7 @@ impl Endpoint { pub fn new_with_abstract_socket( config: EndpointConfig, server_config: Option, - socket: Arc, + socket: Box, runtime: Arc, ) -> io::Result { let addr = socket.local_addr()?; @@ -224,7 +224,7 @@ impl Endpoint { .inner .connect(self.runtime.now(), config, addr, server_name)?; - let sender = endpoint.socket.clone().create_sender(); + let sender = endpoint.socket.create_sender(); endpoint.stats.outgoing_handshakes += 1; Ok(endpoint .recv_state @@ -246,7 +246,7 @@ impl Endpoint { /// connections and connections to servers unreachable from the new address will be lost. /// /// On error, the old UDP socket is retained. - pub fn rebind_abstract(&self, socket: Arc) -> io::Result<()> { + pub fn rebind_abstract(&self, socket: Box) -> io::Result<()> { let addr = socket.local_addr()?; let mut inner = self.inner.state.lock().unwrap(); inner.prev_socket = Some(mem::replace(&mut inner.socket, socket)); @@ -255,9 +255,7 @@ impl Endpoint { // Update connection socket references for sender in inner.recv_state.connections.senders.values() { // Ignoring errors from dropped connections - let _ = sender.send(ConnectionEvent::Rebind( - inner.socket.clone().create_sender(), - )); + let _ = sender.send(ConnectionEvent::Rebind(inner.socket.create_sender())); } if let Some(driver) = inner.driver.take() { // Ensure the driver can register for wake-ups from the new socket @@ -426,7 +424,7 @@ impl EndpointInner { { Ok((handle, conn)) => { state.stats.accepted_handshakes += 1; - let sender = state.socket.clone().create_sender(); + let sender = state.socket.create_sender(); let runtime = state.runtime.clone(); Ok(state .recv_state @@ -467,11 +465,11 @@ impl EndpointInner { #[derive(Debug)] pub(crate) struct State { - socket: Arc, + socket: Box, sender: Pin>, /// During an active migration, abandoned_socket receives traffic /// until the first packet arrives on the new socket. - prev_socket: Option>, + prev_socket: Option>, inner: proto::Endpoint, recv_state: RecvState, driver: Option, @@ -494,12 +492,12 @@ impl State { fn drive_recv(&mut self, cx: &mut Context, now: Instant) -> Result { let get_time = || self.runtime.now(); self.recv_state.recv_limiter.start_cycle(get_time); - if let Some(socket) = &self.prev_socket { + if let Some(socket) = &mut self.prev_socket { // We don't care about the `PollProgress` from old sockets. let poll_res = self.recv_state.poll_socket( cx, &mut self.inner, - &**socket, + &mut **socket, &mut self.sender, &*self.runtime, now, @@ -511,7 +509,7 @@ impl State { let poll_res = self.recv_state.poll_socket( cx, &mut self.inner, - &*self.socket, + &mut *self.socket, &mut self.sender, &*self.runtime, now, @@ -712,14 +710,14 @@ pub(crate) struct EndpointRef(Arc); impl EndpointRef { pub(crate) fn new( - socket: Arc, + socket: Box, inner: proto::Endpoint, ipv6: bool, runtime: Arc, ) -> Self { let (sender, events) = mpsc::unbounded_channel(); let recv_state = RecvState::new(sender, socket.max_receive_segments(), &inner); - let sender = socket.clone().create_sender(); + let sender = socket.create_sender(); Self(Arc::new(EndpointInner { shared: Shared { incoming: Notify::new(), @@ -809,7 +807,7 @@ impl RecvState { &mut self, cx: &mut Context, endpoint: &mut proto::Endpoint, - socket: &dyn AsyncUdpSocket, + socket: &mut dyn AsyncUdpSocket, sender: &mut Pin>, runtime: &dyn Runtime, now: Instant, diff --git a/quinn/src/runtime.rs b/quinn/src/runtime.rs index a78fbbd81..64734d2ea 100644 --- a/quinn/src/runtime.rs +++ b/quinn/src/runtime.rs @@ -21,7 +21,7 @@ pub trait Runtime: Send + Sync + Debug + 'static { fn spawn(&self, future: Pin + Send>>); /// Convert `t` into the socket type used by this runtime #[cfg(not(wasm_browser))] - fn wrap_udp_socket(&self, t: std::net::UdpSocket) -> io::Result>; + fn wrap_udp_socket(&self, t: std::net::UdpSocket) -> io::Result>; /// Look up the current time /// /// Allows simulating the flow of time for testing. @@ -50,11 +50,11 @@ pub trait AsyncUdpSocket: Send + Sync + Debug + 'static { /// [`Waker`]. /// /// [`Waker`]: std::task::Waker - fn create_sender(self: Arc) -> Pin>; + fn create_sender(&self) -> Pin>; /// Receive UDP datagrams, or register to be woken if receiving may succeed in the future fn poll_recv( - &self, + &mut self, cx: &mut Context, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta], diff --git a/quinn/src/runtime/async_io.rs b/quinn/src/runtime/async_io.rs index 546647e3a..eb5380665 100644 --- a/quinn/src/runtime/async_io.rs +++ b/quinn/src/runtime/async_io.rs @@ -39,8 +39,8 @@ mod smol { fn wrap_udp_socket( &self, sock: std::net::UdpSocket, - ) -> io::Result> { - Ok(Arc::new(UdpSocket::new(sock)?)) + ) -> io::Result> { + Ok(Box::new(UdpSocket::new(sock)?)) } } } @@ -55,25 +55,25 @@ impl AsyncTimer for Timer { } } -#[cfg(feature = "runtime-smol")] -#[derive(Debug)] +#[cfg(any(feature = "runtime-smol"))] +#[derive(Debug, Clone)] struct UdpSocket { - io: Async, - inner: udp::UdpSocketState, + io: Arc>, + inner: Arc, } #[cfg(feature = "runtime-smol")] impl UdpSocket { fn new(sock: std::net::UdpSocket) -> io::Result { Ok(Self { - inner: udp::UdpSocketState::new((&sock).into())?, - io: Async::new_nonblocking(sock)?, + inner: Arc::new(udp::UdpSocketState::new((&sock).into())?), + io: Arc::new(Async::new_nonblocking(sock)?), }) } } #[cfg(feature = "runtime-smol")] -impl UdpSenderHelperSocket for Arc { +impl UdpSenderHelperSocket for UdpSocket { fn max_transmit_segments(&self) -> usize { self.inner.max_gso_segments() } @@ -85,18 +85,15 @@ impl UdpSenderHelperSocket for Arc { #[cfg(feature = "runtime-smol")] impl AsyncUdpSocket for UdpSocket { - fn create_sender(self: Arc) -> Pin> { - Box::pin(UdpSenderHelper::new( - Arc::clone(&self), - |socket: &Arc| { - let socket = socket.clone(); - async move { socket.io.writable().await } - }, - )) + fn create_sender(&self) -> Pin> { + Box::pin(UdpSenderHelper::new(self.clone(), |socket: &Self| { + let socket = socket.clone(); + async move { socket.io.writable().await } + })) } fn poll_recv( - &self, + &mut self, cx: &mut Context, bufs: &mut [io::IoSliceMut<'_>], meta: &mut [udp::RecvMeta], @@ -110,7 +107,7 @@ impl AsyncUdpSocket for UdpSocket { } fn local_addr(&self) -> io::Result { - self.io.as_ref().local_addr() + self.io.as_ref().as_ref().local_addr() } fn may_fragment(&self) -> bool { diff --git a/quinn/src/runtime/tokio.rs b/quinn/src/runtime/tokio.rs index 6bbfad4d6..6b54bcb09 100644 --- a/quinn/src/runtime/tokio.rs +++ b/quinn/src/runtime/tokio.rs @@ -27,10 +27,10 @@ impl Runtime for TokioRuntime { tokio::spawn(future); } - fn wrap_udp_socket(&self, sock: std::net::UdpSocket) -> io::Result> { - Ok(Arc::new(UdpSocket { - inner: udp::UdpSocketState::new((&sock).into())?, - io: tokio::net::UdpSocket::from_std(sock)?, + fn wrap_udp_socket(&self, sock: std::net::UdpSocket) -> io::Result> { + Ok(Box::new(UdpSocket { + inner: Arc::new(udp::UdpSocketState::new((&sock).into())?), + io: Arc::new(tokio::net::UdpSocket::from_std(sock)?), })) } @@ -48,13 +48,13 @@ impl AsyncTimer for Sleep { } } -#[derive(Debug)] +#[derive(Debug, Clone)] struct UdpSocket { - io: tokio::net::UdpSocket, - inner: udp::UdpSocketState, + io: Arc, + inner: Arc, } -impl UdpSenderHelperSocket for Arc { +impl UdpSenderHelperSocket for UdpSocket { fn max_transmit_segments(&self) -> usize { self.inner.max_gso_segments() } @@ -67,18 +67,15 @@ impl UdpSenderHelperSocket for Arc { } impl AsyncUdpSocket for UdpSocket { - fn create_sender(self: Arc) -> Pin> { - Box::pin(UdpSenderHelper::new( - Arc::clone(&self), - |socket: &Arc| { - let socket = socket.clone(); - async move { socket.io.writable().await } - }, - )) + fn create_sender(&self) -> Pin> { + Box::pin(UdpSenderHelper::new(self.clone(), |socket: &Self| { + let socket = socket.clone(); + async move { socket.io.writable().await } + })) } fn poll_recv( - &self, + &mut self, cx: &mut Context, bufs: &mut [std::io::IoSliceMut<'_>], meta: &mut [udp::RecvMeta], From 1350132407c7ded9c5e71d9b9b5eb13f2f095606 Mon Sep 17 00:00:00 2001 From: Phoenix Kahlo Date: Sat, 6 Sep 2025 13:30:46 -0500 Subject: [PATCH 20/71] refactor: Pass ConnectionId by value Breaking. --- perf/src/noprotection.rs | 8 ++++---- quinn-proto/src/cid_generator.rs | 6 +++--- quinn-proto/src/connection/mod.rs | 6 +++--- quinn-proto/src/crypto.rs | 13 +++++-------- quinn-proto/src/crypto/rustls.rs | 16 ++++++++-------- quinn-proto/src/endpoint.rs | 28 ++++++++++++++-------------- quinn-proto/src/packet.rs | 14 +++++++------- quinn/src/incoming.rs | 2 +- 8 files changed, 45 insertions(+), 48 deletions(-) diff --git a/perf/src/noprotection.rs b/perf/src/noprotection.rs index 7b8a2ad19..9762e4b4c 100644 --- a/perf/src/noprotection.rs +++ b/perf/src/noprotection.rs @@ -64,7 +64,7 @@ impl NoProtectionServerConfig { // forward all calls to inner except those related to packet encryption/decryption impl crypto::Session for NoProtectionSession { - fn initial_keys(&self, dst_cid: &ConnectionId, side: Side) -> crypto::Keys { + fn initial_keys(&self, dst_cid: ConnectionId, side: Side) -> crypto::Keys { self.inner.initial_keys(dst_cid, side) } @@ -115,7 +115,7 @@ impl crypto::Session for NoProtectionSession { Some(Self::wrap_packet_keys(keys)) } - fn is_valid_retry(&self, orig_dst_cid: &ConnectionId, header: &[u8], payload: &[u8]) -> bool { + fn is_valid_retry(&self, orig_dst_cid: ConnectionId, header: &[u8], payload: &[u8]) -> bool { self.inner.is_valid_retry(orig_dst_cid, header, payload) } @@ -149,12 +149,12 @@ impl crypto::ServerConfig for NoProtectionServerConfig { fn initial_keys( &self, version: u32, - dst_cid: &ConnectionId, + dst_cid: ConnectionId, ) -> Result { self.inner.initial_keys(version, dst_cid) } - fn retry_tag(&self, version: u32, orig_dst_cid: &ConnectionId, packet: &[u8]) -> [u8; 16] { + fn retry_tag(&self, version: u32, orig_dst_cid: ConnectionId, packet: &[u8]) -> [u8; 16] { self.inner.retry_tag(version, orig_dst_cid, packet) } diff --git a/quinn-proto/src/cid_generator.rs b/quinn-proto/src/cid_generator.rs index e62415e8b..7af4eca84 100644 --- a/quinn-proto/src/cid_generator.rs +++ b/quinn-proto/src/cid_generator.rs @@ -20,7 +20,7 @@ pub trait ConnectionIdGenerator: Send + Sync { /// Quickly determine whether `cid` could have been generated by this generator /// /// False positives are permitted, but increase the cost of handling invalid packets. - fn validate(&self, _cid: &ConnectionId) -> Result<(), InvalidCid> { + fn validate(&self, _cid: ConnectionId) -> Result<(), InvalidCid> { Ok(()) } @@ -143,7 +143,7 @@ impl ConnectionIdGenerator for HashedConnectionIdGenerator { ConnectionId::new(&bytes_arr) } - fn validate(&self, cid: &ConnectionId) -> Result<(), InvalidCid> { + fn validate(&self, cid: ConnectionId) -> Result<(), InvalidCid> { let (nonce, signature) = cid.split_at(NONCE_LEN); let mut hasher = rustc_hash::FxHasher::default(); hasher.write_u64(self.key); @@ -175,6 +175,6 @@ mod tests { fn validate_keyed_cid() { let mut generator = HashedConnectionIdGenerator::new(); let cid = generator.generate_cid(); - generator.validate(&cid).unwrap(); + generator.validate(cid).unwrap(); } } diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 38ea8fbb4..4ab5e3363 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -262,7 +262,7 @@ impl Connection { let connection_side = ConnectionSide::from(side_args); let side = connection_side.side(); let initial_space = PacketSpace { - crypto: Some(crypto.initial_keys(&init_cid, side)), + crypto: Some(crypto.initial_keys(init_cid, side)), ..PacketSpace::new(now) }; let state = State::Handshake(state::Handshake { @@ -2455,7 +2455,7 @@ impl Connection { if self.total_authed_packets > 1 || packet.payload.len() <= 16 // token + 16 byte tag || !self.crypto.is_valid_retry( - &self.rem_cids.active(), + self.rem_cids.active(), &packet.header_data, &packet.payload, ) @@ -2484,7 +2484,7 @@ impl Connection { self.discard_space(now, SpaceId::Initial); // Make sure we clean up after any retransmitted Initials self.spaces[SpaceId::Initial] = PacketSpace { - crypto: Some(self.crypto.initial_keys(&rem_cid, self.side.side())), + crypto: Some(self.crypto.initial_keys(rem_cid, self.side.side())), next_packet_number: self.spaces[SpaceId::Initial].next_packet_number, crypto_offset: client_hello.len() as u64, ..PacketSpace::new(now) diff --git a/quinn-proto/src/crypto.rs b/quinn-proto/src/crypto.rs index aebd864d4..2ac40fc1e 100644 --- a/quinn-proto/src/crypto.rs +++ b/quinn-proto/src/crypto.rs @@ -27,7 +27,7 @@ pub mod rustls; /// A cryptographic session (commonly TLS) pub trait Session: Send + Sync + 'static { /// Create the initial set of keys given the client's initial destination ConnectionId - fn initial_keys(&self, dst_cid: &ConnectionId, side: Side) -> Keys; + fn initial_keys(&self, dst_cid: ConnectionId, side: Side) -> Keys; /// Get data negotiated during the handshake, if available /// @@ -77,7 +77,7 @@ pub trait Session: Send + Sync + 'static { fn next_1rtt_keys(&mut self) -> Option>>; /// Verify the integrity of a retry packet - fn is_valid_retry(&self, orig_dst_cid: &ConnectionId, header: &[u8], payload: &[u8]) -> bool; + fn is_valid_retry(&self, orig_dst_cid: ConnectionId, header: &[u8], payload: &[u8]) -> bool; /// Fill `output` with `output.len()` bytes of keying material derived /// from the [Session]'s secrets, using `label` and `context` for domain @@ -123,16 +123,13 @@ pub trait ClientConfig: Send + Sync { /// Server-side configuration for the crypto protocol pub trait ServerConfig: Send + Sync { /// Create the initial set of keys given the client's initial destination ConnectionId - fn initial_keys( - &self, - version: u32, - dst_cid: &ConnectionId, - ) -> Result; + fn initial_keys(&self, version: u32, dst_cid: ConnectionId) + -> Result; /// Generate the integrity tag for a retry packet /// /// Never called if `initial_keys` rejected `version`. - fn retry_tag(&self, version: u32, orig_dst_cid: &ConnectionId, packet: &[u8]) -> [u8; 16]; + fn retry_tag(&self, version: u32, orig_dst_cid: ConnectionId, packet: &[u8]) -> [u8; 16]; /// Start a server session with this configuration /// diff --git a/quinn-proto/src/crypto/rustls.rs b/quinn-proto/src/crypto/rustls.rs index b45ad3e84..c31fddf87 100644 --- a/quinn-proto/src/crypto/rustls.rs +++ b/quinn-proto/src/crypto/rustls.rs @@ -53,8 +53,8 @@ impl TlsSession { } impl crypto::Session for TlsSession { - fn initial_keys(&self, dst_cid: &ConnectionId, side: Side) -> Keys { - initial_keys(self.version, *dst_cid, side, &self.suite) + fn initial_keys(&self, dst_cid: ConnectionId, side: Side) -> Keys { + initial_keys(self.version, dst_cid, side, &self.suite) } fn handshake_data(&self) -> Option> { @@ -171,7 +171,7 @@ impl crypto::Session for TlsSession { }) } - fn is_valid_retry(&self, orig_dst_cid: &ConnectionId, header: &[u8], payload: &[u8]) -> bool { + fn is_valid_retry(&self, orig_dst_cid: ConnectionId, header: &[u8], payload: &[u8]) -> bool { let tag_start = match payload.len().checked_sub(16) { Some(x) => x, None => return false, @@ -180,7 +180,7 @@ impl crypto::Session for TlsSession { let mut pseudo_packet = Vec::with_capacity(header.len() + payload.len() + orig_dst_cid.len() + 1); pseudo_packet.push(orig_dst_cid.len() as u8); - pseudo_packet.extend_from_slice(orig_dst_cid); + pseudo_packet.extend_from_slice(&orig_dst_cid); pseudo_packet.extend_from_slice(header); let tag_start = tag_start + pseudo_packet.len(); pseudo_packet.extend_from_slice(payload); @@ -532,13 +532,13 @@ impl crypto::ServerConfig for QuicServerConfig { fn initial_keys( &self, version: u32, - dst_cid: &ConnectionId, + dst_cid: ConnectionId, ) -> Result { let version = interpret_version(version)?; - Ok(initial_keys(version, *dst_cid, Side::Server, &self.initial)) + Ok(initial_keys(version, dst_cid, Side::Server, &self.initial)) } - fn retry_tag(&self, version: u32, orig_dst_cid: &ConnectionId, packet: &[u8]) -> [u8; 16] { + fn retry_tag(&self, version: u32, orig_dst_cid: ConnectionId, packet: &[u8]) -> [u8; 16] { // Safe: `start_session()` is never called if `initial_keys()` rejected `version` let version = interpret_version(version).unwrap(); let (nonce, key) = match version { @@ -549,7 +549,7 @@ impl crypto::ServerConfig for QuicServerConfig { let mut pseudo_packet = Vec::with_capacity(packet.len() + orig_dst_cid.len() + 1); pseudo_packet.push(orig_dst_cid.len() as u8); - pseudo_packet.extend_from_slice(orig_dst_cid); + pseudo_packet.extend_from_slice(&orig_dst_cid); pseudo_packet.extend_from_slice(packet); let nonce = aead::Nonce::assume_unique_for_key(nonce); diff --git a/quinn-proto/src/endpoint.rs b/quinn-proto/src/endpoint.rs index c04694577..76bce6232 100644 --- a/quinn-proto/src/endpoint.rs +++ b/quinn-proto/src/endpoint.rs @@ -252,7 +252,7 @@ impl Endpoint { } else { // If we got this far, we're receiving a seemingly valid packet for an unknown // connection. Send a stateless reset if possible. - self.stateless_reset(now, datagram_len, addresses, *dst_cid, buf) + self.stateless_reset(now, datagram_len, addresses, dst_cid, buf) .map(DatagramEvent::Response) } } @@ -426,7 +426,7 @@ impl Endpoint { let Some(server_config) = &self.server_config else { debug!("packet for unrecognized connection {}", dst_cid); return self - .stateless_reset(event.now, datagram_len, addresses, *dst_cid, buf) + .stateless_reset(event.now, datagram_len, addresses, dst_cid, buf) .map(DatagramEvent::Response); }; @@ -453,7 +453,7 @@ impl Endpoint { header.version, addresses, &crypto, - &header.src_cid, + header.src_cid, reason, buf, ))); @@ -486,7 +486,7 @@ impl Endpoint { header.version, addresses, &crypto, - &header.src_cid, + header.src_cid, TransportError::INVALID_TOKEN(""), buf, ))); @@ -563,7 +563,7 @@ impl Endpoint { version, incoming.addresses, &incoming.crypto, - &src_cid, + src_cid, TransportError::CONNECTION_REFUSED(""), buf, )), @@ -659,7 +659,7 @@ impl Endpoint { version, incoming.addresses, &incoming.crypto, - &src_cid, + src_cid, e.clone(), buf, )), @@ -709,7 +709,7 @@ impl Endpoint { incoming.packet.header.version, incoming.addresses, &incoming.crypto, - &incoming.packet.header.src_cid, + incoming.packet.header.src_cid, TransportError::CONNECTION_REFUSED(""), buf, ) @@ -753,7 +753,7 @@ impl Endpoint { buf.put_slice(&token); buf.extend_from_slice(&server_config.crypto.retry_tag( incoming.packet.header.version, - &incoming.packet.header.dst_cid, + incoming.packet.header.dst_cid, buf, )); encode.finish(buf, &*incoming.crypto.header.local, None); @@ -849,7 +849,7 @@ impl Endpoint { version: u32, addresses: FourTuple, crypto: &Keys, - remote_id: &ConnectionId, + remote_id: ConnectionId, reason: TransportError, buf: &mut Vec, ) -> Transmit { @@ -859,7 +859,7 @@ impl Endpoint { let local_id = self.local_cid_generator.generate_cid(); let number = PacketNumber::U8(0); let header = Header::Initial(InitialHeader { - dst_cid: *remote_id, + dst_cid: remote_id, src_cid: local_id, number, token: Bytes::new(), @@ -1070,12 +1070,12 @@ impl ConnectionIndex { /// Find the existing connection that `datagram` should be routed to, if any fn get(&self, addresses: &FourTuple, datagram: &PartialDecode) -> Option { if !datagram.dst_cid().is_empty() { - if let Some(&ch) = self.connection_ids.get(datagram.dst_cid()) { + if let Some(&ch) = self.connection_ids.get(&datagram.dst_cid()) { return Some(RouteDatagramTo::Connection(ch)); } } if datagram.is_initial() || datagram.is_0rtt() { - if let Some(&ch) = self.connection_ids_initial.get(datagram.dst_cid()) { + if let Some(&ch) = self.connection_ids_initial.get(&datagram.dst_cid()) { return Some(ch); } } @@ -1194,8 +1194,8 @@ impl Incoming { } /// The original destination connection ID sent by the client - pub fn orig_dst_cid(&self) -> &ConnectionId { - &self.token.orig_dst_cid + pub fn orig_dst_cid(&self) -> ConnectionId { + self.token.orig_dst_cid } } diff --git a/quinn-proto/src/packet.rs b/quinn-proto/src/packet.rs index b5ef0c402..ba7a173bc 100644 --- a/quinn-proto/src/packet.rs +++ b/quinn-proto/src/packet.rs @@ -99,7 +99,7 @@ impl PartialDecode { } /// The destination connection ID of the packet - pub fn dst_cid(&self) -> &ConnectionId { + pub fn dst_cid(&self) -> ConnectionId { self.plain_header.dst_cid() } @@ -555,14 +555,14 @@ impl ProtectedHeader { } /// The destination Connection ID of the packet - pub fn dst_cid(&self) -> &ConnectionId { + pub fn dst_cid(&self) -> ConnectionId { use ProtectedHeader::*; match self { - Initial(header) => &header.dst_cid, - Long { dst_cid, .. } => dst_cid, - Retry { dst_cid, .. } => dst_cid, - Short { dst_cid, .. } => dst_cid, - VersionNegotiate { dst_cid, .. } => dst_cid, + Initial(header) => header.dst_cid, + &Long { dst_cid, .. } => dst_cid, + &Retry { dst_cid, .. } => dst_cid, + &Short { dst_cid, .. } => dst_cid, + &VersionNegotiate { dst_cid, .. } => dst_cid, } } diff --git a/quinn/src/incoming.rs b/quinn/src/incoming.rs index 8eced8cdc..f11a76e9b 100644 --- a/quinn/src/incoming.rs +++ b/quinn/src/incoming.rs @@ -96,7 +96,7 @@ impl Incoming { /// The original destination CID when initiating the connection pub fn orig_dst_cid(&self) -> ConnectionId { - *self.0.as_ref().unwrap().inner.orig_dst_cid() + self.0.as_ref().unwrap().inner.orig_dst_cid() } } From 7d7afb5b3e4b4b3475cf5ffe3d529f1fe8a9e113 Mon Sep 17 00:00:00 2001 From: Phoenix Kahlo Date: Sat, 6 Sep 2025 12:58:18 -0500 Subject: [PATCH 21/71] refactor(proto): Box AcceptError Boxes AcceptError to avoid clippy::result_large_err, rather than suppressing it. Breaking change. --- quinn-proto/src/endpoint.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/quinn-proto/src/endpoint.rs b/quinn-proto/src/endpoint.rs index 76bce6232..668e3c2f2 100644 --- a/quinn-proto/src/endpoint.rs +++ b/quinn-proto/src/endpoint.rs @@ -515,15 +515,14 @@ impl Endpoint { } /// Attempt to accept this incoming connection (an error may still occur) - // AcceptError cannot be made smaller without semver breakage - #[allow(clippy::result_large_err)] + // box err to avoid clippy::result_large_err pub fn accept( &mut self, mut incoming: Incoming, now: Instant, buf: &mut Vec, server_config: Option>, - ) -> Result<(ConnectionHandle, Connection), AcceptError> { + ) -> Result<(ConnectionHandle, Connection), Box> { let remote_address_validated = incoming.remote_address_validated(); incoming.improper_drop_warner.dismiss(); let incoming_buffer = self.incoming_buffers.remove(incoming.incoming_idx); @@ -548,16 +547,16 @@ impl Endpoint { { debug!("abandoning accept of stale initial"); self.index.remove_initial(dst_cid); - return Err(AcceptError { + return Err(Box::new(AcceptError { cause: ConnectionError::TimedOut, response: None, - }); + })); } if self.cids_exhausted() { debug!("refusing connection"); self.index.remove_initial(dst_cid); - return Err(AcceptError { + return Err(Box::new(AcceptError { cause: ConnectionError::CidsExhausted, response: Some(self.initial_close( version, @@ -567,7 +566,7 @@ impl Endpoint { TransportError::CONNECTION_REFUSED(""), buf, )), - }); + })); } if incoming @@ -583,10 +582,10 @@ impl Endpoint { { debug!(packet_number, "failed to authenticate initial packet"); self.index.remove_initial(dst_cid); - return Err(AcceptError { + return Err(Box::new(AcceptError { cause: TransportError::PROTOCOL_VIOLATION("authentication failed").into(), response: None, - }); + })); }; let ch = ConnectionHandle(self.connections.vacant_key()); @@ -665,7 +664,7 @@ impl Endpoint { )), _ => None, }; - Err(AcceptError { cause: e, response }) + Err(Box::new(AcceptError { cause: e, response })) } } } From c8970cf72e7ec1bb62fbacd00fe3706f21c31237 Mon Sep 17 00:00:00 2001 From: Sinh Pham Date: Tue, 12 Aug 2025 09:58:26 -0700 Subject: [PATCH 22/71] Add interface_index to RecvMeta --- quinn-udp/src/fallback.rs | 1 + quinn-udp/src/lib.rs | 3 +++ quinn-udp/src/unix.rs | 4 ++++ quinn-udp/src/windows.rs | 4 ++++ 4 files changed, 12 insertions(+) diff --git a/quinn-udp/src/fallback.rs b/quinn-udp/src/fallback.rs index 4444bed81..ee5762090 100644 --- a/quinn-udp/src/fallback.rs +++ b/quinn-udp/src/fallback.rs @@ -72,6 +72,7 @@ impl UdpSocketState { addr: addr.as_socket().unwrap(), ecn: None, dst_ip: None, + interface_index: None, }; Ok(1) } diff --git a/quinn-udp/src/lib.rs b/quinn-udp/src/lib.rs index f93578b9a..077fd42bb 100644 --- a/quinn-udp/src/lib.rs +++ b/quinn-udp/src/lib.rs @@ -115,6 +115,8 @@ pub struct RecvMeta { /// Populated on platforms: Windows, Linux, Android (API level > 25), /// FreeBSD, OpenBSD, NetBSD, macOS, and iOS. pub dst_ip: Option, + /// The interface index of the interface on which the datagram was received + pub interface_index: Option, } impl Default for RecvMeta { @@ -126,6 +128,7 @@ impl Default for RecvMeta { stride: 0, ecn: None, dst_ip: None, + interface_index: None, } } } diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index 6557eac56..b6885f88d 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -704,6 +704,7 @@ fn decode_recv( let name = unsafe { name.assume_init() }; let mut ecn_bits = 0; let mut dst_ip = None; + let mut interface_index = None; #[allow(unused_mut)] // only mutable on Linux let mut stride = len; @@ -736,6 +737,7 @@ fn decode_recv( dst_ip = Some(IpAddr::V4(Ipv4Addr::from( pktinfo.ipi_addr.s_addr.to_ne_bytes(), ))); + interface_index = Some(pktinfo.ipi_ifindex as u32); } #[cfg(any(bsd, apple))] (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { @@ -745,6 +747,7 @@ fn decode_recv( (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { let pktinfo = unsafe { cmsg::decode::(cmsg) }; dst_ip = Some(IpAddr::V6(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr))); + interface_index = Some(pktinfo.ipi6_ifindex as u32); } #[cfg(any(target_os = "linux", target_os = "android"))] (libc::SOL_UDP, gro::UDP_GRO) => unsafe { @@ -784,6 +787,7 @@ fn decode_recv( addr, ecn: EcnCodepoint::from_bits(ecn_bits), dst_ip, + interface_index, } } diff --git a/quinn-udp/src/windows.rs b/quinn-udp/src/windows.rs index 1e0410722..612840c4d 100644 --- a/quinn-udp/src/windows.rs +++ b/quinn-udp/src/windows.rs @@ -225,6 +225,7 @@ impl UdpSocketState { // Decode control messages (PKTINFO and ECN) let mut ecn_bits = 0; let mut dst_ip = None; + let mut interface_index = None; let mut stride = len; let cmsg_iter = unsafe { cmsg::Iter::new(&wsa_msg) }; @@ -238,12 +239,14 @@ impl UdpSocketState { // Addr is stored in big endian format let ip4 = Ipv4Addr::from(u32::from_be(unsafe { pktinfo.ipi_addr.S_un.S_addr })); dst_ip = Some(ip4.into()); + interface_index = Some(pktinfo.ipi_ifindex); } (WinSock::IPPROTO_IPV6, WinSock::IPV6_PKTINFO) => { let pktinfo = unsafe { cmsg::decode::(cmsg) }; // Addr is stored in big endian format dst_ip = Some(IpAddr::from(unsafe { pktinfo.ipi6_addr.u.Byte })); + interface_index = Some(pktinfo.ipi6_ifindex); } (WinSock::IPPROTO_IP, WinSock::IP_ECN) => { // ECN is a C integer https://learn.microsoft.com/en-us/windows/win32/winsock/winsock-ecn @@ -268,6 +271,7 @@ impl UdpSocketState { addr: addr.unwrap(), ecn: EcnCodepoint::from_bits(ecn_bits as u8), dst_ip, + interface_index, }; Ok(1) } From c4eaafa95023d24f3238557d61f97608837218ca Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 8 Sep 2025 16:35:05 +0200 Subject: [PATCH 23/71] Update semver-compatible dependencies --- Cargo.lock | 149 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 883e91edd..c714ea363 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,9 +426,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.3" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "blocking" @@ -480,10 +480,11 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.34" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -556,9 +557,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" dependencies = [ "clap_builder", "clap_derive", @@ -566,9 +567,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" dependencies = [ "anstream", "anstyle", @@ -578,9 +579,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.45" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck", "proc-macro2", @@ -798,9 +799,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", ] @@ -915,6 +916,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "flate2" version = "1.1.2" @@ -1036,7 +1043,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.4+wasi-0.2.4", "wasm-bindgen", ] @@ -1459,9 +1466,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -1551,9 +1558,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lru-slab" @@ -1825,9 +1832,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -2305,9 +2312,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" dependencies = [ "bitflags", "core-foundation", @@ -2318,9 +2325,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -2561,12 +2568,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -2578,15 +2584,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2894,29 +2900,30 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -2928,9 +2935,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -2941,9 +2948,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2951,9 +2958,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -2964,18 +2971,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +checksum = "80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad" dependencies = [ "js-sys", "minicov", @@ -2986,9 +2993,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +checksum = "c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d" dependencies = [ "proc-macro2", "quote", @@ -2997,9 +3004,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -3054,11 +3061,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -3073,6 +3080,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-sys" version = "0.45.0" @@ -3109,6 +3122,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -3146,7 +3168,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -3296,13 +3318,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "writeable" @@ -3345,18 +3364,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", From 3e302f728207ae0e85332c110c8a2950bb8dfbda Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 8 Sep 2025 16:35:38 +0200 Subject: [PATCH 24/71] Upgrade windows-sys to 0.61 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c714ea363..ccb7dcc3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1991,7 +1991,7 @@ dependencies = [ "socket2 0.6.0", "tokio", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index aa5825413..8af1b0b6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ tracing-subscriber = { version = "0.3.0", default-features = false, features = [ url = "2" wasm-bindgen-test = { version = "0.3.45" } web-time = "1" -windows-sys = { version = ">=0.52, <=0.60", features = ["Win32_Foundation", "Win32_System_IO", "Win32_Networking_WinSock"] } +windows-sys = { version = ">=0.52, <=0.61", features = ["Win32_Foundation", "Win32_System_IO", "Win32_Networking_WinSock"] } cfg_aliases = "0.2" [profile.bench] From 74680528ca980da4bde701ce32e9963653bbe2f9 Mon Sep 17 00:00:00 2001 From: Max Leonard Inden Date: Sun, 14 Sep 2025 18:14:07 +0200 Subject: [PATCH 25/71] feat!(udp): mark RecvMeta as non_exhaustive Mark `RecvMeta` as non exhaustive such that subsequent field additions are not breaking changes. Fixes https://github.com/quinn-rs/quinn/issues/2378. --- quinn-udp/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/quinn-udp/src/lib.rs b/quinn-udp/src/lib.rs index 077fd42bb..eaceaf521 100644 --- a/quinn-udp/src/lib.rs +++ b/quinn-udp/src/lib.rs @@ -93,6 +93,7 @@ pub const BATCH_SIZE: usize = 1; /// /// [`stride`]: RecvMeta::stride #[derive(Debug, Copy, Clone)] +#[non_exhaustive] pub struct RecvMeta { /// The source address of the datagram(s) contained in the buffer pub addr: SocketAddr, From c1c56861cff978bcedddc4c4cd953eca1d1ef5b2 Mon Sep 17 00:00:00 2001 From: Max Leonard Inden Date: Sun, 14 Sep 2025 16:00:00 +0200 Subject: [PATCH 26/71] fix(udp/unix): don't panic on unknown address family We have reports that on some MacOS 10.15 systems, recvmsg can return a non IPv4 or IPv4 `RecvMeta`, potentially due to uninitialized memory. Instead of panicking on an unknown address family, simply return an IO error. Fixes https://github.com/quinn-rs/quinn/issues/2383. --- quinn-udp/src/unix.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index b6885f88d..f551d2229 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -498,7 +498,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) -> } }; for i in 0..(msg_count as usize) { - meta[i] = decode_recv(&names[i], &hdrs[i].msg_hdr, hdrs[i].msg_len as usize); + meta[i] = decode_recv(&names[i], &hdrs[i].msg_hdr, hdrs[i].msg_len as usize)?; } Ok(msg_count as usize) } @@ -533,7 +533,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) -> } }; for i in 0..(msg_count as usize) { - meta[i] = decode_recv(&names[i], &hdrs[i], hdrs[i].msg_datalen as usize); + meta[i] = decode_recv(&names[i], &hdrs[i], hdrs[i].msg_datalen as usize)?; } Ok(msg_count as usize) } @@ -562,7 +562,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) -> _ => return Err(e), } }; - meta[0] = decode_recv(&name, &hdr, n as usize); + meta[0] = decode_recv(&name, &hdr, n as usize)?; Ok(1) } @@ -700,7 +700,7 @@ fn decode_recv( #[cfg(not(apple_fast))] hdr: &libc::msghdr, #[cfg(apple_fast)] hdr: &msghdr_x, len: usize, -) -> RecvMeta { +) -> io::Result { let name = unsafe { name.assume_init() }; let mut ecn_bits = 0; let mut dst_ip = None; @@ -778,17 +778,21 @@ fn decode_recv( addr.sin6_scope_id, )) } - _ => unreachable!(), + f => { + return Err(io::Error::other(format!( + "expected AF_INET or AF_INET6, got {f} in decode_recv" + ))); + } }; - RecvMeta { + Ok(RecvMeta { len, stride, addr, ecn: EcnCodepoint::from_bits(ecn_bits), dst_ip, interface_index, - } + }) } #[cfg(not(apple_slow))] From 8449cf7ccb3f8eef4d788b434ac2399699b39918 Mon Sep 17 00:00:00 2001 From: Seto Date: Sun, 14 Sep 2025 21:35:27 +0200 Subject: [PATCH 27/71] Add watchOS to BSD-like OS target list --- quinn-udp/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quinn-udp/build.rs b/quinn-udp/build.rs index c43c0aa34..ed26e5e64 100644 --- a/quinn-udp/build.rs +++ b/quinn-udp/build.rs @@ -9,7 +9,8 @@ fn main() { target_os = "macos", target_os = "ios", target_os = "tvos", - target_os = "visionos" + target_os = "visionos", + target_os = "watchos" ) }, bsd: { From da0631246457f8449c980523703a0524151687ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:27:05 +0000 Subject: [PATCH 28/71] build(deps): bump rcgen from 0.14.3 to 0.14.4 Bumps [rcgen](https://github.com/rustls/rcgen) from 0.14.3 to 0.14.4. - [Release notes](https://github.com/rustls/rcgen/releases) - [Commits](https://github.com/rustls/rcgen/compare/v0.14.3...v0.14.4) --- updated-dependencies: - dependency-name: rcgen dependency-version: 0.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccb7dcc3d..71a4db8b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2079,9 +2079,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0068c5b3cab1d4e271e0bb6539c87563c43411cad90b057b15c79958fbeb41f7" +checksum = "4c83367ba62b3f1dbd0f086ede4e5ebfb4713fb234dbbc5807772a31245ff46d" dependencies = [ "pem", "ring", From f76410dc70e6a04b20a543ad80244b49a574abe9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:09:48 +0000 Subject: [PATCH 29/71] build(deps): bump serde from 1.0.219 to 1.0.223 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.219 to 1.0.223. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.219...v1.0.223) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.223 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71a4db8b9..e1bee6005 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2335,18 +2335,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" dependencies = [ "proc-macro2", "quote", From aaf63545cbd309113a3f2b5612ced7beffe81dc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:58:50 +0000 Subject: [PATCH 30/71] build(deps): bump async-io from 2.5.0 to 2.6.0 Bumps [async-io](https://github.com/smol-rs/async-io) from 2.5.0 to 2.6.0. - [Release notes](https://github.com/smol-rs/async-io/releases) - [Changelog](https://github.com/smol-rs/async-io/blob/master/CHANGELOG.md) - [Commits](https://github.com/smol-rs/async-io/compare/v2.5.0...v2.6.0) --- updated-dependencies: - dependency-name: async-io dependency-version: 2.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1bee6005..02aa446a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,11 +142,11 @@ dependencies = [ [[package]] name = "async-io" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", @@ -155,7 +155,7 @@ dependencies = [ "polling", "rustix 1.0.8", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -874,7 +874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -1509,7 +1509,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-targets 0.52.6", ] [[package]] @@ -2194,7 +2194,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] From b450a2e7587443f276a97755424692ebf7bcdc44 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Fri, 19 Sep 2025 06:40:04 +0200 Subject: [PATCH 31/71] Fix warning about unneeded sub cfg --- quinn/src/runtime/async_io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quinn/src/runtime/async_io.rs b/quinn/src/runtime/async_io.rs index eb5380665..7f995144b 100644 --- a/quinn/src/runtime/async_io.rs +++ b/quinn/src/runtime/async_io.rs @@ -55,7 +55,7 @@ impl AsyncTimer for Timer { } } -#[cfg(any(feature = "runtime-smol"))] +#[cfg(feature = "runtime-smol")] #[derive(Debug, Clone)] struct UdpSocket { io: Arc>, From a730d3dd58e9631bf1e9eee8167b21a4e3643f8a Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Fri, 19 Sep 2025 06:45:15 +0200 Subject: [PATCH 32/71] Update semver-compatible dependencies --- Cargo.lock | 204 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 117 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02aa446a0..7aa16f9e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "async-fs" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f7e37c0ed80b2a977691c47dae8625cfb21e205827106c64f7c588766b2e50" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" dependencies = [ "async-lock", "blocking", @@ -153,7 +153,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 1.0.8", + "rustix 1.1.2", "slab", "windows-sys 0.61.0", ] @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel", "async-io", @@ -195,14 +195,14 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 1.0.8", + "rustix 1.1.2", ] [[package]] name = "async-signal" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -210,10 +210,10 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.0.8", + "rustix 1.1.2", "signal-hook-registry", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -273,7 +273,7 @@ version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2608e5a7965cc9d58c56234d346c9c89b824c4c8652b6f047b3bd0a777c0644f" dependencies = [ - "bindgen", + "bindgen 0.69.5", "cc", "cmake", "dunce", @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" dependencies = [ "aws-lc-fips-sys", "aws-lc-sys", @@ -294,11 +294,11 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" dependencies = [ - "bindgen", + "bindgen 0.72.1", "cc", "cmake", "dunce", @@ -424,6 +424,26 @@ dependencies = [ "which", ] +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.1", + "shlex", + "syn", +] + [[package]] name = "bitflags" version = "2.9.4" @@ -480,9 +500,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.36" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ "find-msvc-tools", "jobserver", @@ -869,12 +889,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.0", ] [[package]] @@ -918,9 +938,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "flate2" @@ -1043,7 +1063,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.4+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", "wasm-bindgen", ] @@ -1071,7 +1091,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.0", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -1096,9 +1116,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "hdrhistogram" @@ -1188,9 +1208,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" @@ -1230,9 +1250,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "bytes", "futures-channel", @@ -1374,12 +1394,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", ] [[package]] @@ -1466,9 +1486,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -1509,7 +1529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.3", ] [[package]] @@ -1520,9 +1540,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags", "libc", @@ -1536,9 +1556,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -1818,16 +1838,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.0.8", - "windows-sys 0.60.2", + "rustix 1.1.2", + "windows-sys 0.61.0", ] [[package]] @@ -2186,15 +2206,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.52.0", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.0", ] [[package]] @@ -2264,9 +2284,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" dependencies = [ "aws-lc-rs", "ring", @@ -2297,11 +2317,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -2335,9 +2355,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.223" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ "serde_core", "serde_derive", @@ -2345,18 +2365,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.223" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.223" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", @@ -2365,15 +2385,16 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.11.4", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -2843,9 +2864,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "untrusted" @@ -2910,18 +2931,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.4+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", @@ -2931,9 +2961,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" dependencies = [ "bumpalo", "log", @@ -2945,9 +2975,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.51" +version = "0.4.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" dependencies = [ "cfg-if", "js-sys", @@ -2958,9 +2988,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2968,9 +2998,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", @@ -2981,18 +3011,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad" +checksum = "aee0a0f5343de9221a0d233b04520ed8dc2e6728dce180b1dcd9288ec9d9fa3c" dependencies = [ "js-sys", "minicov", @@ -3003,9 +3033,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d" +checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d" dependencies = [ "proc-macro2", "quote", @@ -3014,9 +3044,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" dependencies = [ "js-sys", "wasm-bindgen", @@ -3329,9 +3359,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" From 93b6d01605147b9763ee1b1b381a6feb9fcd454e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 13:02:21 +0000 Subject: [PATCH 33/71] build(deps): bump serde from 1.0.225 to 1.0.226 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.225 to 1.0.226. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.225...v1.0.226) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.226 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7aa16f9e8..31ad7810d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2355,9 +2355,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" dependencies = [ "serde_core", "serde_derive", @@ -2365,18 +2365,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" dependencies = [ "proc-macro2", "quote", From 2515f343c0d7b8f41f4d0ef3ba57f7e8bff8562e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 23:45:06 +0000 Subject: [PATCH 34/71] build(deps): bump rcgen from 0.14.4 to 0.14.5 Bumps [rcgen](https://github.com/rustls/rcgen) from 0.14.4 to 0.14.5. - [Release notes](https://github.com/rustls/rcgen/releases) - [Commits](https://github.com/rustls/rcgen/compare/v0.14.4...v0.14.5) --- updated-dependencies: - dependency-name: rcgen dependency-version: 0.14.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31ad7810d..f595e4b7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2099,9 +2099,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c83367ba62b3f1dbd0f086ede4e5ebfb4713fb234dbbc5807772a31245ff46d" +checksum = "5fae430c6b28f1ad601274e78b7dffa0546de0b73b4cd32f46723c0c2a16f7a5" dependencies = [ "pem", "ring", From 3dfd4c560dff33f85f6e51f170b01df10f55c4d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 17:42:58 +0000 Subject: [PATCH 35/71] build(deps): bump windows-sys from 0.61.0 to 0.61.1 Bumps [windows-sys](https://github.com/microsoft/windows-rs) from 0.61.0 to 0.61.1. - [Release notes](https://github.com/microsoft/windows-rs/releases) - [Commits](https://github.com/microsoft/windows-rs/commits) --- updated-dependencies: - dependency-name: windows-sys dependency-version: 0.61.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f595e4b7d..8d0e9cec1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,7 +155,7 @@ dependencies = [ "polling", "rustix 1.1.2", "slab", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -213,7 +213,7 @@ dependencies = [ "rustix 1.1.2", "signal-hook-registry", "slab", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -894,7 +894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.52.0", ] [[package]] @@ -1847,7 +1847,7 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix 1.1.2", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -2011,7 +2011,7 @@ dependencies = [ "socket2 0.6.0", "tokio", "tracing", - "windows-sys 0.61.0", + "windows-sys 0.52.0", ] [[package]] @@ -2214,7 +2214,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.0", + "windows-sys 0.52.0", ] [[package]] @@ -2321,7 +2321,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -3105,7 +3105,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.52.0", ] [[package]] @@ -3164,9 +3164,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link 0.2.0", ] From e340daa36e252de9e43419bff5e5c65ea454dd15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 17:43:56 +0000 Subject: [PATCH 36/71] build(deps): bump serde from 1.0.226 to 1.0.228 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.226 to 1.0.228. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.226...v1.0.228) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.228 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d0e9cec1..2811b5d0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2355,9 +2355,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -2365,18 +2365,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", From 6ce93786e2212c75b740528fc8cd80eba7bcdb9f Mon Sep 17 00:00:00 2001 From: Fabien Savy Date: Thu, 3 Jul 2025 09:15:37 +0200 Subject: [PATCH 37/71] regroup cubic state values --- quinn-proto/src/congestion/cubic.rs | 104 +++++++++++++++------------- 1 file changed, 57 insertions(+), 47 deletions(-) diff --git a/quinn-proto/src/congestion/cubic.rs b/quinn-proto/src/congestion/cubic.rs index 1bd9c69de..ff19f40b6 100644 --- a/quinn-proto/src/congestion/cubic.rs +++ b/quinn-proto/src/congestion/cubic.rs @@ -19,12 +19,27 @@ const C: f64 = 0.4; /// k, w_max are described in the RFC. #[derive(Debug, Default, Clone)] pub(super) struct State { + /// Time period that the cubic function takes to increase the window size to W_max. k: f64, + /// Congestion window size when the last congestion event occurred. w_max: f64, - // Store cwnd increment during congestion avoidance. + /// Congestion window increment stored during congestion avoidance. cwnd_inc: u64, + + /// Maximum number of bytes in flight that may be sent. + window: u64, + + /// Slow start threshold in bytes. + /// + /// When the congestion window is below ssthresh, the mode is slow start + /// and the window grows by the number of bytes acknowledged. + ssthresh: u64, + + /// The time when QUIC first detects a loss, causing it to enter recovery. When a packet sent + /// after this time is acknowledged, QUIC exits recovery. + recovery_start_time: Option, } /// CUBIC Functions. @@ -39,7 +54,7 @@ impl State { (w_max * (1.0 - BETA_CUBIC) / C).cbrt() } - // W_cubic(t) = C * (t - K)^3 - w_max (Eq. 1) + // W_cubic(t) = C * (t - K)^3 + w_max (Eq. 1) fn w_cubic(&self, t: Duration, max_datagram_size: u64) -> f64 { let w_max = self.w_max / max_datagram_size as f64; @@ -60,15 +75,7 @@ impl State { #[derive(Debug, Clone)] pub struct Cubic { config: Arc, - /// Maximum number of bytes in flight that may be sent. - window: u64, - /// Slow start threshold in bytes. When the congestion window is below ssthresh, the mode is - /// slow start and the window grows by the number of bytes acknowledged. - ssthresh: u64, - /// The time when QUIC first detects a loss, causing it to enter recovery. When a packet sent - /// after this time is acknowledged, QUIC exits recovery. - recovery_start_time: Option, - cubic_state: State, + state: State, current_mtu: u64, } @@ -76,12 +83,13 @@ impl Cubic { /// Construct a state using the given `config` and current time `now` pub fn new(config: Arc, _now: Instant, current_mtu: u16) -> Self { Self { - window: config.initial_window, - ssthresh: u64::MAX, - recovery_start_time: None, - config, - cubic_state: Default::default(), + state: State { + window: config.initial_window, + ssthresh: u64::MAX, + ..Default::default() + }, current_mtu: current_mtu as u64, + config, } } @@ -101,6 +109,7 @@ impl Controller for Cubic { ) { if app_limited || self + .state .recovery_start_time .map(|recovery_start_time| sent <= recovery_start_time) .unwrap_or(false) @@ -108,35 +117,35 @@ impl Controller for Cubic { return; } - if self.window < self.ssthresh { + if self.state.window < self.state.ssthresh { // Slow start - self.window += bytes; + self.state.window += bytes; } else { // Congestion avoidance. let ca_start_time; - match self.recovery_start_time { + match self.state.recovery_start_time { Some(t) => ca_start_time = t, None => { // When we come here without congestion_event() triggered, // initialize congestion_recovery_start_time, w_max and k. ca_start_time = now; - self.recovery_start_time = Some(now); + self.state.recovery_start_time = Some(now); - self.cubic_state.w_max = self.window as f64; - self.cubic_state.k = 0.0; + self.state.w_max = self.state.window as f64; + self.state.k = 0.0; } } let t = now - ca_start_time; // w_cubic(t + rtt) - let w_cubic = self.cubic_state.w_cubic(t + rtt.get(), self.current_mtu); + let w_cubic = self.state.w_cubic(t + rtt.get(), self.current_mtu); // w_est(t) - let w_est = self.cubic_state.w_est(t, rtt.get(), self.current_mtu); + let w_est = self.state.w_est(t, rtt.get(), self.current_mtu); - let mut cubic_cwnd = self.window; + let mut cubic_cwnd = self.state.window; if w_cubic < w_est { // TCP friendly region. @@ -150,14 +159,14 @@ impl Controller for Cubic { } // Update the increment and increase cwnd by MSS. - self.cubic_state.cwnd_inc += cubic_cwnd - self.window; + self.state.cwnd_inc += cubic_cwnd - self.state.window; // cwnd_inc can be more than 1 MSS in the late stage of max probing. // however RFC9002 §7.3.3 (Congestion Avoidance) limits // the increase of cwnd to 1 max_datagram_size per cwnd acknowledged. - if self.cubic_state.cwnd_inc >= self.current_mtu { - self.window += self.current_mtu; - self.cubic_state.cwnd_inc = 0; + if self.state.cwnd_inc >= self.current_mtu { + self.state.window += self.current_mtu; + self.state.cwnd_inc = 0; } } } @@ -170,6 +179,7 @@ impl Controller for Cubic { _lost_bytes: u64, ) { if self + .state .recovery_start_time .map(|recovery_start_time| sent <= recovery_start_time) .unwrap_or(false) @@ -177,53 +187,53 @@ impl Controller for Cubic { return; } - self.recovery_start_time = Some(now); + self.state.recovery_start_time = Some(now); // Fast convergence - if (self.window as f64) < self.cubic_state.w_max { - self.cubic_state.w_max = self.window as f64 * (1.0 + BETA_CUBIC) / 2.0; + if (self.state.window as f64) < self.state.w_max { + self.state.w_max = self.state.window as f64 * (1.0 + BETA_CUBIC) / 2.0; } else { - self.cubic_state.w_max = self.window as f64; + self.state.w_max = self.state.window as f64; } - self.ssthresh = cmp::max( - (self.cubic_state.w_max * BETA_CUBIC) as u64, + self.state.ssthresh = cmp::max( + (self.state.w_max * BETA_CUBIC) as u64, self.minimum_window(), ); - self.window = self.ssthresh; - self.cubic_state.k = self.cubic_state.cubic_k(self.current_mtu); + self.state.window = self.state.ssthresh; + self.state.k = self.state.cubic_k(self.current_mtu); - self.cubic_state.cwnd_inc = (self.cubic_state.cwnd_inc as f64 * BETA_CUBIC) as u64; + self.state.cwnd_inc = (self.state.cwnd_inc as f64 * BETA_CUBIC) as u64; if is_persistent_congestion { - self.recovery_start_time = None; - self.cubic_state.w_max = self.window as f64; + self.state.recovery_start_time = None; + self.state.w_max = self.state.window as f64; // 4.7 Timeout - reduce ssthresh based on BETA_CUBIC - self.ssthresh = cmp::max( - (self.window as f64 * BETA_CUBIC) as u64, + self.state.ssthresh = cmp::max( + (self.state.window as f64 * BETA_CUBIC) as u64, self.minimum_window(), ); - self.cubic_state.cwnd_inc = 0; + self.state.cwnd_inc = 0; - self.window = self.minimum_window(); + self.state.window = self.minimum_window(); } } fn on_mtu_update(&mut self, new_mtu: u16) { self.current_mtu = new_mtu as u64; - self.window = self.window.max(self.minimum_window()); + self.state.window = self.state.window.max(self.minimum_window()); } fn window(&self) -> u64 { - self.window + self.state.window } fn metrics(&self) -> super::ControllerMetrics { super::ControllerMetrics { congestion_window: self.window(), - ssthresh: Some(self.ssthresh), + ssthresh: Some(self.state.ssthresh), pacing_rate: None, } } From 531ca90ec9f8fc2f8cba05564bc8d3a439884975 Mon Sep 17 00:00:00 2001 From: Fabien Savy Date: Wed, 2 Jul 2025 09:43:23 +0200 Subject: [PATCH 38/71] spurious loss detection and recovery --- quinn-proto/src/congestion.rs | 7 ++++ quinn-proto/src/congestion/bbr/mod.rs | 1 + quinn-proto/src/congestion/cubic.rs | 19 ++++++++- quinn-proto/src/congestion/new_reno.rs | 1 + quinn-proto/src/connection/mod.rs | 55 +++++++++++++++++++++++++- quinn-proto/src/connection/spaces.rs | 11 ++++++ 6 files changed, 92 insertions(+), 2 deletions(-) diff --git a/quinn-proto/src/congestion.rs b/quinn-proto/src/congestion.rs index 391e4d19c..6b34e2854 100644 --- a/quinn-proto/src/congestion.rs +++ b/quinn-proto/src/congestion.rs @@ -56,9 +56,16 @@ pub trait Controller: Send + Sync { now: Instant, sent: Instant, is_persistent_congestion: bool, + is_ecn: bool, lost_bytes: u64, ); + /// Packets were incorrectly deemed lost + /// + /// This function is called when all packets that were deemed lost (for instance because + /// of packet reordering) are acknowledged after the congestion event was raised. + fn on_spurious_congestion_event(&mut self) {} + /// The known MTU for the current network path has been updated fn on_mtu_update(&mut self, new_mtu: u16); diff --git a/quinn-proto/src/congestion/bbr/mod.rs b/quinn-proto/src/congestion/bbr/mod.rs index 97fb3bffc..458716230 100644 --- a/quinn-proto/src/congestion/bbr/mod.rs +++ b/quinn-proto/src/congestion/bbr/mod.rs @@ -465,6 +465,7 @@ impl Controller for Bbr { _now: Instant, _sent: Instant, _is_persistent_congestion: bool, + _is_ecn: bool, lost_bytes: u64, ) { self.loss_state.lost_bytes += lost_bytes; diff --git a/quinn-proto/src/congestion/cubic.rs b/quinn-proto/src/congestion/cubic.rs index ff19f40b6..08db3ddad 100644 --- a/quinn-proto/src/congestion/cubic.rs +++ b/quinn-proto/src/congestion/cubic.rs @@ -75,8 +75,10 @@ impl State { #[derive(Debug, Clone)] pub struct Cubic { config: Arc, - state: State, current_mtu: u64, + state: State, + /// Copy of the controller state to restore when a spurious congestion event is detected. + pre_congestion_state: Option, } impl Cubic { @@ -89,6 +91,7 @@ impl Cubic { ..Default::default() }, current_mtu: current_mtu as u64, + pre_congestion_state: None, config, } } @@ -176,6 +179,7 @@ impl Controller for Cubic { now: Instant, sent: Instant, is_persistent_congestion: bool, + is_ecn: bool, _lost_bytes: u64, ) { if self @@ -187,6 +191,11 @@ impl Controller for Cubic { return; } + // Save state in case this event ends up being spurious + if !is_ecn { + self.pre_congestion_state = Some(self.state.clone()); + } + self.state.recovery_start_time = Some(now); // Fast convergence @@ -221,6 +230,14 @@ impl Controller for Cubic { } } + fn on_spurious_congestion_event(&mut self) { + if let Some(prior_state) = self.pre_congestion_state.take() { + if self.state.window < prior_state.window { + self.state = prior_state; + } + } + } + fn on_mtu_update(&mut self, new_mtu: u16) { self.current_mtu = new_mtu as u64; self.state.window = self.state.window.max(self.minimum_window()); diff --git a/quinn-proto/src/congestion/new_reno.rs b/quinn-proto/src/congestion/new_reno.rs index 7bc61c666..90a6fa2c5 100644 --- a/quinn-proto/src/congestion/new_reno.rs +++ b/quinn-proto/src/congestion/new_reno.rs @@ -87,6 +87,7 @@ impl Controller for NewReno { now: Instant, sent: Instant, is_persistent_congestion: bool, + _is_ecn: bool, _lost_bytes: u64, ) { if sent <= self.recovery_start_time { diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 4ab5e3363..80a7e01d1 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -22,6 +22,7 @@ use crate::{ cid_queue::CidQueue, coding::BufMutExt, config::{ServerConfig, TransportConfig}, + connection::spaces::LostPacket, crypto::{self, KeyPair, Keys, PacketKey}, frame::{self, Close, Datagram, FrameStruct, NewConnectionId, NewToken}, packet::{ @@ -1461,6 +1462,10 @@ impl Connection { } }; + if self.detect_spurious_loss(&ack, space) { + self.path.congestion.on_spurious_congestion_event(); + } + // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks. let mut newly_acked = ArrayRangeSet::new(); for range in ack.iter() { @@ -1555,6 +1560,43 @@ impl Connection { Ok(()) } + fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId) -> bool { + let lost_packets = &mut self.spaces[space].lost_packets; + + if lost_packets.is_empty() { + return false; + } + + for range in ack.iter() { + let spurious_losses: Vec = lost_packets + .range(range.clone()) + .map(|(pn, _info)| pn) + .copied() + .collect(); + + for pn in spurious_losses { + lost_packets.remove(&pn); + } + } + + // If this ACK frame acknowledged all deemed lost packets, + // then we have raised a spurious congestion event in the past. + // We cannot conclude when there are remaining packets, + // but future ACK frames might indicate a spurious loss detection. + lost_packets.is_empty() + } + + /// Drain lost packets that we reasonably think will never arrive + /// + /// The current criterion is copied from `msquic`: + /// discard packets that were sent earlier than 2 probe timeouts ago. + fn drain_lost_packets(&mut self, now: Instant, space: SpaceId) { + let two_pto = 2 * self.path.rtt.pto_base(); + + let lost_packets = &mut self.spaces[space].lost_packets; + lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto); + } + /// Process a new ECN block from an in-order ACK fn process_ecn( &mut self, @@ -1577,7 +1619,7 @@ impl Connection { self.stats.path.congestion_events += 1; self.path .congestion - .on_congestion_event(now, largest_sent_time, false, 0); + .on_congestion_event(now, largest_sent_time, false, true, 0); } } } @@ -1735,6 +1777,8 @@ impl Connection { prev_packet = Some(packet); } + self.drain_lost_packets(now, pn_space); + // OnPacketsLost if let Some(largest_lost) = lost_packets.last().cloned() { let old_bytes_in_flight = self.path.in_flight.bytes; @@ -1756,12 +1800,20 @@ impl Connection { now, self.orig_rem_cid, ); + self.remove_in_flight(&info); for frame in info.stream_frames { self.streams.retransmit(frame); } self.spaces[pn_space].pending |= info.retransmits; self.path.mtud.on_non_probe_lost(packet, info.size); + + self.spaces[pn_space].lost_packets.insert( + packet, + LostPacket { + time_sent: info.time_sent, + }, + ); } if self.path.mtud.black_hole_detected(now) { @@ -1783,6 +1835,7 @@ impl Connection { now, largest_lost_sent, in_persistent_congestion, + false, size_of_lost_packets, ); } diff --git a/quinn-proto/src/connection/spaces.rs b/quinn-proto/src/connection/spaces.rs index 8282f70b9..0a4ac0ad1 100644 --- a/quinn-proto/src/connection/spaces.rs +++ b/quinn-proto/src/connection/spaces.rs @@ -39,6 +39,9 @@ pub(super) struct PacketSpace { /// Transmitted but not acked // We use a BTreeMap here so we can efficiently query by range on ACK and for loss detection pub(super) sent_packets: BTreeMap, + /// Packets that were deemed lost + // Older packets are regularly removed in `Connection::drain_lost_packets`. + pub(super) lost_packets: BTreeMap, /// Number of explicit congestion notification codepoints seen on incoming packets pub(super) ecn_counters: frame::EcnCounts, /// Recent ECN counters sent by the peer in ACK frames @@ -84,6 +87,7 @@ impl PacketSpace { largest_ack_eliciting_sent: 0, unacked_non_ack_eliciting_tail: 0, sent_packets: BTreeMap::new(), + lost_packets: BTreeMap::new(), ecn_counters: frame::EcnCounts::ZERO, ecn_feedback: frame::EcnCounts::ZERO, @@ -302,6 +306,13 @@ pub(super) struct SentPacket { pub(super) stream_frames: frame::StreamMetaVec, } +/// Represents one or more packets that are deemed lost. +#[derive(Debug)] +pub(super) struct LostPacket { + /// The time the packet was sent. + pub(super) time_sent: Instant, +} + /// Retransmittable data queue #[allow(unreachable_pub)] // fuzzing only #[derive(Debug, Default, Clone)] From 719cc78866193506d96c00094d350e287af8f229 Mon Sep 17 00:00:00 2001 From: Pablo Sichert Date: Wed, 1 Oct 2025 13:46:26 +0200 Subject: [PATCH 39/71] Use `saturating_mul` when calculating `congestion_period` to not panic on overflow --- quinn-proto/src/connection/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 80a7e01d1..869fa3df4 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -1721,8 +1721,9 @@ impl Connection { // InPersistentCongestion: Determine if all packets in the time period before the newest // lost packet, including the edges, are marked lost. PTO computation must always // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1). - let congestion_period = - self.pto(SpaceId::Data) * self.config.persistent_congestion_threshold; + let congestion_period = self + .pto(SpaceId::Data) + .saturating_mul(self.config.persistent_congestion_threshold); let mut persistent_congestion_start: Option = None; let mut prev_packet = None; let mut in_persistent_congestion = false; From a43918cfed28228a3f3acbfc236ba7c1e9b826bf Mon Sep 17 00:00:00 2001 From: David Emett Date: Mon, 29 Sep 2025 17:03:09 +0100 Subject: [PATCH 40/71] Fix some comparisons in the black hole detector Lost packets with size exactly matching the minimum MTU should not be treated as suspicious; by definition the MTU will never be reduced below this. Similarly, lost packets with size exactly matching a more recent successfully transmitted packet should not be treated as suspicious. --- quinn-proto/src/connection/mtud.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quinn-proto/src/connection/mtud.rs b/quinn-proto/src/connection/mtud.rs index b690731b4..51a5f4763 100644 --- a/quinn-proto/src/connection/mtud.rs +++ b/quinn-proto/src/connection/mtud.rs @@ -450,9 +450,9 @@ impl BlackHoleDetector { }; // If a loss burst contains a packet smaller than the minimum MTU or a more recently // transmitted packet, it is not suspicious. - if burst.smallest_packet_size < self.min_mtu + if burst.smallest_packet_size <= self.min_mtu || (burst.latest_non_probe < self.largest_post_loss_packet - && burst.smallest_packet_size < self.acked_mtu) + && burst.smallest_packet_size <= self.acked_mtu) { return; } From e05a8e5a7e4d068a98ec861ed722999f90f28a43 Mon Sep 17 00:00:00 2001 From: David Emett Date: Mon, 29 Sep 2025 17:15:36 +0100 Subject: [PATCH 41/71] Relax MTU discovery state assertion While we will never start probing before the connection has been established, it is possible for black hole detection to trigger, which will put MTU discovery into the Complete state. --- quinn-proto/src/connection/mtud.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/quinn-proto/src/connection/mtud.rs b/quinn-proto/src/connection/mtud.rs index 51a5f4763..7e6fc1d8a 100644 --- a/quinn-proto/src/connection/mtud.rs +++ b/quinn-proto/src/connection/mtud.rs @@ -83,9 +83,14 @@ impl MtuDiscovery { self.current_mtu = self.current_mtu.min(peer_max_udp_payload_size); if let Some(state) = self.state.as_mut() { - // MTUD is only active after the connection has been fully established, so it is - // guaranteed we will receive the peer's transport parameters before we start probing - debug_assert!(matches!(state.phase, Phase::Initial)); + // It is possible for black hole detection to trigger before the connection has been + // fully established, if the initial MTU is greater the minimum MTU. We should never + // send probes before the connection has been fully established and we have received + // the peer's transport parameters though. + debug_assert!( + !matches!(state.phase, Phase::Searching(_)), + "Transport parameters received after MTU probing started" + ); state.peer_max_udp_payload_size = peer_max_udp_payload_size; } } @@ -733,10 +738,14 @@ mod tests { #[cfg(debug_assertions)] #[test] - #[should_panic] - fn mtu_discovery_with_peer_max_udp_payload_size_after_search_panics() { + #[should_panic(expected = "Transport parameters received after MTU probing started")] + fn mtu_discovery_with_peer_max_udp_payload_size_during_search_panics() { let mut mtud = default_mtud(); - drive_to_completion(&mut mtud, Instant::now(), 1500); + assert!(mtud.poll_transmit(Instant::now(), 0).is_some()); + assert!(matches!( + mtud.state.as_ref().unwrap().phase, + Phase::Searching(_) + )); mtud.on_peer_max_udp_payload_size_received(1300); } From 1e44c69f866374c4b5bddc3a2d3d6ff328bb3634 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 13:44:22 +0000 Subject: [PATCH 42/71] build(deps): bump getrandom from 0.3.3 to 0.3.4 Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.3.3 to 0.3.4. - [Release notes](https://github.com/rust-random/getrandom/releases) - [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-random/getrandom/compare/v0.3.3...v0.3.4) --- updated-dependencies: - dependency-name: getrandom dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2811b5d0f..0c9d16793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -924,7 +924,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18c1ddb9231d8554c2d6bdf4cfaabf0c59251658c68b6c95cd52dd0c513a912a" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libm", "rand 0.9.2", "siphasher", @@ -1049,21 +1049,21 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] @@ -1480,7 +1480,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] @@ -1647,7 +1647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.59.0", ] @@ -1977,7 +1977,7 @@ dependencies = [ "aws-lc-rs", "bytes", "fastbloom", - "getrandom 0.3.3", + "getrandom 0.3.4", "hex-literal", "lazy_static", "lru-slab", @@ -2085,7 +2085,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -2929,15 +2929,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" From fc5e219fd9c9418c874f3db4e6d26d9cc32cea67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 13:46:07 +0000 Subject: [PATCH 43/71] build(deps): bump actions/setup-node from 4 to 6 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index dde8bc727..bf3f00a89 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -155,7 +155,7 @@ jobs: - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable - run: rustup target add wasm32-unknown-unknown - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: 20 - uses: bytecodealliance/actions/wasm-tools/setup@v1 From 0a6635d6b788f3e2d02e41048e289a8d316a9d21 Mon Sep 17 00:00:00 2001 From: ice-user Date: Fri, 24 Oct 2025 23:48:01 +0530 Subject: [PATCH 44/71] =?UTF-8?q?fix(pacing):=20allow=20=C2=B10ns=20tolera?= =?UTF-8?q?nce=20in=20computes=5Fpause=5Fcorrectly=20test=20on=20i386=20-U?= =?UTF-8?q?sed=20Duration::abs=5Fdiff()=20instead=20of=20manual=20differen?= =?UTF-8?q?ce=20for=20cleaner=20and=20more=20robust=20duration=20compariso?= =?UTF-8?q?n.=20-added=20inline=20formatting=20as=20required.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quinn-proto/src/connection/pacing.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/quinn-proto/src/connection/pacing.rs b/quinn-proto/src/connection/pacing.rs index 39815606b..495f0954f 100644 --- a/quinn-proto/src/connection/pacing.rs +++ b/quinn-proto/src/connection/pacing.rs @@ -273,14 +273,18 @@ mod tests { let pace_duration = Duration::from_nanos((TARGET_BURST_INTERVAL.as_nanos() * 4 / 5) as u64); - assert_eq!( - pacer - .delay(rtt, mtu as u64, mtu, window, old_instant) - .expect("Send must be delayed") - .duration_since(old_instant), - pace_duration - ); + let actual_delay = pacer + .delay(rtt, mtu as u64, mtu, window, old_instant) + .expect("Send must be delayed") + .duration_since(old_instant); + let diff = actual_delay.abs_diff(pace_duration); + + // Allow up to 2ns difference due to rounding + assert!( + diff < Duration::from_nanos(2), + "expected ≈ {pace_duration:?}, got {actual_delay:?} (diff {diff:?})" + ); // Refill half of the tokens assert_eq!( pacer.delay( From 491b8b5deb14ff5c1e4ba709b7936855e63aeef5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:56:43 +0000 Subject: [PATCH 45/71] build(deps): bump rustls-platform-verifier from 0.6.1 to 0.6.2 Bumps [rustls-platform-verifier](https://github.com/rustls/rustls-platform-verifier) from 0.6.1 to 0.6.2. - [Release notes](https://github.com/rustls/rustls-platform-verifier/releases) - [Changelog](https://github.com/rustls/rustls-platform-verifier/blob/main/CHANGELOG) - [Commits](https://github.com/rustls/rustls-platform-verifier/compare/v/0.6.1...v/0.6.2) --- updated-dependencies: - dependency-name: rustls-platform-verifier dependency-version: 0.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c9d16793..e7b00be91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -894,7 +894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -2011,7 +2011,7 @@ dependencies = [ "socket2 0.6.0", "tokio", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -2214,7 +2214,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -2257,9 +2257,9 @@ dependencies = [ [[package]] name = "rustls-platform-verifier" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be59af91596cac372a6942530653ad0c3a246cdd491aaa9dcaee47f88d67d5a0" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ "core-foundation", "core-foundation-sys", @@ -2273,7 +2273,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2332,9 +2332,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags", "core-foundation", @@ -3096,7 +3096,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] From 814183176046f33712d9bdf28cffa501ed12bf44 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 29 Oct 2025 09:46:50 +0100 Subject: [PATCH 46/71] Take semver-compatible updates --- Cargo.lock | 653 ++++++++++++++++++++--------------------------------- 1 file changed, 242 insertions(+), 411 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7b00be91..fe8338111 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -19,9 +10,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -34,9 +25,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -49,9 +40,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -84,9 +75,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" @@ -153,9 +144,9 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 1.1.2", + "rustix", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -195,7 +186,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 1.1.2", + "rustix", ] [[package]] @@ -210,10 +201,10 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.1.2", + "rustix", "signal-hook-registry", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -269,11 +260,11 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-fips-sys" -version = "0.13.7" +version = "0.13.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2608e5a7965cc9d58c56234d346c9c89b824c4c8652b6f047b3bd0a777c0644f" +checksum = "ede71ad84efb06d748d9af3bc500b14957a96282a69a6833b1420dcacb411cc3" dependencies = [ - "bindgen 0.69.5", + "bindgen", "cc", "cmake", "dunce", @@ -283,9 +274,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" +checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" dependencies = [ "aws-lc-fips-sys", "aws-lc-sys", @@ -294,11 +285,11 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.31.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" +checksum = "107a4e9d9cab9963e04e84bb8dee0e25f2a987f9a8bad5ed054abd439caa8f8c" dependencies = [ - "bindgen 0.72.1", + "bindgen", "cc", "cmake", "dunce", @@ -352,21 +343,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base64" version = "0.21.7" @@ -401,29 +377,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn", - "which", -] - [[package]] name = "bindgen" version = "0.72.1" @@ -439,16 +392,16 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 2.1.1", + "rustc-hash", "shlex", "syn", ] [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blocking" @@ -500,9 +453,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.38" +version = "1.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" dependencies = [ "find-msvc-tools", "jobserver", @@ -527,9 +480,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -577,9 +530,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.47" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", "clap_derive", @@ -587,9 +540,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.47" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstream", "anstyle", @@ -599,9 +552,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -611,9 +564,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cmake" @@ -784,9 +737,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "darling" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ "darling_core", "darling_macro", @@ -794,9 +747,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", @@ -808,9 +761,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", @@ -819,9 +772,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] @@ -894,7 +847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -938,15 +891,15 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -1067,12 +1020,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "glob" version = "0.3.3" @@ -1100,12 +1047,13 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -1151,15 +1099,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71" -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "http" version = "1.3.1" @@ -1263,7 +1202,7 @@ dependencies = [ "hyper", "libc", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.1", "tokio", "tower-service", "tracing", @@ -1271,9 +1210,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1284,9 +1223,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1297,11 +1236,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1312,42 +1250,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1402,31 +1336,11 @@ dependencies = [ "hashbrown 0.16.0", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -1486,9 +1400,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -1500,17 +1414,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" -version = "0.2.175" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libfuzzer-sys" @@ -1524,12 +1432,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link", ] [[package]] @@ -1548,12 +1456,6 @@ dependencies = [ "libc", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -1562,17 +1464,16 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -1605,9 +1506,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -1638,17 +1539,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "wasi", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1663,11 +1565,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1694,15 +1596,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1711,9 +1604,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oorandom" @@ -1735,9 +1628,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1745,25 +1638,25 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "pem" -version = "3.0.5" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ "base64 0.22.1", - "serde", + "serde_core", ] [[package]] @@ -1787,7 +1680,7 @@ dependencies = [ "rustls", "serde", "serde_json", - "socket2 0.6.0", + "socket2 0.6.1", "tokio", "tracing", "tracing-subscriber", @@ -1846,15 +1739,15 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.1.2", - "windows-sys 0.61.1", + "rustix", + "windows-sys 0.61.2", ] [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -1886,9 +1779,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -1955,11 +1848,11 @@ dependencies = [ "quinn-udp", "rand 0.9.2", "rcgen", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "smol", - "socket2 0.6.0", - "thiserror 2.0.16", + "socket2 0.6.1", + "thiserror 2.0.17", "tokio", "tracing", "tracing-futures", @@ -1986,12 +1879,12 @@ dependencies = [ "rand_pcg", "rcgen", "ring", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "rustls-pki-types", "rustls-platform-verifier", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "tracing-subscriber", @@ -2008,17 +1901,17 @@ dependencies = [ "libc", "log", "once_cell", - "socket2 0.6.0", + "socket2 0.6.1", "tokio", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -2112,9 +2005,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] @@ -2132,9 +2025,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -2144,9 +2037,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -2155,9 +2048,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "ring" @@ -2173,37 +2066,12 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.2" @@ -2213,15 +2081,15 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", - "windows-sys 0.60.2", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" dependencies = [ "aws-lc-rs", "log", @@ -2235,9 +2103,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -2247,9 +2115,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -2273,7 +2141,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2284,9 +2152,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.6" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring", @@ -2321,7 +2189,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -2399,9 +2267,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.0" +version = "3.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" dependencies = [ "serde", "serde_derive", @@ -2410,9 +2278,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.0" +version = "3.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" dependencies = [ "darling", "proc-macro2", @@ -2444,6 +2312,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "siphasher" version = "1.0.1" @@ -2494,19 +2368,19 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "strsim" @@ -2522,9 +2396,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -2559,11 +2433,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -2579,9 +2453,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -2599,11 +2473,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.43" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", + "itoa", "libc", "num-conv", "num_threads", @@ -2615,15 +2490,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -2631,9 +2506,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -2666,29 +2541,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -2864,9 +2736,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "untrusted" @@ -2940,35 +2812,22 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.53" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -2979,9 +2838,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2989,31 +2848,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.53" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee0a0f5343de9221a0d233b04520ed8dc2e6728dce180b1dcd9288ec9d9fa3c" +checksum = "bfc379bfb624eb59050b509c13e77b4eb53150c350db69628141abce842f2373" dependencies = [ "js-sys", "minicov", @@ -3024,9 +2883,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.53" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d" +checksum = "085b2df989e1e6f9620c1311df6c996e83fe16f57792b272ce1e024ac16a90f1" dependencies = [ "proc-macro2", "quote", @@ -3035,9 +2894,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.80" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -3055,25 +2914,13 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" +checksum = "05d651ec480de84b762e7be71e6efa7461699c19d9e2c272c8d93455f567786e" dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "winapi" version = "0.3.9" @@ -3096,7 +2943,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3107,15 +2954,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -3135,31 +2976,22 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -3195,19 +3027,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -3224,9 +3056,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -3242,9 +3074,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -3260,9 +3092,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -3272,9 +3104,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -3290,9 +3122,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -3308,9 +3140,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -3326,9 +3158,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -3344,9 +3176,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "wit-bindgen" @@ -3356,9 +3188,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yasna" @@ -3371,11 +3203,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -3383,9 +3214,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -3436,15 +3267,15 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -3453,9 +3284,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -3464,9 +3295,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", From 994ab35b9f2d07f5ac940eb03c8ccc302d6f2198 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 29 Oct 2025 09:47:27 +0100 Subject: [PATCH 47/71] ci: pin wasm-bindgen-cli to match lockfile --- .github/workflows/rust.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index bf3f00a89..6721d9811 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -174,7 +174,8 @@ jobs: run: | ! wasm-tools print --skeleton target/wasm32-unknown-unknown/debug/quinn.wasm | grep 'import "env"' - - run: cargo binstall wasm-bindgen-cli --locked --no-confirm + # Match the version of wasm-bindgen used in `Cargo.lock` + - run: cargo binstall wasm-bindgen-cli@0.2.105 --locked --no-confirm - run: cargo test --locked -p quinn-proto --target wasm32-unknown-unknown msrv: From eee334dff6c2ada82e2125ae2e99b15ce6f4cbef Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 29 Oct 2025 10:21:11 +0100 Subject: [PATCH 48/71] ci: drop netbsd testing --- .github/workflows/rust.yml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6721d9811..ac68e9dfb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -35,31 +35,6 @@ jobs: cargo build --locked --all-targets && cargo test --locked && cargo test --locked -- --ignored stress && cargo test --locked --manifest-path fuzz/Cargo.toml && cargo test --locked -p quinn-udp --benches - test-netbsd: - name: test on netbsd - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - name: test on netbsd - uses: vmactions/netbsd-vm@v1 - with: - usesh: true - mem: 4096 - copyback: false - prepare: | - export PATH="/usr/sbin:/sbin:$PATH" - pkg_add curl - curl https://sh.rustup.rs -sSf --output rustup.sh - sh rustup.sh -y --profile minimal --default-toolchain stable - run: | - export PATH="$HOME/.cargo/bin:$PATH" - echo "===== rustc --version =====" - rustc --version - echo "===== uname -a =====" - uname -a - - cargo build --locked --all-targets && cargo test --locked && cargo test --locked -- --ignored stress && cargo test --locked --manifest-path fuzz/Cargo.toml && cargo test --locked -p quinn-udp --benches - test-solaris: name: test on solaris runs-on: ubuntu-latest From 84d392c23a80857e0cafccf0daced20bdad14728 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Thu, 30 Oct 2025 22:18:32 +0100 Subject: [PATCH 49/71] Apply suggestions from clippy 1.91 --- quinn-proto/src/connection/assembler.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/quinn-proto/src/connection/assembler.rs b/quinn-proto/src/connection/assembler.rs index 2288f5ecc..735e65981 100644 --- a/quinn-proto/src/connection/assembler.rs +++ b/quinn-proto/src/connection/assembler.rs @@ -314,8 +314,9 @@ impl PartialEq for Buffer { } } -#[derive(Debug)] +#[derive(Debug, Default)] enum State { + #[default] Ordered, Unordered { /// The set of offsets that have been received from the peer, including portions not yet @@ -330,12 +331,6 @@ impl State { } } -impl Default for State { - fn default() -> Self { - Self::Ordered - } -} - /// Error indicating that an ordered read was performed on a stream after an unordered read #[derive(Debug)] pub struct IllegalOrderedRead; From 8c0f2a21e9cffc8969ac261956ee484f7d038758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Kr=C3=BCger?= Date: Mon, 10 Nov 2025 10:39:18 +0100 Subject: [PATCH 50/71] Refactor `QlogSink::emit_packet_lost` to take `loss_delay` instead of `lost_send_time` --- quinn-proto/src/connection/mod.rs | 2 +- quinn-proto/src/connection/qlog.rs | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 869fa3df4..a33bbb7a2 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -1796,7 +1796,7 @@ impl Connection { self.config.qlog_sink.emit_packet_lost( packet, &info, - lost_send_time, + loss_delay, pn_space, now, self.orig_rem_cid, diff --git a/quinn-proto/src/connection/qlog.rs b/quinn-proto/src/connection/qlog.rs index a324746f1..dafba3c47 100644 --- a/quinn-proto/src/connection/qlog.rs +++ b/quinn-proto/src/connection/qlog.rs @@ -3,6 +3,7 @@ #[cfg(feature = "qlog")] use std::sync::{Arc, Mutex}; +use std::time::Duration; #[cfg(feature = "qlog")] use qlog::{ @@ -86,7 +87,7 @@ impl QlogSink { &self, pn: u64, info: &SentPacket, - lost_send_time: Instant, + loss_delay: Duration, space: SpaceId, now: Instant, orig_rem_cid: ConnectionId, @@ -105,10 +106,12 @@ impl QlogSink { ..Default::default() }), frames: None, - trigger: Some(match info.time_sent <= lost_send_time { - true => PacketLostTrigger::TimeThreshold, - false => PacketLostTrigger::ReorderingThreshold, - }), + trigger: Some( + match info.time_sent.saturating_duration_since(now) >= loss_delay { + true => PacketLostTrigger::TimeThreshold, + false => PacketLostTrigger::ReorderingThreshold, + }, + ), }; stream.emit_event(orig_rem_cid, EventData::PacketLost(event), now); From 4f7f3e7d827fefe9861f632b8610e54b84abca80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Kr=C3=BCger?= Date: Mon, 3 Nov 2025 14:41:18 +0100 Subject: [PATCH 51/71] Remove `instant_saturating_sub` fn in favor of `Instant::saturating_duration_since` --- quinn-proto/src/connection/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index a33bbb7a2..26f8f95e1 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -1523,7 +1523,7 @@ impl Connection { Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0), ) }; - let rtt = instant_saturating_sub(now, self.spaces[space].largest_acked_packet_sent); + let rtt = now.saturating_duration_since(self.spaces[space].largest_acked_packet_sent); self.path.rtt.update(ack_delay, rtt); if self.path.first_packet_after_rtt_sample.is_none() { self.path.first_packet_after_rtt_sample = @@ -4056,10 +4056,6 @@ pub enum Event { DatagramsUnblocked, } -fn instant_saturating_sub(x: Instant, y: Instant) -> Duration { - if x > y { x - y } else { Duration::ZERO } -} - fn get_max_ack_delay(params: &TransportParameters) -> Duration { Duration::from_micros(params.max_ack_delay.0 * 1000) } From b699e5c815ceb438cbca79e21eb06cc0d5cf8cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Kr=C3=BCger?= Date: Mon, 10 Nov 2025 15:05:06 +0100 Subject: [PATCH 52/71] Avoid underflow panic in packet loss `Instant` calculations --- quinn-proto/src/connection/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 26f8f95e1..b4a953597 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -1712,8 +1712,6 @@ impl Connection { let rtt = self.path.rtt.conservative(); let loss_delay = cmp::max(rtt.mul_f32(self.config.time_threshold), TIMER_GRANULARITY); - // Packets sent before this time are deemed lost. - let lost_send_time = now.checked_sub(loss_delay).unwrap(); let largest_acked_packet = self.spaces[pn_space].largest_acked_packet.unwrap(); let packet_threshold = self.config.packet_threshold as u64; let mut size_of_lost_packets = 0u64; @@ -1737,8 +1735,11 @@ impl Connection { persistent_congestion_start = None; } - if info.time_sent <= lost_send_time || largest_acked_packet >= packet + packet_threshold - { + // Packets sent before now - loss_delay are deemed lost. + // However, we avoid this subtraction as it can panic and there's no + // saturating equivalent of this substraction operation with a Duration. + let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay; + if packet_too_old || largest_acked_packet >= packet + packet_threshold { if Some(packet) == in_flight_mtu_probe { // Lost MTU probes are not included in `lost_packets`, because they should not // trigger a congestion control response From 425b8b45f60d50eacec387def6372a221e268dea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:11:55 +0000 Subject: [PATCH 53/71] build(deps): bump console-subscriber from 0.4.1 to 0.5.0 Bumps [console-subscriber](https://github.com/tokio-rs/console) from 0.4.1 to 0.5.0. - [Release notes](https://github.com/tokio-rs/console/releases) - [Changelog](https://github.com/tokio-rs/console/blob/main/release-plz.toml) - [Commits](https://github.com/tokio-rs/console/compare/console-subscriber-v0.4.1...console-subscriber-v0.5.0) --- updated-dependencies: - dependency-name: console-subscriber dependency-version: 0.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 188 +++++++++++++----------------------------------- perf/Cargo.toml | 2 +- 2 files changed, 52 insertions(+), 138 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe8338111..67ca3690c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -207,28 +207,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-task" version = "4.7.1" @@ -298,11 +276,10 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.9" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" dependencies = [ - "async-trait", "axum-core", "bytes", "futures-util", @@ -315,29 +292,26 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "sync_wrapper", - "tower 0.5.2", + "tower", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.5" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ - "async-trait", "bytes", - "futures-util", + "futures-core", "http", "http-body", "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -604,22 +578,23 @@ dependencies = [ [[package]] name = "console-api" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8030735ecb0d128428b64cd379809817e620a40e5001c54465b99ec5feec2857" +checksum = "e8599749b6667e2f0c910c1d0dff6901163ff698a52d5a39720f61b5be4b20d3" dependencies = [ "futures-core", "prost", "prost-types", "tonic", + "tonic-prost", "tracing-core", ] [[package]] name = "console-subscriber" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6539aa9c6a4cd31f4b1c040f860a1eac9aa80e7df6b05d506a6e7179936d6a01" +checksum = "fb4915b7d8dd960457a1b6c380114c2944f728e7c65294ab247ae6b6f1f37592" dependencies = [ "console-api", "crossbeam-channel", @@ -879,7 +854,7 @@ checksum = "18c1ddb9231d8554c2d6bdf4cfaabf0c59251658c68b6c95cd52dd0c513a912a" dependencies = [ "getrandom 0.3.4", "libm", - "rand 0.9.2", + "rand", "siphasher", ] @@ -1038,7 +1013,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.4", + "indexmap", "slab", "tokio", "tokio-util", @@ -1056,12 +1031,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.16.0" @@ -1202,7 +1171,7 @@ dependencies = [ "hyper", "libc", "pin-project-lite", - "socket2 0.6.1", + "socket2", "tokio", "tower-service", "tracing", @@ -1316,16 +1285,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.11.4" @@ -1333,7 +1292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown", ] [[package]] @@ -1500,9 +1459,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" @@ -1680,7 +1639,7 @@ dependencies = [ "rustls", "serde", "serde_json", - "socket2 0.6.1", + "socket2", "tokio", "tracing", "tracing-subscriber", @@ -1788,9 +1747,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" dependencies = [ "bytes", "prost-derive", @@ -1798,9 +1757,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ "anyhow", "itertools 0.14.0", @@ -1811,9 +1770,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" dependencies = [ "prost", ] @@ -1846,12 +1805,12 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rand 0.9.2", + "rand", "rcgen", "rustc-hash", "rustls", "smol", - "socket2 0.6.1", + "socket2", "thiserror 2.0.17", "tokio", "tracing", @@ -1875,7 +1834,7 @@ dependencies = [ "lazy_static", "lru-slab", "qlog", - "rand 0.9.2", + "rand", "rand_pcg", "rcgen", "ring", @@ -1901,7 +1860,7 @@ dependencies = [ "libc", "log", "once_cell", - "socket2 0.6.1", + "socket2", "tokio", "tracing", "windows-sys 0.61.2", @@ -1922,35 +1881,14 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "rand_chacha", + "rand_core", ] [[package]] @@ -1960,16 +1898,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", + "rand_core", ] [[package]] @@ -1987,7 +1916,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b48ac3f7ffaab7fac4d2376632268aa5f89abdb55f7ebf8f4d11fffccb2320f7" dependencies = [ - "rand_core 0.9.3", + "rand_core", ] [[package]] @@ -2257,7 +2186,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.4", + "indexmap", "itoa", "memchr", "ryu", @@ -2356,16 +2285,6 @@ dependencies = [ "futures-lite", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.1" @@ -2550,7 +2469,7 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2", "tokio-macros", "tracing", "windows-sys 0.61.2", @@ -2593,11 +2512,10 @@ dependencies = [ [[package]] name = "tonic" -version = "0.12.3" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" dependencies = [ - "async-stream", "async-trait", "axum", "base64 0.22.1", @@ -2611,34 +2529,25 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", - "socket2 0.5.10", + "socket2", + "sync_wrapper", "tokio", "tokio-stream", - "tower 0.4.13", + "tower", "tower-layer", "tower-service", "tracing", ] [[package]] -name = "tower" -version = "0.4.13" +name = "tonic-prost" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", + "bytes", + "prost", + "tonic", ] [[package]] @@ -2649,10 +2558,15 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap", "pin-project-lite", + "slab", "sync_wrapper", + "tokio", + "tokio-util", "tower-layer", "tower-service", + "tracing", ] [[package]] diff --git a/perf/Cargo.toml b/perf/Cargo.toml index 2cdb1586c..348174698 100644 --- a/perf/Cargo.toml +++ b/perf/Cargo.toml @@ -28,7 +28,7 @@ tokio-console = ["console-subscriber"] anyhow = { workspace = true } bytes = { workspace = true } clap = { workspace = true } -console-subscriber = { version = "0.4.1", features = ["parking_lot"], optional = true } +console-subscriber = { version = "0.5.0", features = ["parking_lot"], optional = true } hdrhistogram = { workspace = true } quinn = { path = "../quinn" } quinn-proto = { path = "../quinn-proto" } From 7fc33f4143f1084e9839f858177fc9cb7720a084 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:12:14 +0000 Subject: [PATCH 54/71] build(deps): bump hex-literal from 1.0.0 to 1.1.0 Bumps [hex-literal](https://github.com/RustCrypto/utils) from 1.0.0 to 1.1.0. - [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v1.0.0...hex-literal-v1.1.0) --- updated-dependencies: - dependency-name: hex-literal dependency-version: 1.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67ca3690c..3e75f1b37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1064,9 +1064,9 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex-literal" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" [[package]] name = "http" From 35cefdd003cbf875ef18cce6e964b30be3044d43 Mon Sep 17 00:00:00 2001 From: Cathal Mullan Date: Fri, 14 Nov 2025 11:37:47 +0000 Subject: [PATCH 55/71] Bump MSRV to 1.80, remove `once_cell` and `lazy_static` deps --- .github/workflows/rust.yml | 2 +- Cargo.lock | 2 -- Cargo.toml | 4 +--- README.md | 2 +- quinn-proto/Cargo.toml | 1 - quinn-proto/src/connection/streams/state.rs | 6 ++---- quinn-proto/src/tests/util.rs | 14 ++++++-------- quinn-proto/src/token.rs | 3 +-- quinn-udp/Cargo.toml | 1 - quinn-udp/src/windows.rs | 8 +++----- quinn/src/runtime.rs | 6 ++---- quinn/src/runtime/async_io.rs | 3 +-- 12 files changed, 18 insertions(+), 34 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ac68e9dfb..e5a8f7da6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -158,7 +158,7 @@ jobs: steps: - uses: actions/checkout@v5 # Note that we must also update the README when changing the MSRV - - uses: dtolnay/rust-toolchain@1.74.1 + - uses: dtolnay/rust-toolchain@1.80.0 - uses: Swatinem/rust-cache@v2 - run: cargo check --locked --lib --all-features -p quinn-udp -p quinn-proto -p quinn diff --git a/Cargo.lock b/Cargo.lock index 3e75f1b37..d6fcbbb83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1831,7 +1831,6 @@ dependencies = [ "fastbloom", "getrandom 0.3.4", "hex-literal", - "lazy_static", "lru-slab", "qlog", "rand", @@ -1859,7 +1858,6 @@ dependencies = [ "criterion", "libc", "log", - "once_cell", "socket2", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 8af1b0b6a..91f5b51b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ default-members = ["quinn", "quinn-proto", "quinn-udp", "bench", "perf"] resolver = "2" [workspace.package] -rust-version = "1.74.1" +rust-version = "1.80.0" edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/quinn-rs/quinn" @@ -28,9 +28,7 @@ getrandom = { version = "0.3", default-features = false } hdrhistogram = { version = "7.2", default-features = false } hex-literal = "1" lru-slab = "0.1.2" -lazy_static = "1" log = "0.4" -once_cell = "1.19" pin-project-lite = "0.2" qlog = "0.15.2" rand = "0.9" diff --git a/README.md b/README.md index a4edbff08..f34e42c96 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.74.1 +- Minimum supported Rust version of 1.80.0 ## Overview diff --git a/quinn-proto/Cargo.toml b/quinn-proto/Cargo.toml index 1b038eaf8..3b41b4d34 100644 --- a/quinn-proto/Cargo.toml +++ b/quinn-proto/Cargo.toml @@ -72,7 +72,6 @@ hex-literal = { workspace = true } rand_pcg = "0.9" rcgen = { workspace = true } tracing-subscriber = { workspace = true } -lazy_static = "1" wasm-bindgen-test = { workspace = true } [lints.rust] diff --git a/quinn-proto/src/connection/streams/state.rs b/quinn-proto/src/connection/streams/state.rs index 09644fea0..810e916f9 100644 --- a/quinn-proto/src/connection/streams/state.rs +++ b/quinn-proto/src/connection/streams/state.rs @@ -256,9 +256,8 @@ impl StreamsState { payload_len: usize, ) -> Result { let id = frame.id; - self.validate_receive_id(id).map_err(|e| { + self.validate_receive_id(id).inspect_err(|_| { debug!("received illegal STREAM frame"); - e })?; let rs = match self @@ -310,9 +309,8 @@ impl StreamsState { error_code, final_offset, } = frame; - self.validate_receive_id(id).map_err(|e| { + self.validate_receive_id(id).inspect_err(|_| { debug!("received illegal RESET_STREAM frame"); - e })?; let rs = match self diff --git a/quinn-proto/src/tests/util.rs b/quinn-proto/src/tests/util.rs index fd61e6118..445e2a9f1 100644 --- a/quinn-proto/src/tests/util.rs +++ b/quinn-proto/src/tests/util.rs @@ -7,12 +7,11 @@ use std::{ net::{Ipv6Addr, SocketAddr, UdpSocket}, ops::RangeFrom, str, - sync::{Arc, Mutex}, + sync::{Arc, LazyLock, Mutex}, }; use assert_matches::assert_matches; use bytes::BytesMut; -use lazy_static::lazy_static; use rustls::{ KeyLogFile, client::WebPkiServerVerifier, @@ -719,12 +718,11 @@ fn set_congestion_experienced( }) } -lazy_static! { - pub static ref SERVER_PORTS: Mutex> = Mutex::new(4433..); - pub static ref CLIENT_PORTS: Mutex> = Mutex::new(44433..); - pub(crate) static ref CERTIFIED_KEY: rcgen::CertifiedKey = - rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); -} +static SERVER_PORTS: LazyLock>> = LazyLock::new(|| Mutex::new(4433..)); +pub(crate) static CLIENT_PORTS: LazyLock>> = + LazyLock::new(|| Mutex::new(44433..)); +pub(crate) static CERTIFIED_KEY: LazyLock> = + LazyLock::new(|| rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap()); #[derive(Default)] struct SimpleTokenLog(Mutex>); diff --git a/quinn-proto/src/token.rs b/quinn-proto/src/token.rs index e4ab5ea52..c128d0603 100644 --- a/quinn-proto/src/token.rs +++ b/quinn-proto/src/token.rs @@ -247,9 +247,8 @@ impl Token { fn decode(key: &dyn HandshakeTokenKey, raw_token_bytes: &[u8]) -> Option { // Decrypt - // MSRV: split_at_checked requires 1.80.0 let nonce_slice_start = raw_token_bytes.len().checked_sub(size_of::())?; - let (sealed_token, nonce_bytes) = raw_token_bytes.split_at(nonce_slice_start); + let (sealed_token, nonce_bytes) = raw_token_bytes.split_at_checked(nonce_slice_start)?; let nonce = u128::from_le_bytes(nonce_bytes.try_into().unwrap()); diff --git a/quinn-udp/Cargo.toml b/quinn-udp/Cargo.toml index 75348be1a..a9da5bcc1 100644 --- a/quinn-udp/Cargo.toml +++ b/quinn-udp/Cargo.toml @@ -29,7 +29,6 @@ tracing = { workspace = true, optional = true } socket2 = { workspace = true } [target.'cfg(windows)'.dependencies] -once_cell = { workspace = true } windows-sys = { workspace = true } [dev-dependencies] diff --git a/quinn-udp/src/windows.rs b/quinn-udp/src/windows.rs index 612840c4d..ae1fb5033 100644 --- a/quinn-udp/src/windows.rs +++ b/quinn-udp/src/windows.rs @@ -4,12 +4,11 @@ use std::{ net::{IpAddr, Ipv4Addr}, os::windows::io::AsRawSocket, ptr, - sync::Mutex, + sync::{LazyLock, Mutex}, time::Instant, }; use libc::{c_int, c_uint}; -use once_cell::sync::Lazy; use windows_sys::Win32::Networking::WinSock; use crate::{ @@ -447,8 +446,7 @@ pub(crate) const BATCH_SIZE: usize = 1; const CMSG_LEN: usize = 128; const OPTION_ON: u32 = 1; -// FIXME this could use [`std::sync::OnceLock`] once the MSRV is bumped to 1.70 and upper -static WSARECVMSG_PTR: Lazy = Lazy::new(|| { +static WSARECVMSG_PTR: LazyLock = LazyLock::new(|| { let s = unsafe { WinSock::socket(WinSock::AF_INET as _, WinSock::SOCK_DGRAM as _, 0) }; if s == WinSock::INVALID_SOCKET { debug!( @@ -496,7 +494,7 @@ static WSARECVMSG_PTR: Lazy = Lazy::new(|| { wsa_recvmsg_ptr }); -static MAX_GSO_SEGMENTS: Lazy = Lazy::new(|| { +static MAX_GSO_SEGMENTS: LazyLock = LazyLock::new(|| { let socket = match std::net::UdpSocket::bind("[::]:0") .or_else(|_| std::net::UdpSocket::bind((Ipv4Addr::LOCALHOST, 0))) { diff --git a/quinn/src/runtime.rs b/quinn/src/runtime.rs index 64734d2ea..785e9dc93 100644 --- a/quinn/src/runtime.rs +++ b/quinn/src/runtime.rs @@ -239,12 +239,10 @@ pub fn default_runtime() -> Option> { #[cfg(feature = "runtime-tokio")] mod tokio; -// Due to MSRV, we must specify `self::` where there's crate/module ambiguity #[cfg(feature = "runtime-tokio")] -pub use self::tokio::TokioRuntime; +pub use tokio::TokioRuntime; #[cfg(feature = "async-io")] mod async_io; -// Due to MSRV, we must specify `self::` where there's crate/module ambiguity #[cfg(feature = "runtime-smol")] -pub use self::async_io::*; +pub use async_io::*; diff --git a/quinn/src/runtime/async_io.rs b/quinn/src/runtime/async_io.rs index 7f995144b..33bf283e3 100644 --- a/quinn/src/runtime/async_io.rs +++ b/quinn/src/runtime/async_io.rs @@ -16,8 +16,7 @@ use super::AsyncTimer; use super::{AsyncUdpSocket, Runtime, UdpSender, UdpSenderHelper, UdpSenderHelperSocket}; #[cfg(feature = "runtime-smol")] -// Due to MSRV, we must specify `self::` where there's crate/module ambiguity -pub use self::smol::SmolRuntime; +pub use smol::SmolRuntime; #[cfg(feature = "runtime-smol")] mod smol { From ac22065c2943e5578d191179d908ffcb0afa1b6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:02:43 +0000 Subject: [PATCH 56/71] build(deps): bump bytes from 1.10.1 to 1.11.0 Bumps [bytes](https://github.com/tokio-rs/bytes) from 1.10.1 to 1.11.0. - [Release notes](https://github.com/tokio-rs/bytes/releases) - [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/bytes/compare/v1.10.1...v1.11.0) --- updated-dependencies: - dependency-name: bytes dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6fcbbb83..cf81e2789 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,9 +415,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cast" From 42bc17f812bf8797de9188f54f0070674e85f7ee Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 11 Nov 2025 16:31:54 +0100 Subject: [PATCH 57/71] quinn: move runtime module to be closer to its child modules --- quinn/src/{runtime.rs => runtime/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename quinn/src/{runtime.rs => runtime/mod.rs} (100%) diff --git a/quinn/src/runtime.rs b/quinn/src/runtime/mod.rs similarity index 100% rename from quinn/src/runtime.rs rename to quinn/src/runtime/mod.rs From 4c17321999561b33d7ba4f9bce75a0d368eb0435 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 11 Nov 2025 16:33:30 +0100 Subject: [PATCH 58/71] quinn: rename async_io module to smol --- quinn/src/runtime/mod.rs | 4 ++-- quinn/src/runtime/{async_io.rs => smol.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename quinn/src/runtime/{async_io.rs => smol.rs} (100%) diff --git a/quinn/src/runtime/mod.rs b/quinn/src/runtime/mod.rs index 785e9dc93..057c60e5d 100644 --- a/quinn/src/runtime/mod.rs +++ b/quinn/src/runtime/mod.rs @@ -243,6 +243,6 @@ mod tokio; pub use tokio::TokioRuntime; #[cfg(feature = "async-io")] -mod async_io; +mod smol; #[cfg(feature = "runtime-smol")] -pub use async_io::*; +pub use smol::*; diff --git a/quinn/src/runtime/async_io.rs b/quinn/src/runtime/smol.rs similarity index 100% rename from quinn/src/runtime/async_io.rs rename to quinn/src/runtime/smol.rs From 1ffd9cd83fef6970c34d26320bfd790f8b34b062 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 11 Nov 2025 16:35:13 +0100 Subject: [PATCH 59/71] quinn: simplify cfg guards for runtime-smol --- quinn/Cargo.toml | 2 +- quinn/src/runtime/mod.rs | 2 +- quinn/src/runtime/smol.rs | 42 +++++++++++---------------------------- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 81869bcfc..503efe4f5 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -36,7 +36,7 @@ rustls-ring = ["dep:rustls", "ring", "proto/rustls-ring", "proto/ring"] # Outside wasm*-unknown-unknown targets, this enables `Endpoint::client` and `Endpoint::server` conveniences. ring = ["proto/ring"] runtime-tokio = ["tokio/time", "tokio/rt", "tokio/net"] -runtime-smol = ["async-io", "smol"] +runtime-smol = ["dep:async-io", "smol"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. tracing-log = ["tracing/log", "proto/tracing-log", "udp/tracing-log"] diff --git a/quinn/src/runtime/mod.rs b/quinn/src/runtime/mod.rs index 057c60e5d..907b1992b 100644 --- a/quinn/src/runtime/mod.rs +++ b/quinn/src/runtime/mod.rs @@ -242,7 +242,7 @@ mod tokio; #[cfg(feature = "runtime-tokio")] pub use tokio::TokioRuntime; -#[cfg(feature = "async-io")] +#[cfg(feature = "runtime-smol")] mod smol; #[cfg(feature = "runtime-smol")] pub use smol::*; diff --git a/quinn/src/runtime/smol.rs b/quinn/src/runtime/smol.rs index 33bf283e3..f9bff2194 100644 --- a/quinn/src/runtime/smol.rs +++ b/quinn/src/runtime/smol.rs @@ -4,43 +4,29 @@ use std::{ task::{Context, Poll}, time::Instant, }; -#[cfg(feature = "runtime-smol")] use std::{io, sync::Arc, task::ready}; -#[cfg(feature = "runtime-smol")] use async_io::Async; use async_io::Timer; use super::AsyncTimer; -#[cfg(feature = "runtime-smol")] use super::{AsyncUdpSocket, Runtime, UdpSender, UdpSenderHelper, UdpSenderHelperSocket}; -#[cfg(feature = "runtime-smol")] -pub use smol::SmolRuntime; +/// A Quinn runtime for smol +#[derive(Debug)] +pub struct SmolRuntime; -#[cfg(feature = "runtime-smol")] -mod smol { - use super::*; +impl Runtime for SmolRuntime { + fn new_timer(&self, t: Instant) -> Pin> { + Box::pin(Timer::at(t)) + } - /// A Quinn runtime for smol - #[derive(Debug)] - pub struct SmolRuntime; + fn spawn(&self, future: Pin + Send>>) { + ::smol::spawn(future).detach(); + } - impl Runtime for SmolRuntime { - fn new_timer(&self, t: Instant) -> Pin> { - Box::pin(Timer::at(t)) - } - - fn spawn(&self, future: Pin + Send>>) { - ::smol::spawn(future).detach(); - } - - fn wrap_udp_socket( - &self, - sock: std::net::UdpSocket, - ) -> io::Result> { - Ok(Box::new(UdpSocket::new(sock)?)) - } + fn wrap_udp_socket(&self, sock: std::net::UdpSocket) -> io::Result> { + Ok(Box::new(UdpSocket::new(sock)?)) } } @@ -54,14 +40,12 @@ impl AsyncTimer for Timer { } } -#[cfg(feature = "runtime-smol")] #[derive(Debug, Clone)] struct UdpSocket { io: Arc>, inner: Arc, } -#[cfg(feature = "runtime-smol")] impl UdpSocket { fn new(sock: std::net::UdpSocket) -> io::Result { Ok(Self { @@ -71,7 +55,6 @@ impl UdpSocket { } } -#[cfg(feature = "runtime-smol")] impl UdpSenderHelperSocket for UdpSocket { fn max_transmit_segments(&self) -> usize { self.inner.max_gso_segments() @@ -82,7 +65,6 @@ impl UdpSenderHelperSocket for UdpSocket { } } -#[cfg(feature = "runtime-smol")] impl AsyncUdpSocket for UdpSocket { fn create_sender(&self) -> Pin> { Box::pin(UdpSenderHelper::new(self.clone(), |socket: &Self| { From 9596c7a2611c6060d24af8c98bf0e2f0fe31a959 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 11 Nov 2025 16:35:38 +0100 Subject: [PATCH 60/71] quinn: hide implicit feature for optional smol dependency --- quinn/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quinn/Cargo.toml b/quinn/Cargo.toml index 503efe4f5..42a3d4917 100644 --- a/quinn/Cargo.toml +++ b/quinn/Cargo.toml @@ -36,7 +36,7 @@ rustls-ring = ["dep:rustls", "ring", "proto/rustls-ring", "proto/ring"] # Outside wasm*-unknown-unknown targets, this enables `Endpoint::client` and `Endpoint::server` conveniences. ring = ["proto/ring"] runtime-tokio = ["tokio/time", "tokio/rt", "tokio/net"] -runtime-smol = ["dep:async-io", "smol"] +runtime-smol = ["dep:async-io", "dep:smol"] # Configure `tracing` to log events via `log` if no `tracing` subscriber exists. tracing-log = ["tracing/log", "proto/tracing-log", "udp/tracing-log"] From d2cdd65ca44208f4820ff612f72578b8461efe7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:17:15 +0000 Subject: [PATCH 61/71] build(deps): bump actions/checkout from 5 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/book.yml | 2 +- .github/workflows/codecov.yml | 2 +- .github/workflows/rust.yml | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml index b5feee379..b2961dec5 100644 --- a/.github/workflows/book.yml +++ b/.github/workflows/book.yml @@ -9,7 +9,7 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Setup mdBook uses: peaceiris/actions-mdbook@v2 with: diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 210355eb4..6ff4e30ed 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -11,7 +11,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: taiki-e/install-action@cargo-llvm-cov - shell: bash diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e5a8f7da6..80f8a6141 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -15,7 +15,7 @@ jobs: name: test on freebsd runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: test on freebsd uses: vmactions/freebsd-vm@v1 with: @@ -39,7 +39,7 @@ jobs: name: test on solaris runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: test on Solaris uses: vmactions/solaris-vm@v1 with: @@ -64,7 +64,7 @@ jobs: name: test on illumos runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: test on Illumos uses: vmactions/omnios-vm@v1 with: @@ -92,7 +92,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} @@ -111,7 +111,7 @@ jobs: test-aws-lc-rs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 # Prevent feature unification from selecting *ring* as the crypto provider @@ -127,7 +127,7 @@ jobs: name: test wasm32-unknown-unknown runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - run: rustup target add wasm32-unknown-unknown - uses: actions/setup-node@v6 @@ -156,7 +156,7 @@ jobs: msrv: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 # Note that we must also update the README when changing the MSRV - uses: dtolnay/rust-toolchain@1.80.0 - uses: Swatinem/rust-cache@v2 @@ -165,7 +165,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy @@ -188,7 +188,7 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: EmbarkStudios/cargo-deny-action@v2 test-android: @@ -210,7 +210,7 @@ jobs: run: echo "API_LEVEL=${{ matrix.api-level }}" >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install JDK uses: actions/setup-java@v5 @@ -263,7 +263,7 @@ jobs: # skip FIPS features outside of Linux SKIP_FEATURES: ${{ matrix.os != 'ubuntu-latest' && 'rustls-aws-lc-rs-fips,aws-lc-rs-fips,__rustls-post-quantum-test' || '' }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: taiki-e/install-action@cargo-hack - run: cargo hack check --feature-powerset --depth 3 --optional-deps --no-dev-deps --ignore-private --skip "${{env.SKIP_FEATURES}}" From f90254a4107d3cb600b83ca2e536ecba5023d051 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 24 Nov 2025 10:11:41 +0100 Subject: [PATCH 62/71] quinn: statically hide default_runtime() if unavailable --- quinn/src/endpoint.rs | 24 ++++++++++++++++++++---- quinn/src/lib.rs | 4 +++- quinn/src/runtime/mod.rs | 4 +++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/quinn/src/endpoint.rs b/quinn/src/endpoint.rs index 761a2fc5f..442608cc5 100644 --- a/quinn/src/endpoint.rs +++ b/quinn/src/endpoint.rs @@ -11,7 +11,11 @@ use std::{ task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, }; -#[cfg(all(not(wasm_browser), any(feature = "aws-lc-rs", feature = "ring")))] +#[cfg(all( + not(wasm_browser), + any(feature = "runtime-tokio", feature = "runtime-smol"), + any(feature = "aws-lc-rs", feature = "ring"), +))] use crate::runtime::default_runtime; use crate::{ Instant, @@ -25,7 +29,11 @@ use proto::{ EndpointEvent, ServerConfig, }; use rustc_hash::FxHashMap; -#[cfg(all(not(wasm_browser), any(feature = "aws-lc-rs", feature = "ring"),))] +#[cfg(all( + not(wasm_browser), + any(feature = "runtime-tokio", feature = "runtime-smol"), + any(feature = "aws-lc-rs", feature = "ring"), +))] use socket2::{Domain, Protocol, Socket, Type}; use tokio::sync::{Notify, futures::Notified, mpsc}; use tracing::{Instrument, Span}; @@ -67,7 +75,11 @@ impl Endpoint { /// /// Some environments may not allow creation of dual-stack sockets, in which case an IPv6 /// client will only be able to connect to IPv6 servers. An IPv4 client is never dual-stack. - #[cfg(all(not(wasm_browser), any(feature = "aws-lc-rs", feature = "ring")))] // `EndpointConfig::default()` is only available with these + #[cfg(all( + not(wasm_browser), + any(feature = "runtime-tokio", feature = "runtime-smol"), + any(feature = "aws-lc-rs", feature = "ring"), // `EndpointConfig::default()` is only available with these + ))] pub fn client(addr: SocketAddr) -> io::Result { let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))?; if addr.is_ipv6() { @@ -97,7 +109,11 @@ impl Endpoint { /// IPv6 address on Windows will not by default be able to communicate with IPv4 /// addresses. Portable applications should bind an address that matches the family they wish to /// communicate within. - #[cfg(all(not(wasm_browser), any(feature = "aws-lc-rs", feature = "ring")))] // `EndpointConfig::default()` is only available with these + #[cfg(all( + not(wasm_browser), + any(feature = "runtime-tokio", feature = "runtime-smol"), + any(feature = "aws-lc-rs", feature = "ring"), // `EndpointConfig::default()` is only available with these + ))] pub fn server(config: ServerConfig, addr: SocketAddr) -> io::Result { let socket = std::net::UdpSocket::bind(addr)?; let runtime = diff --git a/quinn/src/lib.rs b/quinn/src/lib.rs index 64f4800bb..61b7eb64a 100644 --- a/quinn/src/lib.rs +++ b/quinn/src/lib.rs @@ -85,7 +85,9 @@ pub use crate::recv_stream::{ReadError, ReadExactError, ReadToEndError, RecvStre pub use crate::runtime::SmolRuntime; #[cfg(feature = "runtime-tokio")] pub use crate::runtime::TokioRuntime; -pub use crate::runtime::{AsyncTimer, AsyncUdpSocket, Runtime, UdpSender, default_runtime}; +#[cfg(any(feature = "runtime-tokio", feature = "runtime-smol"))] +pub use crate::runtime::default_runtime; +pub use crate::runtime::{AsyncTimer, AsyncUdpSocket, Runtime, UdpSender}; pub use crate::send_stream::{SendStream, StoppedError, WriteError}; #[cfg(test)] diff --git a/quinn/src/runtime/mod.rs b/quinn/src/runtime/mod.rs index 907b1992b..15a7a1112 100644 --- a/quinn/src/runtime/mod.rs +++ b/quinn/src/runtime/mod.rs @@ -1,10 +1,11 @@ +#[cfg(any(feature = "runtime-tokio", feature = "runtime-smol"))] +use std::sync::Arc; use std::{ fmt::{self, Debug}, future::Future, io::{self, IoSliceMut}, net::SocketAddr, pin::Pin, - sync::Arc, task::{Context, Poll}, }; @@ -219,6 +220,7 @@ trait UdpSenderHelperSocket: Send + Sync + 'static { /// If `runtime-tokio` is enabled and this function is called from within a Tokio runtime context, /// then `TokioRuntime` is returned. Otherwise, if `runtime-smol` is enabled, `SmolRuntime` is /// returned. Otherwise, `None` is returned. +#[cfg(any(feature = "runtime-tokio", feature = "runtime-smol"))] #[allow(clippy::needless_return)] // Be sure we return the right thing pub fn default_runtime() -> Option> { #[cfg(feature = "runtime-tokio")] From 5334839f9594625015126eeaea0679c9c1393f46 Mon Sep 17 00:00:00 2001 From: Marcus Medom Ryding Date: Sat, 8 Nov 2025 15:04:46 +0100 Subject: [PATCH 63/71] Track handshake confirmation --- quinn-proto/src/connection/mod.rs | 6 ++ quinn-proto/src/tests/mod.rs | 113 ++++++++++++++++++++++++++++++ quinn-proto/src/tests/util.rs | 8 +++ quinn/src/connection.rs | 40 +++++++++++ 4 files changed, 167 insertions(+) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index b4a953597..877220f7e 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -2638,6 +2638,8 @@ impl Connection { // Server-only self.spaces[SpaceId::Data].pending.handshake_done = true; self.discard_space(now, SpaceId::Handshake); + self.events.push_back(Event::HandshakeConfirmed); + trace!("handshake confirmed"); } self.events.push_back(Event::Connected); @@ -3057,6 +3059,8 @@ impl Connection { if self.spaces[SpaceId::Handshake].crypto.is_some() { self.discard_space(now, SpaceId::Handshake); } + self.events.push_back(Event::HandshakeConfirmed); + trace!("handshake confirmed"); } } } @@ -4042,6 +4046,8 @@ pub enum Event { HandshakeDataReady, /// The connection was successfully established Connected, + /// The TLS handshake was confirmed + HandshakeConfirmed, /// The connection was lost /// /// Emitted if the peer closes the connection or an error is encountered. diff --git a/quinn-proto/src/tests/mod.rs b/quinn-proto/src/tests/mod.rs index d4645e35c..6bacefc43 100644 --- a/quinn-proto/src/tests/mod.rs +++ b/quinn-proto/src/tests/mod.rs @@ -579,6 +579,10 @@ fn zero_rtt_happypath() { pair.server_conn_mut(server_ch).poll(), Some(Event::HandshakeDataReady) ); + assert_matches!( + pair.server_conn_mut(server_ch).poll(), + Some(Event::HandshakeConfirmed) + ); // We don't currently preserve stream event order wrt. connection events assert_matches!( pair.server_conn_mut(server_ch).poll(), @@ -618,6 +622,10 @@ fn zero_rtt_rejection() { pair.server_conn_mut(server_ch).poll(), Some(Event::HandshakeDataReady) ); + assert_matches!( + pair.server_conn_mut(server_ch).poll(), + Some(Event::HandshakeConfirmed) + ); assert_matches!( pair.server_conn_mut(server_ch).poll(), Some(Event::Connected) @@ -659,6 +667,10 @@ fn zero_rtt_rejection() { pair.server_conn_mut(server_ch).poll(), Some(Event::HandshakeDataReady) ); + assert_matches!( + pair.server_conn_mut(server_ch).poll(), + Some(Event::HandshakeConfirmed) + ); assert_matches!( pair.server_conn_mut(server_ch).poll(), Some(Event::Connected) @@ -742,6 +754,10 @@ fn test_zero_rtt_incoming_limit(configure_server: pair.server_conn_mut(server_ch).poll(), Some(Event::HandshakeDataReady) ); + assert_matches!( + pair.server_conn_mut(server_ch).poll(), + Some(Event::HandshakeConfirmed) + ); // We don't currently preserve stream event order wrt. connection events assert_matches!( pair.server_conn_mut(server_ch).poll(), @@ -812,6 +828,10 @@ fn alpn_success() { pair.server_conn_mut(server_ch).poll(), Some(Event::HandshakeDataReady) ); + assert_matches!( + pair.server_conn_mut(server_ch).poll(), + Some(Event::HandshakeConfirmed) + ); assert_matches!( pair.server_conn_mut(server_ch).poll(), Some(Event::Connected) @@ -1997,6 +2017,10 @@ fn large_initial() { pair.server_conn_mut(server_ch).poll(), Some(Event::HandshakeDataReady) ); + assert_matches!( + pair.server_conn_mut(server_ch).poll(), + Some(Event::HandshakeConfirmed) + ); assert_matches!( pair.server_conn_mut(server_ch).poll(), Some(Event::Connected) @@ -3387,3 +3411,92 @@ fn preferred_address() { let mut pair = Pair::new(Arc::new(EndpointConfig::default()), server_config); pair.connect(); } + +#[test] +fn handshake_sequence() { + let _guard = subscribe(); + + let mut pair = Pair::default(); + let ch = pair.begin_connect(client_config()); + + pair.step(); + assert_matches!(pair.client_conn_mut(ch).poll(), None); + let sh = pair.server.assert_accept(); + assert_matches!( + pair.server_conn_mut(sh).poll(), + Some(Event::HandshakeDataReady) + ); + assert_matches!(pair.server_conn_mut(sh).poll(), None); + + pair.step(); + assert_matches!( + pair.client_conn_mut(ch).poll(), + Some(Event::HandshakeDataReady) + ); + assert_matches!(pair.client_conn_mut(ch).poll(), Some(Event::Connected)); + assert_matches!(pair.client_conn_mut(ch).poll(), None); + assert_matches!( + pair.server_conn_mut(sh).poll(), + Some(Event::HandshakeConfirmed) + ); + assert_matches!(pair.server_conn_mut(sh).poll(), Some(Event::Connected)); + assert_matches!(pair.server_conn_mut(sh).poll(), None); + + pair.drive_client(); + assert_matches!( + pair.client_conn_mut(ch).poll(), + Some(Event::HandshakeConfirmed) + ); + assert_matches!(pair.client_conn_mut(ch).poll(), None); +} + +#[test] +fn handshake_confirmation_no_resumption_shortcut() { + let _guard = subscribe(); + + // Initial connection + let mut pair = Pair::default(); + let config = client_config(); + let (ch, _) = pair.connect_with(config.clone()); + pair.client + .connections + .get_mut(&ch) + .unwrap() + .close(pair.time, VarInt(0), [][..].into()); + pair.drive(); + + // Resumed connection + info!("resuming session"); + let ch = pair.begin_connect(config); + assert!(pair.client_conn_mut(ch).has_0rtt()); + + pair.step(); + assert_matches!(pair.client_conn_mut(ch).poll(), None); + let sh = pair.server.assert_accept(); + assert_matches!( + pair.server_conn_mut(sh).poll(), + Some(Event::HandshakeDataReady) + ); + assert_matches!(pair.server_conn_mut(sh).poll(), None); + + pair.step(); + assert_matches!( + pair.client_conn_mut(ch).poll(), + Some(Event::HandshakeDataReady) + ); + assert_matches!(pair.client_conn_mut(ch).poll(), Some(Event::Connected)); + assert_matches!(pair.client_conn_mut(ch).poll(), None); + assert_matches!( + pair.server_conn_mut(sh).poll(), + Some(Event::HandshakeConfirmed) + ); + assert_matches!(pair.server_conn_mut(sh).poll(), Some(Event::Connected)); + assert_matches!(pair.server_conn_mut(sh).poll(), None); + + pair.drive_client(); + assert_matches!( + pair.client_conn_mut(ch).poll(), + Some(Event::HandshakeConfirmed) + ); + assert_matches!(pair.client_conn_mut(ch).poll(), None); +} diff --git a/quinn-proto/src/tests/util.rs b/quinn-proto/src/tests/util.rs index 445e2a9f1..1befd044a 100644 --- a/quinn-proto/src/tests/util.rs +++ b/quinn-proto/src/tests/util.rs @@ -230,10 +230,18 @@ impl Pair { self.server_conn_mut(server_ch).poll(), Some(Event::HandshakeDataReady) ); + assert_matches!( + self.server_conn_mut(server_ch).poll(), + Some(Event::HandshakeConfirmed) + ); assert_matches!( self.server_conn_mut(server_ch).poll(), Some(Event::Connected) ); + assert_matches!( + self.client_conn_mut(client_ch).poll(), + Some(Event::HandshakeConfirmed) + ); } pub(super) fn client_conn_mut(&mut self, ch: ConnectionHandle) -> &mut Connection { diff --git a/quinn/src/connection.rs b/quinn/src/connection.rs index ab3777d71..7ca330835 100644 --- a/quinn/src/connection.rs +++ b/quinn/src/connection.rs @@ -422,6 +422,38 @@ impl Connection { conn.close(error_code, Bytes::copy_from_slice(reason), &self.0.shared); } + /// Wait for the handshake to be confirmed. + /// + /// As a server, who must be authenticated by clients, + /// this happens when the handshake completes + /// upon receiving a TLS Finished message from the client. + /// In return, the server send a HANDSHAKE_DONE frame. + /// + /// As a client, this happens when receiving a HANDSHAKE_DONE frame. + /// At this point, the server has either accepted our authentication, + /// or, if client authentication is not required, accepted our lack of authentication. + pub async fn handshake_confirmed(&self) -> Result<(), ConnectionError> { + { + let conn = self.0.state.lock("handshake_confirmed"); + if let Some(error) = conn.error.as_ref() { + return Err(error.clone()); + } + if conn.handshake_confirmed { + return Ok(()); + } + // Construct the future while the lock is held to ensure we can't miss a wakeup if + // the `Notify` is signaled immediately after we release the lock. `await` it after + // the lock guard is out of scope. + self.0.shared.handshake_confirmed.notified() + } + .await; + if let Some(error) = self.0.state.lock("handshake_confirmed").error.as_ref() { + Err(error.clone()) + } else { + Ok(()) + } + } + /// Transmit `data` as an unreliable, unordered application datagram /// /// Application datagrams are a low-level primitive. They may be lost or delivered out of order, @@ -893,6 +925,7 @@ impl ConnectionRef { on_handshake_data: Some(on_handshake_data), on_connected: Some(on_connected), connected: false, + handshake_confirmed: false, timer: None, timer_deadline: None, conn_events, @@ -954,6 +987,7 @@ pub(crate) struct ConnectionInner { #[derive(Debug, Default)] pub(crate) struct Shared { + handshake_confirmed: Notify, /// Notified when new streams may be locally initiated due to an increase in stream ID flow /// control budget stream_budget_available: [Notify; 2], @@ -971,6 +1005,7 @@ pub(crate) struct State { on_handshake_data: Option>, on_connected: Option>, connected: bool, + handshake_confirmed: bool, timer: Option>>, timer_deadline: Option, conn_events: mpsc::UnboundedReceiver, @@ -1110,6 +1145,10 @@ impl State { wake_all_notify(&mut self.stopped); } } + HandshakeConfirmed => { + self.handshake_confirmed = true; + shared.handshake_confirmed.notify_waiters(); + } ConnectionLost { reason } => { self.terminate(reason, shared); } @@ -1214,6 +1253,7 @@ impl State { if let Some(x) = self.on_connected.take() { let _ = x.send(false); } + shared.handshake_confirmed.notify_waiters(); wake_all_notify(&mut self.stopped); shared.closed.notify_waiters(); } From 67ededbc9e93251fee61a1e318d38a94785c70a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Szczygie=C5=82?= Date: Fri, 21 Nov 2025 10:48:10 +0200 Subject: [PATCH 64/71] Add an option to retrieve TLS errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mateusz Szczygieł --- quinn-proto/src/connection/mod.rs | 2 ++ quinn-proto/src/crypto/rustls.rs | 1 + quinn-proto/src/transport_error.rs | 33 ++++++++++++++++++++++++++++-- quinn/src/connection.rs | 9 ++++---- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 877220f7e..1060a894c 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -2605,6 +2605,7 @@ impl Connection { code: TransportErrorCode::crypto(0x6d), frame: None, reason: "transport parameters missing".into(), + crypto: None, })?; if self.has_0rtt() { @@ -2680,6 +2681,7 @@ impl Connection { code: TransportErrorCode::crypto(0x6d), frame: None, reason: "transport parameters missing".into(), + crypto: None, })?; self.handle_peer_params(params)?; self.issue_first_cids(now); diff --git a/quinn-proto/src/crypto/rustls.rs b/quinn-proto/src/crypto/rustls.rs index c31fddf87..48891fd88 100644 --- a/quinn-proto/src/crypto/rustls.rs +++ b/quinn-proto/src/crypto/rustls.rs @@ -110,6 +110,7 @@ impl crypto::Session for TlsSession { code: TransportErrorCode::crypto(alert.into()), frame: None, reason: e.to_string(), + crypto: Some(Arc::new(e)), } } else { TransportError::PROTOCOL_VIOLATION(format!("TLS error: {e}")) diff --git a/quinn-proto/src/transport_error.rs b/quinn-proto/src/transport_error.rs index 047cd0acc..b29a854b9 100644 --- a/quinn-proto/src/transport_error.rs +++ b/quinn-proto/src/transport_error.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{fmt, sync::Arc}; use bytes::{Buf, BufMut}; @@ -8,7 +8,12 @@ use crate::{ }; /// Transport-level errors occur when a peer violates the protocol specification -#[derive(Debug, Clone, Eq, PartialEq)] +/// +/// # Note +/// +/// The `PartialEq` implementation for this type performs comparison on the `code` field only +#[derive(Debug, Clone)] +#[non_exhaustive] pub struct Error { /// Type of error pub code: Code, @@ -16,8 +21,30 @@ pub struct Error { pub frame: Option, /// Human-readable explanation of the reason pub reason: String, + /// An underlying crypto (e.g. TLS) layer error + pub crypto: Option>, } +impl Error { + /// Construct an error with a code and a reason + pub fn new(code: Code, reason: String) -> Self { + Self { + code, + frame: None, + reason, + crypto: None, + } + } +} + +impl PartialEq for Error { + fn eq(&self, other: &Self) -> bool { + self.code == other.code + } +} + +impl Eq for Error {} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.code.fmt(f)?; @@ -39,6 +66,7 @@ impl From for Error { code: x, frame: None, reason: "".to_string(), + crypto: None, } } } @@ -79,6 +107,7 @@ macro_rules! errors { code: Code::$name, frame: None, reason: reason.into(), + crypto: None, } } )* diff --git a/quinn/src/connection.rs b/quinn/src/connection.rs index 7ca330835..b9f317746 100644 --- a/quinn/src/connection.rs +++ b/quinn/src/connection.rs @@ -1109,11 +1109,10 @@ impl State { self.close(error_code, reason, shared); } Poll::Ready(None) => { - return Err(ConnectionError::TransportError(proto::TransportError { - code: proto::TransportErrorCode::INTERNAL_ERROR, - frame: None, - reason: "endpoint driver future was dropped".to_string(), - })); + return Err(ConnectionError::TransportError(proto::TransportError::new( + proto::TransportErrorCode::INTERNAL_ERROR, + "endpoint driver future was dropped".to_string(), + ))); } Poll::Pending => { return Ok(()); From 8bf6825da7876dc233434baaea546d3addc4b0ed Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Sat, 29 Nov 2025 08:02:21 +0100 Subject: [PATCH 65/71] Fix quinn-udp on DragonFly BSD - There is no libc::IP_RECVTOST defined for DragonFly. We do support it in the kernel, but it's not yet defined in libc. - There is no recvmmsg(2) support in DragonFly kernel. --- quinn-udp/src/unix.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/quinn-udp/src/unix.rs b/quinn-udp/src/unix.rs index f551d2229..376b4afa2 100644 --- a/quinn-udp/src/unix.rs +++ b/quinn-udp/src/unix.rs @@ -113,7 +113,12 @@ impl UdpSocketState { // mac and ios do not support IP_RECVTOS on dual-stack sockets :( // older macos versions also don't have the flag and will error out if we don't ignore it - #[cfg(not(any(target_os = "openbsd", target_os = "netbsd", solarish)))] + #[cfg(not(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + solarish + )))] if is_ipv4 || !io.only_v6()? { if let Err(_err) = set_socket_option(&*io, libc::IPPROTO_IP, libc::IP_RECVTOS, OPTION_ON) @@ -461,7 +466,13 @@ fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io: } } -#[cfg(not(any(apple, target_os = "openbsd", target_os = "netbsd", solarish)))] +#[cfg(not(any( + apple, + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + solarish +)))] fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) -> io::Result { let mut names = [MaybeUninit::::uninit(); BATCH_SIZE]; let mut ctrls = [cmsg::Aligned(MaybeUninit::<[u8; CMSG_LEN]>::uninit()); BATCH_SIZE]; @@ -538,7 +549,13 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) -> Ok(msg_count as usize) } -#[cfg(any(target_os = "openbsd", target_os = "netbsd", solarish, apple_slow))] +#[cfg(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + solarish, + apple_slow +))] fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) -> io::Result { let mut name = MaybeUninit::::uninit(); let mut ctrl = cmsg::Aligned(MaybeUninit::<[u8; CMSG_LEN]>::uninit()); @@ -715,7 +732,12 @@ fn decode_recv( ecn_bits = cmsg::decode::(cmsg); }, // FreeBSD uses IP_RECVTOS here, and we can be liberal because cmsgs are opt-in. - #[cfg(not(any(target_os = "openbsd", target_os = "netbsd", solarish)))] + #[cfg(not(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + solarish + )))] (libc::IPPROTO_IP, libc::IP_RECVTOS) => unsafe { ecn_bits = cmsg::decode::(cmsg); }, From 6380cb33093cdcf6a20f23848196be01b49d6128 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 1 Dec 2025 14:18:06 +0100 Subject: [PATCH 66/71] ci: fixup package names --- .github/workflows/rust.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3d5f53755..8aa98d51b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -55,7 +55,7 @@ jobs: export PATH=$HOME/.rust_solaris/bin:$PATH # Workaround for https://github.com/quinn-rs/quinn/issues/2218 export CARGO_HTTP_MULTIPLEXING=false - cargo build --locked --all-targets && cargo test --locked --manifest-path fuzz/Cargo.toml && cargo test --locked -p quinn-udp --benches + cargo build --locked --all-targets && cargo test --locked --manifest-path fuzz/Cargo.toml && cargo test --locked -p iroh-quinn-udp --benches test-illumos: name: test on illumos @@ -73,7 +73,7 @@ jobs: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal run: | . "$HOME/.cargo/env" - cargo build --locked --all-targets && cargo test --locked && cargo test --locked -- --ignored stress && cargo test --locked --manifest-path fuzz/Cargo.toml && cargo test --locked -p quinn-udp --benches + cargo build --locked --all-targets && cargo test --locked && cargo test --locked -- --ignored stress && cargo test --locked --manifest-path fuzz/Cargo.toml && cargo test --locked -p iroh-quinn-udp --benches test: strategy: @@ -154,7 +154,7 @@ jobs: # Match the version of wasm-bindgen used in `Cargo.lock` - run: cargo binstall wasm-bindgen-cli@0.2.105 --locked --no-confirm - - run: cargo test --locked -p quinn-proto --target wasm32-unknown-unknown + - run: cargo test --locked -p iroh-quinn-proto --target wasm32-unknown-unknown msrv: runs-on: ubuntu-latest From 39c190f526ff5f5ce6ce4e4f0cc99b0b0a82280d Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 1 Dec 2025 14:27:29 +0100 Subject: [PATCH 67/71] test: assume low latency to avoid pacing issues --- quinn-proto/src/tests/mod.rs | 10 ++++++++++ quinn-proto/src/tests/multipath.rs | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/quinn-proto/src/tests/mod.rs b/quinn-proto/src/tests/mod.rs index 062ef29ff..983e95748 100644 --- a/quinn-proto/src/tests/mod.rs +++ b/quinn-proto/src/tests/mod.rs @@ -3734,6 +3734,8 @@ fn address_discovery_retransmission() { let server = ServerConfig { transport: Arc::new(TransportConfig { address_discovery_role: crate::address_discovery::Role::Both, + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }), ..server_config() @@ -3742,6 +3744,8 @@ fn address_discovery_retransmission() { let client_config = ClientConfig { transport: Arc::new(TransportConfig { address_discovery_role: crate::address_discovery::Role::Both, + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }), ..client_config() @@ -3759,6 +3763,7 @@ fn address_discovery_retransmission() { pair.drive(); let conn = pair.client_conn_mut(client_ch); + assert_matches!(conn.poll(), Some(Event::HandshakeConfirmed)); assert_matches!(conn.poll(), Some(Event::Path(PathEvent::ObservedAddr{id: PathId::ZERO, addr})) if addr == pair.client.addr); } @@ -3769,6 +3774,8 @@ fn address_discovery_rebind_retransmission() { let server = ServerConfig { transport: Arc::new(TransportConfig { address_discovery_role: crate::address_discovery::Role::Both, + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }), ..server_config() @@ -3777,6 +3784,8 @@ fn address_discovery_rebind_retransmission() { let client_config = ClientConfig { transport: Arc::new(TransportConfig { address_discovery_role: crate::address_discovery::Role::Both, + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }), ..client_config() @@ -3801,6 +3810,7 @@ fn address_discovery_rebind_retransmission() { pair.drive(); let conn = pair.client_conn_mut(client_ch); + assert_matches!(conn.poll(), Some(Event::HandshakeConfirmed)); assert_matches!(conn.poll(), Some(Event::Path(PathEvent::ObservedAddr{id: PathId::ZERO, addr})) if addr == pair.client.addr); } diff --git a/quinn-proto/src/tests/multipath.rs b/quinn-proto/src/tests/multipath.rs index b7bb2b1d2..4cd4f4170 100644 --- a/quinn-proto/src/tests/multipath.rs +++ b/quinn-proto/src/tests/multipath.rs @@ -25,6 +25,8 @@ const MAX_PATHS: u32 = 3; fn multipath_pair() -> (Pair, ConnectionHandle, ConnectionHandle) { let multipath_transport_cfg = Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(MAX_PATHS), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }); let server_cfg = Arc::new(ServerConfig { @@ -50,6 +52,8 @@ fn non_zero_length_cids() { let _guard = subscribe(); let multipath_transport_cfg = Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(3 as _), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }); let server_cfg = Arc::new(ServerConfig { @@ -197,6 +201,8 @@ fn multipath_cid_rotation() { let server_cfg = ServerConfig { transport: Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(MAX_PATHS), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }), ..server_config() @@ -217,6 +223,8 @@ fn multipath_cid_rotation() { let client_cfg = ClientConfig { transport: Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(MAX_PATHS), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }), ..client_config() @@ -306,6 +314,8 @@ fn issue_max_path_id() { // We enable multipath but initially do not allow any paths to be opened. let multipath_transport_cfg = Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(1), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }); let server_cfg = Arc::new(ServerConfig { @@ -320,6 +330,8 @@ fn issue_max_path_id() { // The client is allowed to create more paths immediately. let client_multipath_transport_cfg = Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(MAX_PATHS), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }); let client_cfg = ClientConfig { @@ -374,6 +386,8 @@ fn issue_max_path_id_reordered() { // We enable multipath but initially do not allow any paths to be opened. let multipath_transport_cfg = Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(1), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }); let server_cfg = Arc::new(ServerConfig { @@ -388,6 +402,8 @@ fn issue_max_path_id_reordered() { // The client is allowed to create more paths immediately. let client_multipath_transport_cfg = Arc::new(TransportConfig { max_concurrent_multipath_paths: NonZeroU32::new(MAX_PATHS), + // Assume a low-latency connection so pacing doesn't interfere with the test + initial_rtt: Duration::from_millis(10), ..TransportConfig::default() }); let client_cfg = ClientConfig { From e8b9fb3f3442ccdb32e0b4dd4adfe4de761785d6 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 1 Dec 2025 14:34:31 +0100 Subject: [PATCH 68/71] docs: fixup readme --- README.md | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/README.md b/README.md index 404721a00..82e9038ed 100644 --- a/README.md +++ b/README.md @@ -50,15 +50,7 @@ branch. E.g. when upstream is `main` and the current iroh branch is - You can check the log and cherries again to see if the right commits are left in main. -<<<<<<< HEAD ### Upstream versions -======= -For some cases, including peer-to-peer, trust-on-first-use, deliberately -insecure applications, or any case where servers are not identified by domain -name, this isn't practical. Arbitrary certificate validation logic can be -implemented by customizing the `rustls` configuration; see the -[insecure_connection.rs][insecure] example for details. ->>>>>>> upstream/main Usually we only try to merge tagged upstream versions. Currently (as of the 0.13 iroh-quinn release) we've released work that hasn't been @@ -69,36 +61,6 @@ upstream version by running: `git tag --merged` -<<<<<<< HEAD This shows all the tags which are in the ancestors of HEAD. Look for the highest `quinn`, `quinn-proto` and `quinn-udp` tags which are found in all the ancestor commits. -======= -All feedback welcome. Feel free to file bugs, requests for documentation and -any other feedback to the [issue tracker][issues]. - -The quinn-proto test suite uses simulated IO for reproducibility and to avoid -long sleeps in certain timing-sensitive tests. If the `SSLKEYLOGFILE` -environment variable is set, the tests will emit UDP packets for inspection -using external protocol analyzers like Wireshark, and NSS-compatible key logs -for the client side of each connection will be written to the path specified in -the variable. - -The minimum supported Rust version for published releases of our -crates will always be at least 6 months old at the time of release. - -[quic]: https://quicwg.github.io/ -[issues]: https://github.com/djc/quinn/issues -[rustls]: https://github.com/ctz/rustls -[ring]: https://github.com/briansmith/ring -[talk]: https://paris.rustfest.eu/sessions/a-quic-future-in-rust -[slides]: https://github.com/djc/talks/blob/ff760845b51ba4836cce82e7f2c640ecb5fd59fa/2018-05-26%20A%20QUIC%20future%20in%20Rust/Quinn-Speaker.pdf -[animation]: https://dirkjan.ochtman.nl/files/head-of-line-blocking.html -[youtube]: https://www.youtube.com/watch?v=EHgyY5DNdvI -[letsencrypt]: https://letsencrypt.org/ -[rcgen]: https://crates.io/crates/rcgen -[examples]: https://github.com/djc/quinn/tree/main/quinn/examples -[documentation]: https://quinn-rs.github.io/quinn/networking-introduction.html -[sans-io]: https://sans-io.readthedocs.io/how-to-sans-io.html -[insecure]: https://github.com/quinn-rs/quinn/blob/main/quinn/examples/insecure_connection.rs ->>>>>>> upstream/main From ec7c8035fcb6409a20a8fd03b987b2b52eea37df Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 1 Dec 2025 14:40:11 +0100 Subject: [PATCH 69/71] ci: fixup wasm builds --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8aa98d51b..70272e547 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -153,7 +153,7 @@ jobs: ! wasm-tools print --skeleton target/wasm32-unknown-unknown/debug/iroh_quinn.wasm | grep 'import "env"' # Match the version of wasm-bindgen used in `Cargo.lock` - - run: cargo binstall wasm-bindgen-cli@0.2.105 --locked --no-confirm + - run: cargo binstall wasm-bindgen-cli@0.2.106 --locked --no-confirm - run: cargo test --locked -p iroh-quinn-proto --target wasm32-unknown-unknown msrv: From cdf316d44fe1a419715651751d64577809b15008 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 1 Dec 2025 14:40:19 +0100 Subject: [PATCH 70/71] test: fixup pqc test --- quinn/tests/post_quantum.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quinn/tests/post_quantum.rs b/quinn/tests/post_quantum.rs index 8983794b1..421e97219 100644 --- a/quinn/tests/post_quantum.rs +++ b/quinn/tests/post_quantum.rs @@ -12,7 +12,7 @@ use rustls::{ }; use tracing::info; -use quinn::{ +use iroh_quinn::{ Endpoint, crypto::rustls::{HandshakeData, QuicClientConfig, QuicServerConfig}, }; @@ -88,7 +88,7 @@ fn make_client_endpoint( .with_no_client_auth(); let client_cfg = - quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(rustls_config).unwrap())); + iroh_quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(rustls_config).unwrap())); let mut endpoint = Endpoint::client(bind_addr)?; endpoint.set_default_client_config(client_cfg); Ok(endpoint) @@ -101,7 +101,7 @@ fn make_server_endpoint( let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); let key = PrivatePkcs8KeyDer::from(cert.signing_key.serialize_der()); let cert = CertificateDer::from(cert.cert); - let mut server_config = quinn::ServerConfig::with_crypto(Arc::new( + let mut server_config = iroh_quinn::ServerConfig::with_crypto(Arc::new( QuicServerConfig::try_from( rustls::ServerConfig::builder_with_provider(Arc::new( rustls::crypto::aws_lc_rs::default_provider(), From 0805840549385a67cbc6e13346f72909ba2f3c69 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 2 Dec 2025 10:50:26 +0100 Subject: [PATCH 71/71] style: use display for PathId in tracing fields (#201) --- quinn-proto/src/connection/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quinn-proto/src/connection/mod.rs b/quinn-proto/src/connection/mod.rs index 1a1d3c5d5..f3c84001f 100644 --- a/quinn-proto/src/connection/mod.rs +++ b/quinn-proto/src/connection/mod.rs @@ -1070,7 +1070,7 @@ impl Connection { trace!( ?space_id, %path_id, - ?next_path_id, + %next_path_id, "nothing to send on path" ); path_id = *next_path_id;