diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in index 11bc44e18c11..b72dfbd39779 100644 --- a/.cargo/config.toml.in +++ b/.cargo/config.toml.in @@ -105,9 +105,9 @@ git = "https://github.com/mozilla/mp4parse-rust" rev = "e64650a686e5c5732395cd059e17cfd3b1e5b63b" replace-with = "vendored-sources" -[source."git+https://github.com/mozilla/neqo?tag=v0.11.0"] +[source."git+https://github.com/mozilla/neqo?tag=v0.12.2"] git = "https://github.com/mozilla/neqo" -tag = "v0.11.0" +tag = "v0.12.2" replace-with = "vendored-sources" [source."git+https://github.com/servo/unicode-bidi?rev=ca612daf1c08c53abe07327cb3e6ef6e0a760f0c"] diff --git a/Cargo.lock b/Cargo.lock index 8ed1bc1b8722..ee8f05b9cf4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4405,6 +4405,20 @@ dependencies = [ "num-traits", ] +[[package]] +name = "mtu" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c30d3771729ec4349aae3b1a7c0b6b4a1500459e60b1fda95fe0657c3711574" +dependencies = [ + "bindgen 0.69.4", + "cfg_aliases", + "libc", + "mozbuild", + "static_assertions", + "windows", +] + [[package]] name = "murmurhash3" version = "0.0.5" @@ -4436,8 +4450,8 @@ dependencies = [ [[package]] name = "neqo-bin" -version = "0.11.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.11.0#c6d5502fb5b827473e7c5d7c4c380275cdb3d931" +version = "0.12.2" +source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" dependencies = [ "clap", "clap-verbosity-flag", @@ -4458,8 +4472,8 @@ dependencies = [ [[package]] name = "neqo-common" -version = "0.11.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.11.0#c6d5502fb5b827473e7c5d7c4c380275cdb3d931" +version = "0.12.2" +source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" dependencies = [ "enum-map", "env_logger", @@ -4470,8 +4484,8 @@ dependencies = [ [[package]] name = "neqo-crypto" -version = "0.11.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.11.0#c6d5502fb5b827473e7c5d7c4c380275cdb3d931" +version = "0.12.2" +source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" dependencies = [ "bindgen 0.69.4", "log", @@ -4485,8 +4499,8 @@ dependencies = [ [[package]] name = "neqo-http3" -version = "0.11.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.11.0#c6d5502fb5b827473e7c5d7c4c380275cdb3d931" +version = "0.12.2" +source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" dependencies = [ "enumset", "log", @@ -4501,8 +4515,8 @@ dependencies = [ [[package]] name = "neqo-qpack" -version = "0.11.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.11.0#c6d5502fb5b827473e7c5d7c4c380275cdb3d931" +version = "0.12.2" +source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" dependencies = [ "log", "neqo-common", @@ -4513,12 +4527,13 @@ dependencies = [ [[package]] name = "neqo-transport" -version = "0.11.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.11.0#c6d5502fb5b827473e7c5d7c4c380275cdb3d931" +version = "0.12.2" +source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" dependencies = [ "enum-map", "indexmap", "log", + "mtu", "neqo-common", "neqo-crypto", "qlog", @@ -4528,9 +4543,10 @@ dependencies = [ [[package]] name = "neqo-udp" -version = "0.11.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.11.0#c6d5502fb5b827473e7c5d7c4c380275cdb3d931" +version = "0.12.2" +source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" dependencies = [ + "cfg_aliases", "log", "neqo-common", "quinn-udp", @@ -5203,9 +5219,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn-udp" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" dependencies = [ "cfg_aliases", "libc", diff --git a/build/workspace-hack/Cargo.toml b/build/workspace-hack/Cargo.toml index 2442f7c4afff..bd4f003fd783 100644 --- a/build/workspace-hack/Cargo.toml +++ b/build/workspace-hack/Cargo.toml @@ -199,6 +199,7 @@ features = [ version = "0.58" optional = true features = [ + "Win32_Foundation", "Win32_Graphics", "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D12", @@ -207,6 +208,9 @@ features = [ "Win32_Graphics_DirectComposition", "Win32_Graphics_Dxgi", "Win32_Graphics_Dxgi_Common", + "Win32_NetworkManagement_IpHelper", + "Win32_NetworkManagement_Ndis", + "Win32_Networking_WinSock", "Win32_Security", "Win32_System", "Win32_System_Diagnostics", diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 4c0391b7bfc8..3df829c2a19b 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -14629,6 +14629,13 @@ value: false mirror: always +# When network.http.http3.sni-slicing is set, TLS SNI slicing is enabled. +- name: network.http.http3.sni-slicing + type: RelaxedAtomicBool + value: true + mirror: always + rust: true + # When true, a http request will be upgraded to https when HTTPS RR is # available. - name: network.dns.upgrade_with_https_rr diff --git a/netwerk/metrics.yaml b/netwerk/metrics.yaml index 860a54923147..ed1669f226ed 100644 --- a/netwerk/metrics.yaml +++ b/netwerk/metrics.yaml @@ -1287,7 +1287,9 @@ networking: expires: never labels: - capable - - not-capable + - black-hole + - bleaching + - received-unsent-ect-1 http_3_loss_ratio: type: custom_distribution diff --git a/netwerk/socket/neqo_glue/Cargo.toml b/netwerk/socket/neqo_glue/Cargo.toml index 39ea96896d87..2ac349b727db 100644 --- a/netwerk/socket/neqo_glue/Cargo.toml +++ b/netwerk/socket/neqo_glue/Cargo.toml @@ -10,11 +10,11 @@ name = "neqo_glue" [dependencies] firefox-on-glean = { path = "../../../toolkit/components/glean/api" } -neqo-udp = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-http3 = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-transport = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-common = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-qpack = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } +neqo-udp = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-http3 = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-transport = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo", features = ["gecko"] } +neqo-common = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-qpack = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } nserror = { path = "../../../xpcom/rust/nserror" } nsstring = { path = "../../../xpcom/rust/nsstring" } xpcom = { path = "../../../xpcom/rust/xpcom" } @@ -29,10 +29,11 @@ uuid = { version = "1.0", features = ["v4"] } winapi = {version = "0.3", features = ["ws2def"] } [dependencies.neqo-crypto] -tag = "v0.11.0" +tag = "v0.12.2" git = "https://github.com/mozilla/neqo" default-features = false features = ["gecko"] [features] +bench = [] # no-op, see fuzzing = ["neqo-http3/disable-encryption"] diff --git a/netwerk/socket/neqo_glue/src/lib.rs b/netwerk/socket/neqo_glue/src/lib.rs index cd9051e17464..4e7d20c61b45 100644 --- a/netwerk/socket/neqo_glue/src/lib.rs +++ b/netwerk/socket/neqo_glue/src/lib.rs @@ -42,7 +42,7 @@ use winapi::shared::ws2def::{AF_INET, AF_INET6}; use xpcom::{interfaces::nsISocketProvider, AtomicRefcnt, RefCounted, RefPtr}; std::thread_local! { - static RECV_BUF: RefCell> = RefCell::new(vec![0; neqo_udp::RECV_BUF_SIZE]); + static RECV_BUF: RefCell = RefCell::new(neqo_udp::RecvBuf::new()); } #[repr(C)] @@ -203,10 +203,6 @@ impl NeqoHttp3Conn { let remote: SocketAddr = netaddr_to_socket_addr(remote_addr)?; let quic_version = match alpn_conv { - "h3-32" => Version::Draft32, - "h3-31" => Version::Draft31, - "h3-30" => Version::Draft30, - "h3-29" => Version::Draft29, "h3" => Version::Version1, _ => return Err(NS_ERROR_INVALID_ARG), }; @@ -232,7 +228,8 @@ impl NeqoHttp3Conn { .cc_algorithm(cc_algorithm) .max_data(max_data) .max_stream_data(StreamType::BiDi, false, max_stream_data) - .grease(static_prefs::pref!("security.tls.grease_http3_enable")); + .grease(static_prefs::pref!("security.tls.grease_http3_enable")) + .sni_slicing(static_prefs::pref!("network.http.http3.sni-slicing")); // Set a short timeout when fuzzing. #[cfg(feature = "fuzzing")] @@ -339,6 +336,7 @@ impl NeqoHttp3Conn { fn record_stats_in_glean(&self) { use firefox_on_glean::metrics::networking as glean; use neqo_common::IpTosEcn; + use neqo_transport::ecn; // Metric values must be recorded as integers. Glean does not support // floating point distributions. In order to represent values <1, they @@ -395,12 +393,32 @@ impl NeqoHttp3Conn { glean::http_3_ecn_ce_ect0_ratio_received .accumulate_single_sample_signed(ratio as i64); } - glean::http_3_ecn_path_capability - .get(&"capable") - .add(stats.ecn_paths_capable as i32); - glean::http_3_ecn_path_capability - .get(&"not-capable") - .add(stats.ecn_paths_not_capable as i32); + for (outcome, value) in stats.ecn_path_validation.into_iter() { + match outcome { + ecn::ValidationOutcome::Capable => { + glean::http_3_ecn_path_capability + .get(&"capable") + .add(value as i32); + } + ecn::ValidationOutcome::NotCapable(ecn::ValidationError::BlackHole) => { + glean::http_3_ecn_path_capability + .get(&"black-hole") + .add(value as i32); + } + ecn::ValidationOutcome::NotCapable(ecn::ValidationError::Bleaching) => { + glean::http_3_ecn_path_capability + .get(&"bleaching") + .add(value as i32); + } + ecn::ValidationOutcome::NotCapable( + ecn::ValidationError::ReceivedUnsentECT1, + ) => { + glean::http_3_ecn_path_capability + .get(&"received-unsent-ect-1") + .add(value as i32); + } + } + } } // Ignore connections into the void. @@ -593,18 +611,15 @@ pub unsafe extern "C" fn neqo_http3conn_process_input( }; } }; - if dgrams.len() == 0 { - break; - } // Attach metric instrumentation to `dgrams` iterator. let mut sum = 0; - conn.datagram_segments_received - .accumulate(dgrams.len() as u64); + let mut segment_count = 0; let datagram_segment_size_received = &mut conn.datagram_segment_size_received; let dgrams = dgrams.map(|d| { datagram_segment_size_received.accumulate(d.len() as u64); sum += d.len(); + segment_count += 1; d }); @@ -620,6 +635,7 @@ pub unsafe extern "C" fn neqo_http3conn_process_input( conn.conn.process_multiple_input(dgrams, Instant::now()); conn.datagram_size_received.accumulate(sum as u64); + conn.datagram_segments_received.accumulate(segment_count); bytes_read += sum; } @@ -1463,7 +1479,7 @@ pub extern "C" fn neqo_http3conn_event( return res; } Http3Event::PushPromise { - push_id, + push_id: push_id.into(), request_stream_id: request_stream_id.as_u64(), } } @@ -1480,16 +1496,22 @@ pub extern "C" fn neqo_http3conn_event( if res != NS_OK { return res; } - Http3Event::PushHeaderReady { push_id, fin } + Http3Event::PushHeaderReady { + push_id: push_id.into(), + fin, + } } } - Http3ClientEvent::PushDataReadable { push_id } => { - Http3Event::PushDataReadable { push_id } - } - Http3ClientEvent::PushCanceled { push_id } => Http3Event::PushCanceled { push_id }, - Http3ClientEvent::PushReset { push_id, error } => { - Http3Event::PushReset { push_id, error } - } + Http3ClientEvent::PushDataReadable { push_id } => Http3Event::PushDataReadable { + push_id: push_id.into(), + }, + Http3ClientEvent::PushCanceled { push_id } => Http3Event::PushCanceled { + push_id: push_id.into(), + }, + Http3ClientEvent::PushReset { push_id, error } => Http3Event::PushReset { + push_id: push_id.into(), + error, + }, Http3ClientEvent::RequestsCreatable => Http3Event::RequestsCreatable, Http3ClientEvent::AuthenticationNeeded => Http3Event::AuthenticationNeeded, Http3ClientEvent::ZeroRttRejected => Http3Event::ZeroRttRejected, diff --git a/netwerk/test/http3server/Cargo.toml b/netwerk/test/http3server/Cargo.toml index 90dc1aa514f9..004e487eae2d 100644 --- a/netwerk/test/http3server/Cargo.toml +++ b/netwerk/test/http3server/Cargo.toml @@ -6,11 +6,11 @@ edition = "2018" license = "MPL-2.0" [dependencies] -neqo-bin = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-transport = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-common = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-http3 = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } -neqo-qpack = { tag = "v0.11.0", git = "https://github.com/mozilla/neqo" } +neqo-bin = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-transport = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo", features = ["gecko"] } +neqo-common = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-http3 = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-qpack = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } log = "0.4.0" base64 = "0.21" cfg-if = "1.0" @@ -20,7 +20,7 @@ tokio = { version = "1", features = ["rt-multi-thread"] } mozilla-central-workspace-hack = { version = "0.1", features = ["http3server"], optional = true } [dependencies.neqo-crypto] -tag = "v0.11.0" +tag = "v0.12.2" git = "https://github.com/mozilla/neqo" default-features = false features = ["gecko"] @@ -32,3 +32,6 @@ bindgen = {version = "0.69", default-features = false, features = ["runtime"] } [[bin]] name = "http3server" path = "src/main.rs" + +[features] +bench = [] # no-op, see diff --git a/netwerk/test/http3server/src/main.rs b/netwerk/test/http3server/src/main.rs index b3d52e88c801..2207c49060ee 100644 --- a/netwerk/test/http3server/src/main.rs +++ b/netwerk/test/http3server/src/main.rs @@ -1227,3 +1227,5 @@ extern "C" fn __tsan_default_suppressions() -> *const std::os::raw::c_char { extern "C" {} #[cfg_attr(target_os = "windows", link(name = "propsys"))] extern "C" {} +#[cfg_attr(target_os = "windows", link(name = "iphlpapi"))] +extern "C" {} diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index e281f259938c..853a4398680a 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -3399,6 +3399,16 @@ criteria = "safe-to-deploy" version = "0.1.2" notes = "Developed by Mozilla staff." +[[audits.mtu]] +who = "Max Inden " +criteria = "safe-to-deploy" +version = "0.2.5" + +[[audits.mtu]] +who = "Max Leonard Inden " +criteria = "safe-to-deploy" +delta = "0.2.5 -> 0.2.6" + [[audits.naga]] who = "Dzmitry Malyshau " criteria = "safe-to-deploy" @@ -4049,6 +4059,11 @@ who = "Max Inden " criteria = "safe-to-deploy" delta = "0.5.8 -> 0.5.9" +[[audits.quinn-udp]] +who = "Max Leonard Inden " +criteria = "safe-to-deploy" +delta = "0.5.9 -> 0.5.10" + [[audits.quote]] who = "Nika Layzell " criteria = "safe-to-deploy" diff --git a/third_party/rust/mtu/.cargo-checksum.json b/third_party/rust/mtu/.cargo-checksum.json new file mode 100644 index 000000000000..599d7cd76856 --- /dev/null +++ b/third_party/rust/mtu/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CODE_OF_CONDUCT.md":"f7b4cba1deaa0a77bd611c04c84ef5b6859e44c8370f7513fe688fb9531b913b","Cargo.lock":"0d7b4f80f302400b5fba9847542ab3a0e94dd50bb0d27111927a6e4037b42eef","Cargo.toml":"82ab8662dd7a9c324bd23a7234fa2b8d6df9a9cab2b9baa778039bb55666bfb8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"4ad721b5b6a3d39ca3e2202f403d897c4a1d42896486dd58963a81f8e64ef61d","README.md":"2c9cce2eb06f0897e9b2fb68d8fa640da581bf440c26f266f8af5b3edb02dc6a","SECURITY.md":"75455814b6cf997e22a927eb979b4356d788583aa1eb96e90853aaab0f82ad1b","build.rs":"c26ac0385171924eefec5ce864067419bb023961b054abaf060d8da567dc6241","src/bsd.rs":"e680ddb399419bb67219fa1c0d3e6672d32023f325584869bd050e2f2ecc8ff9","src/lib.rs":"a59ae67763bc6bb9e6a4f7e7af61fed722ca032b667276a68e6ad687f1fe1e6e","src/linux.rs":"4e99612a04d744e2ca22b2e353faa500b37cb58caddaecb7566b4748aa1f7209","src/routesocket.rs":"be837947e2c3f9301a174499217fe8920ff492918bf85ca5eb281eb7ad2240e1","src/windows.rs":"b139c7aaa0c39415ce1773f1c9569be1a6b82dfe82334ab0c6cb80e7d232363e"},"package":"4c30d3771729ec4349aae3b1a7c0b6b4a1500459e60b1fda95fe0657c3711574"} \ No newline at end of file diff --git a/third_party/rust/mtu/CODE_OF_CONDUCT.md b/third_party/rust/mtu/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..e6b9a7dcaead --- /dev/null +++ b/third_party/rust/mtu/CODE_OF_CONDUCT.md @@ -0,0 +1,18 @@ +# Community Participation Guidelines + +This repository is governed by Mozilla's code of conduct and etiquette +guidelines. For more details, please read the [Mozilla Community Participation +Guidelines](https://www.mozilla.org/about/governance/policies/participation/). + +## How to Report + +For more information on how to report violations of the Community Participation +Guidelines, please read our '[How to +Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' +page. + +## Project Specific Etiquette + +Please consider the advice in the [Bugzilla etiquette +guide](https://bugzilla.mozilla.org/page.cgi?id=etiquette.html) when +contributing to this project. diff --git a/third_party/rust/mtu/Cargo.lock b/third_party/rust/mtu/Cargo.lock new file mode 100644 index 000000000000..eac5a62b9f95 --- /dev/null +++ b/third_party/rust/mtu/Cargo.lock @@ -0,0 +1,369 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0" +dependencies = [ + "memchr", +] + +[[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", + "lazy_static", + "lazycell", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[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.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mozbuild" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903970ae2f248d7275214cf8f387f8ba0c4ea7e3d87a320e85493db60ce28616" + +[[package]] +name = "mtu" +version = "0.2.6" +dependencies = [ + "bindgen", + "cfg_aliases", + "libc", + "mozbuild", + "static_assertions", + "windows", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/third_party/rust/mtu/Cargo.toml b/third_party/rust/mtu/Cargo.toml new file mode 100644 index 000000000000..b4d917f99f3e --- /dev/null +++ b/third_party/rust/mtu/Cargo.toml @@ -0,0 +1,139 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.76.0" +name = "mtu" +version = "0.2.6" +authors = ["The Mozilla Necko Team "] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Obtain the local network interface MTU towards a given IP address." +homepage = "https://github.com/mozilla/mtu/" +readme = "README.md" +keywords = [ + "mozilla", + "interface", + "mtu", +] +categories = [ + "network-programming", + "web-programming", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/mozilla/mtu/" + +[lib] +name = "mtu" +path = "src/lib.rs" + +[dependencies.libc] +version = "0.2" +default-features = false + +[dependencies.static_assertions] +version = "1.1" +default-features = false + +[build-dependencies.bindgen] +version = "0.69" +features = ["runtime"] +default-features = false + +[build-dependencies.cfg_aliases] +version = "0.2" +default-features = false + +[build-dependencies.mozbuild] +version = "0.1" +optional = true +default-features = false + +[features] +gecko = ["dep:mozbuild"] + +[target."cfg(windows)".dependencies.windows] +version = ">=0.58,<0.60" +features = [ + "Win32_Foundation", + "Win32_NetworkManagement_IpHelper", + "Win32_NetworkManagement_Ndis", + "Win32_Networking_WinSock", +] + +[badges.codecov] +branch = "main" +repository = "mozilla/mtu" + +[badges.is-it-maintained-issue-resolution] +branch = "main" +repository = "mozilla/mtu" + +[badges.is-it-maintained-open-issues] +branch = "main" +repository = "mozilla/mtu" + +[badges.maintenance] +branch = "main" +status = "actively-developed" + +[lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" +multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" +unwrap_in_result = "warn" +unwrap_used = "warn" + +[lints.clippy.cargo] +level = "warn" +priority = -1 + +[lints.clippy.nursery] +level = "warn" +priority = -1 + +[lints.clippy.pedantic] +level = "warn" +priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/mtu/LICENSE-APACHE b/third_party/rust/mtu/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/third_party/rust/mtu/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/mtu/LICENSE-MIT b/third_party/rust/mtu/LICENSE-MIT new file mode 100644 index 000000000000..b4850c952004 --- /dev/null +++ b/third_party/rust/mtu/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2019 Mozilla Foundation + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/mtu/README.md b/third_party/rust/mtu/README.md new file mode 100644 index 000000000000..c116263d8b16 --- /dev/null +++ b/third_party/rust/mtu/README.md @@ -0,0 +1,46 @@ +[![Coverage Status](https://codecov.io/gh/mozilla/mtu/branch/main/graph/badge.svg)](https://codecov.io/gh/mozilla/mtu) +[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/mozilla/mtu.svg)](https://isitmaintained.com/project/mozilla/mtu "Average time to resolve an issue") +[![Percentage of issues still open](https://isitmaintained.com/badge/open/mozilla/mtu.svg)](https://isitmaintained.com/project/mozilla/mtu "Percentage of issues still open") +![Maintenance](https://img.shields.io/badge/maintenance-activly--developed-brightgreen.svg) + +# mtu + +A crate to return the name and maximum transmission unit (MTU) of the local network interface +towards a given destination `SocketAddr`, optionally from a given local `SocketAddr`. + +## Usage + +This crate exports a single function `interface_and_mtu` that returns the name and +[maximum transmission unit (MTU)](https://en.wikipedia.org/wiki/Maximum_transmission_unit) +of the outgoing network interface towards a remote destination identified by an `IpAddr`. + +## Example +```rust +let destination = IpAddr::V4(Ipv4Addr::LOCALHOST); +let (name, mtu): (String, usize) = mtu::interface_and_mtu(destination).unwrap(); +println!("MTU towards {destination} is {mtu} on {name}"); +``` + +## Supported Platforms + +* Linux +* macOS +* Windows +* FreeBSD +* NetBSD +* OpenBSD +* Solaris + +## Notes + +The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some platforms for +some remote destinations. (For example, loopback destinations on Windows.) + +The returned interface name is obtained from the operating system. + +## Contributing + +We're happy to receive PRs that improve this crate. Please take a look at our [community +guidelines](CODE_OF_CONDUCT.md) beforehand. + +License: MIT OR Apache-2.0 diff --git a/third_party/rust/mtu/SECURITY.md b/third_party/rust/mtu/SECURITY.md new file mode 100644 index 000000000000..547ca587e676 --- /dev/null +++ b/third_party/rust/mtu/SECURITY.md @@ -0,0 +1,31 @@ +# Security Policy + +This document describes how security vulnerabilities in this project should be reported. + +## Supported Versions + +Support for `mtu` is based on the Firefox version in which it has landed. +Versions of `mtu` in [current versions of Firefox](https://whattrainisitnow.com/calendar/) are actively supported. + +The version of `mtu` that is active can be found in the Firefox repositories: + +- [release](https://hg.mozilla.org/mozilla-unified/file/release/third_party/rust/mtu-transport/Cargo.toml), +- [beta](https://hg.mozilla.org/mozilla-unified/file/beta/third_party/rust/mtu-transport/Cargo.toml), and +- [trunk/central](https://hg.mozilla.org/mozilla-unified/file/central/third_party/rust/mtu-transport/Cargo.toml), +- [ESR 115](https://hg.mozilla.org/mozilla-unified/file/esr115/third_party/rust/mtu-transport/Cargo.toml). + +The listed version in these files corresponds to [tags](https://github.com/mozilla/mtu/tags) on this repository. +Releases do not always correspond to a branch. + +We welcome reports of security vulnerabilities in any of these released versions or the latest code on the `main` branch. + +## Reporting a Vulnerability + +To report a security problem with `mtu`, create a bug in Mozilla's Bugzilla instance in the [Core :: Networking](https://bugzilla.mozilla.org/enter_bug.cgi?product=Core&component=Networking) component. + +**IMPORTANT: For security issues, please make sure that you check the box labelled "Many users could be harmed by this security problem".** +We advise that you check this option for anything that involves anything security-relevant, including memory safety, crashes, race conditions, and handling of confidential information. + +Review Mozilla's [guides on bug reporting](https://bugzilla.mozilla.org/page.cgi?id=bug-writing.html) before you open a bug. + +Mozilla operates a [bug bounty program](https://www.mozilla.org/en-US/security/bug-bounty/), for which this project is eligible. diff --git a/third_party/rust/mtu/build.rs b/third_party/rust/mtu/build.rs new file mode 100644 index 000000000000..fdd736631daa --- /dev/null +++ b/third_party/rust/mtu/build.rs @@ -0,0 +1,112 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(clippy::unwrap_used)] // OK in build scripts. + +use std::env; + +const BINDINGS: &str = "bindings.rs"; + +#[cfg(feature = "gecko")] +fn clang_args() -> Vec { + use mozbuild::TOPOBJDIR; + + let flags_path = TOPOBJDIR.join("netwerk/socket/neqo/extra-bindgen-flags"); + println!("cargo:rerun-if-changed={}", flags_path.to_str().unwrap()); + + let mut flags: Vec = std::fs::read_to_string(flags_path) + .expect("Failed to read extra-bindgen-flags file") + .split_whitespace() + .map(std::borrow::ToOwned::to_owned) + .collect(); + + flags.push(String::from("-include")); + flags.push( + TOPOBJDIR + .join("dist") + .join("include") + .join("mozilla-config.h") + .to_str() + .unwrap() + .to_string(), + ); + flags +} + +#[cfg(not(feature = "gecko"))] +const fn clang_args() -> Vec { + Vec::new() +} + +fn bindgen() { + let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); + + // Platforms currently not supported. + // + // See . + if matches!(target_os.as_str(), "ios" | "tvos" | "visionos") { + return; + } + + if target_os == "windows" { + return; + } + + let bindings = if matches!(target_os.as_str(), "linux" | "android") { + bindgen::Builder::default() + .header_contents("rtnetlink.h", "#include ") + // Only generate bindings for the following types + .allowlist_type("rtattr|rtmsg|ifinfomsg|nlmsghdr") + } else { + bindgen::Builder::default() + .header_contents( + "route.h", + "#include \n#include \n#include \n#include ", + ) + // Only generate bindings for the following types and items + .allowlist_type("rt_msghdr|rt_metrics|if_data") + .allowlist_item("RTAX_MAX|RTM_GET|RTM_VERSION|RTA_DST|RTA_IFP") + }; + + let bindings = bindings + .clang_args(clang_args()) + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + // Constants should be generated as &CStr instead of &[u8]. + .generate_cstr(true) + // Always emit explicit padding fields. + .explicit_padding(true) + // Default trait should be derived when possible + .derive_default(true) + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/$BINDINGS file. + let out_path = std::path::PathBuf::from(env::var("OUT_DIR").unwrap()).join(BINDINGS); + bindings + .write_to_file(out_path.clone()) + .expect("Couldn't write bindings!"); + println!("cargo:rustc-env=BINDINGS={}", out_path.display()); +} + +fn main() { + // Setup cfg aliases + cfg_aliases::cfg_aliases! { + bsd: { + any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "solaris" + ) + } + } + + bindgen(); +} diff --git a/third_party/rust/mtu/src/bsd.rs b/third_party/rust/mtu/src/bsd.rs new file mode 100644 index 000000000000..ea788d241813 --- /dev/null +++ b/third_party/rust/mtu/src/bsd.rs @@ -0,0 +1,358 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{ + ffi::CStr, + io::{Error, ErrorKind, Read as _, Result, Write as _}, + marker::PhantomData, + net::IpAddr, + num::TryFromIntError, + ops::Deref, + ptr, slice, +}; + +use libc::{ + freeifaddrs, getifaddrs, getpid, if_indextoname, ifaddrs, in6_addr, in_addr, sockaddr, + sockaddr_dl, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_UNSPEC, PF_ROUTE, +}; +use static_assertions::{const_assert, const_assert_eq}; + +#[allow( + non_camel_case_types, + clippy::struct_field_names, + clippy::too_many_lines, + clippy::cognitive_complexity, + dead_code // RTA_IFP is only used on NetBSD and Solaris +)] +mod bindings { + include!(env!("BINDINGS")); +} + +#[cfg(any(target_os = "netbsd", target_os = "solaris"))] +use crate::bsd::bindings::RTA_IFP; +use crate::{ + aligned_by, + bsd::bindings::{if_data, rt_msghdr, RTAX_MAX, RTA_DST}, + default_err, + routesocket::RouteSocket, + unlikely_err, +}; + +#[cfg(target_os = "macos")] +const ALIGN: usize = std::mem::size_of::(); + +#[cfg(bsd)] +// See https://github.com/freebsd/freebsd-src/blob/524a425d30fce3d5e47614db796046830b1f6a83/sys/net/route.h#L362-L371 +// See https://github.com/NetBSD/src/blob/4b50954e98313db58d189dd87b4541929efccb09/sys/net/route.h#L329-L331 +// See https://github.com/Arquivotheca/Solaris-8/blob/2ad1d32f9eeed787c5adb07eb32544276e2e2444/osnet_volume/usr/src/cmd/cmd-inet/usr.sbin/route.c#L238-L239 +const ALIGN: usize = std::mem::size_of::(); + +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] +asserted_const_with_type!(RTM_ADDRS, i32, RTA_DST, u32); + +#[cfg(any(target_os = "netbsd", target_os = "solaris"))] +asserted_const_with_type!(RTM_ADDRS, i32, RTA_DST | RTA_IFP, u32); + +#[cfg(not(target_os = "solaris"))] +type AddressFamily = u8; + +#[cfg(target_os = "solaris")] +type AddressFamily = u16; + +asserted_const_with_type!(AF_INET, AddressFamily, libc::AF_INET, i32); +asserted_const_with_type!(AF_INET6, AddressFamily, libc::AF_INET6, i32); +asserted_const_with_type!(AF_LINK, AddressFamily, libc::AF_LINK, i32); +asserted_const_with_type!(RTM_VERSION, u8, bindings::RTM_VERSION, u32); +asserted_const_with_type!(RTM_GET, u8, bindings::RTM_GET, u32); + +const_assert!(std::mem::size_of::() + ALIGN <= u8::MAX as usize); +const_assert!(std::mem::size_of::() + ALIGN <= u8::MAX as usize); +const_assert!(std::mem::size_of::() <= u8::MAX as usize); + +struct IfAddrs(*mut ifaddrs); + +impl Default for IfAddrs { + fn default() -> Self { + Self(ptr::null_mut()) + } +} + +impl IfAddrs { + fn new() -> Result { + let mut ifap = Self::default(); + // getifaddrs allocates memory for the linked list of interfaces that is freed by + // `IfAddrs::drop`. + if unsafe { getifaddrs(ptr::from_mut(&mut ifap.0)) } != 0 { + return Err(Error::last_os_error()); + } + Ok(ifap) + } + + const fn iter(&self) -> IfAddrPtr { + IfAddrPtr { + ptr: self.0, + _ref: PhantomData, + } + } +} + +impl Drop for IfAddrs { + fn drop(&mut self) { + if !self.0.is_null() { + // Free the memory allocated by `getifaddrs`. + unsafe { + freeifaddrs(self.0); + } + } + } +} + +struct IfAddrPtr<'a> { + ptr: *mut ifaddrs, + _ref: PhantomData<&'a ifaddrs>, +} + +impl IfAddrPtr<'_> { + fn addr(&self) -> sockaddr { + unsafe { *self.ifa_addr } + } + + fn name(&self) -> String { + unsafe { CStr::from_ptr(self.ifa_name).to_string_lossy().to_string() } + } + + fn data(&self) -> Option { + if self.ifa_data.is_null() { + None + } else { + Some(unsafe { self.ifa_data.cast::().read() }) + } + } +} + +impl Deref for IfAddrPtr<'_> { + type Target = ifaddrs; + + fn deref(&self) -> &Self::Target { + unsafe { self.ptr.as_ref().expect("can deref") } + } +} + +impl Iterator for IfAddrPtr<'_> { + type Item = Self; + + fn next(&mut self) -> Option { + ptr::NonNull::new(self.ptr).map(|p| { + self.ptr = unsafe { p.as_ref().ifa_next }; + IfAddrPtr { + ptr: p.as_ptr(), + _ref: PhantomData, + } + }) + } +} + +fn if_name_mtu(idx: u32) -> Result<(String, Option)> { + let mut name = [0; libc::IF_NAMESIZE]; + // if_indextoname writes into the provided buffer. + if unsafe { if_indextoname(idx, name.as_mut_ptr()).is_null() } { + return Err(Error::last_os_error()); + } + // Convert to Rust string. + let name = unsafe { + CStr::from_ptr(name.as_ptr()) + .to_str() + .map_err(|err| Error::new(ErrorKind::Other, err))? + }; + let mtu = IfAddrs::new()? + .iter() + .find(|ifa| ifa.addr().sa_family == AF_LINK && ifa.name() == name) + .and_then(|ifa| ifa.data()) + .and_then(|ifa_data| usize::try_from(ifa_data.ifi_mtu).ok()); + Ok((name.to_string(), mtu)) +} + +#[repr(C)] +union SockaddrStorage { + sin: sockaddr_in, + sin6: sockaddr_in6, +} + +fn sockaddr_len(af: AddressFamily) -> Result { + let sa_len = match af { + AF_INET => std::mem::size_of::(), + AF_INET6 => std::mem::size_of::(), + _ => { + return Err(Error::new( + ErrorKind::InvalidInput, + format!("Unsupported address family {af:?}"), + )) + } + }; + Ok(aligned_by(sa_len, ALIGN)) +} + +impl From for SockaddrStorage { + fn from(ip: IpAddr) -> Self { + match ip { + IpAddr::V4(ip) => SockaddrStorage { + sin: sockaddr_in { + #[cfg(not(target_os = "solaris"))] + #[allow(clippy::cast_possible_truncation)] + // `sockaddr_in` len is <= u8::MAX per `const_assert!` above. + sin_len: std::mem::size_of::() as u8, + sin_family: AF_INET, + sin_addr: in_addr { + s_addr: u32::from_ne_bytes(ip.octets()), + }, + sin_port: 0, + sin_zero: [0; 8], + }, + }, + IpAddr::V6(ip) => SockaddrStorage { + sin6: sockaddr_in6 { + #[cfg(not(target_os = "solaris"))] + #[allow(clippy::cast_possible_truncation)] + // `sockaddr_in6` len is <= u8::MAX per `const_assert!` above. + sin6_len: std::mem::size_of::() as u8, + sin6_family: AF_INET6, + sin6_addr: in6_addr { + s6_addr: ip.octets(), + }, + sin6_port: 0, + sin6_flowinfo: 0, + sin6_scope_id: 0, + #[cfg(target_os = "solaris")] + __sin6_src_id: 0, + }, + }, + } + } +} + +#[repr(C)] +struct RouteMessage { + rtm: rt_msghdr, + sa: SockaddrStorage, +} + +impl RouteMessage { + fn new(remote: IpAddr, seq: i32) -> Result { + let sa = SockaddrStorage::from(remote); + let sa_len = sockaddr_len(match remote { + IpAddr::V4(_) => AF_INET, + IpAddr::V6(_) => AF_INET6, + })?; + Ok(Self { + rtm: rt_msghdr { + #[allow(clippy::cast_possible_truncation)] + // `rt_msghdr` len + `ALIGN` is <= u8::MAX per `const_assert!` above. + rtm_msglen: (std::mem::size_of::() + sa_len) as u16, + rtm_version: RTM_VERSION, + rtm_type: RTM_GET, + rtm_seq: seq, + rtm_addrs: RTM_ADDRS, + ..Default::default() + }, + sa, + }) + } + + const fn version(&self) -> u8 { + self.rtm.rtm_version + } + + const fn kind(&self) -> u8 { + self.rtm.rtm_type + } + + const fn len(&self) -> usize { + self.rtm.rtm_msglen as usize + } +} + +impl From<&RouteMessage> for &[u8] { + fn from(value: &RouteMessage) -> Self { + debug_assert!(value.len() >= std::mem::size_of::()); + unsafe { slice::from_raw_parts(ptr::from_ref(value).cast(), value.len()) } + } +} + +impl From<&[u8]> for rt_msghdr { + fn from(value: &[u8]) -> Self { + debug_assert!(value.len() >= std::mem::size_of::()); + unsafe { ptr::read_unaligned(value.as_ptr().cast()) } + } +} + +fn if_index_mtu(remote: IpAddr) -> Result<(u16, Option)> { + // Open route socket. + let mut fd = RouteSocket::new(PF_ROUTE, AF_UNSPEC)?; + + // Send route message. + let query_seq = RouteSocket::new_seq(); + let query = RouteMessage::new(remote, query_seq)?; + let query_version = query.version(); + let query_type = query.kind(); + fd.write_all((&query).into())?; + + // Read route messages. + let pid = unsafe { getpid() }; + loop { + let mut buf = vec![ + 0u8; + std::mem::size_of::() + + // There will never be `RTAX_MAX` sockaddrs attached, but it's a safe upper bound. + (RTAX_MAX as usize * std::mem::size_of::()) + ]; + let len = fd.read(&mut buf[..])?; + if len < std::mem::size_of::() { + return Err(default_err()); + } + let (reply, mut sa) = buf.split_at(std::mem::size_of::()); + let reply: rt_msghdr = reply.into(); + if !(reply.rtm_version == query_version + && reply.rtm_pid == pid + && reply.rtm_seq == query_seq) + { + continue; + } + if reply.rtm_type != query_type { + return Err(default_err()); + } + + // This is a reply to our query. + // This is the reply we are looking for. + // Some BSDs let us get the interface index and MTU directly from the reply. + let mtu = (reply.rtm_rmx.rmx_mtu != 0) + .then(|| usize::try_from(reply.rtm_rmx.rmx_mtu)) + .transpose() + .map_err(|e: TryFromIntError| unlikely_err(e.to_string()))?; + if reply.rtm_index != 0 { + // Some BSDs return the interface index directly. + return Ok((reply.rtm_index, mtu)); + } + // For others, we need to extract it from the sockaddrs. + for i in 0..RTAX_MAX { + if (reply.rtm_addrs & (1 << i)) == 0 { + continue; + } + let saddr = unsafe { ptr::read_unaligned(sa.as_ptr().cast::()) }; + if saddr.sa_family != AF_LINK { + (_, sa) = sa.split_at(sockaddr_len(saddr.sa_family)?); + continue; + } + let sdl = unsafe { ptr::read_unaligned(sa.as_ptr().cast::()) }; + return Ok((sdl.sdl_index, mtu)); + } + } +} + +pub fn interface_and_mtu_impl(remote: IpAddr) -> Result<(String, usize)> { + let (if_index, mtu1) = if_index_mtu(remote)?; + let (if_name, mtu2) = if_name_mtu(if_index.into())?; + Ok((if_name, mtu1.or(mtu2).ok_or_else(default_err)?)) +} diff --git a/third_party/rust/mtu/src/lib.rs b/third_party/rust/mtu/src/lib.rs new file mode 100644 index 000000000000..14fcc2aa574b --- /dev/null +++ b/third_party/rust/mtu/src/lib.rs @@ -0,0 +1,199 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A crate to return the name and maximum transmission unit (MTU) of the local network interface +//! towards a given destination `SocketAddr`, optionally from a given local `SocketAddr`. +//! +//! # Usage +//! +//! This crate exports a single function `interface_and_mtu` that returns the name and +//! [maximum transmission unit (MTU)](https://en.wikipedia.org/wiki/Maximum_transmission_unit) +//! of the outgoing network interface towards a remote destination identified by an `IpAddr`. +//! +//! # Example +//! ``` +//! # use std::net::{IpAddr, Ipv4Addr}; +//! let destination = IpAddr::V4(Ipv4Addr::LOCALHOST); +//! let (name, mtu): (String, usize) = mtu::interface_and_mtu(destination).unwrap(); +//! println!("MTU towards {destination} is {mtu} on {name}"); +//! ``` +//! +//! # Supported Platforms +//! +//! * Linux +//! * macOS +//! * Windows +//! * FreeBSD +//! * NetBSD +//! * OpenBSD +//! * Solaris +//! +//! # Notes +//! +//! The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some platforms for +//! some remote destinations. (For example, loopback destinations on Windows.) +//! +//! The returned interface name is obtained from the operating system. +//! +//! # Contributing +//! +//! We're happy to receive PRs that improve this crate. Please take a look at our [community +//! guidelines](CODE_OF_CONDUCT.md) beforehand. + +use std::{ + io::{Error, ErrorKind, Result}, + net::IpAddr, +}; + +#[cfg(not(target_os = "windows"))] +macro_rules! asserted_const_with_type { + ($name:ident, $t1:ty, $e:expr, $t2:ty) => { + #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] // Guarded by the following `const_assert_eq!`. + const $name: $t1 = $e as $t1; + const_assert_eq!($name as $t2, $e); + }; +} + +#[cfg(any(target_os = "macos", bsd))] +mod bsd; + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod linux; + +#[cfg(target_os = "windows")] +mod windows; + +#[cfg(not(target_os = "windows"))] +mod routesocket; + +#[cfg(any(target_os = "macos", bsd))] +use bsd::interface_and_mtu_impl; +#[cfg(any(target_os = "linux", target_os = "android"))] +use linux::interface_and_mtu_impl; +#[cfg(target_os = "windows")] +use windows::interface_and_mtu_impl; + +/// Prepare a default error. +fn default_err() -> Error { + Error::new(ErrorKind::NotFound, "Local interface MTU not found") +} + +/// Prepare an error for cases that "should never happen". +#[cfg(not(target_os = "windows"))] +fn unlikely_err(msg: String) -> Error { + debug_assert!(false, "{msg}"); + Error::new(ErrorKind::Other, msg) +} + +/// Align `size` to the next multiple of `align` (which needs to be a power of two). +#[cfg(not(target_os = "windows"))] +const fn aligned_by(size: usize, align: usize) -> usize { + if size == 0 { + align + } else { + 1 + ((size - 1) | (align - 1)) + } +} + +// Platforms currently not supported. +// +// See . +#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "visionos"))] +pub fn interface_and_mtu_impl(remote: IpAddr) -> Result<(String, usize)> { + return Err(default_err()); +} + +/// Return the name and maximum transmission unit (MTU) of the outgoing network interface towards a +/// remote destination identified by an [`IpAddr`], +/// +/// The returned MTU may exceed the maximum IP packet size of 65,535 bytes on some platforms for +/// some remote destinations. (For example, loopback destinations on Windows.) +/// +/// The returned interface name is obtained from the operating system. +/// +/// # Errors +/// +/// This function returns an error if the local interface MTU cannot be determined. +pub fn interface_and_mtu(remote: IpAddr) -> Result<(String, usize)> { + interface_and_mtu_impl(remote) +} + +#[cfg(test)] +mod test { + use std::{ + env, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, + }; + + use crate::interface_and_mtu; + + #[derive(Debug)] + struct NameMtu<'a>(Option<&'a str>, usize); + + impl PartialEq> for (String, usize) { + fn eq(&self, other: &NameMtu<'_>) -> bool { + other.0.map_or(true, |name| name == self.0) && other.1 == self.1 + } + } + + #[cfg(any(target_os = "macos", target_os = "freebsd",))] + const LOOPBACK: &[NameMtu] = &[NameMtu(Some("lo0"), 16_384), NameMtu(Some("lo0"), 16_384)]; + #[cfg(any(target_os = "linux", target_os = "android"))] + const LOOPBACK: &[NameMtu] = &[NameMtu(Some("lo"), 65_536), NameMtu(Some("lo"), 65_536)]; + #[cfg(target_os = "windows")] + const LOOPBACK: &[NameMtu] = &[ + NameMtu(Some("loopback_0"), 4_294_967_295), + NameMtu(Some("loopback_0"), 4_294_967_295), + ]; + #[cfg(target_os = "openbsd")] + const LOOPBACK: &[NameMtu] = &[NameMtu(Some("lo0"), 32_768), NameMtu(Some("lo0"), 32_768)]; + #[cfg(target_os = "netbsd")] + const LOOPBACK: &[NameMtu] = &[NameMtu(Some("lo0"), 33_624), NameMtu(Some("lo0"), 33_624)]; + #[cfg(target_os = "solaris")] + // Note: Different loopback MTUs for IPv4 and IPv6?! + const LOOPBACK: &[NameMtu] = &[NameMtu(Some("lo0"), 8_232), NameMtu(Some("lo0"), 8_252)]; + + // Non-loopback interface names are unpredictable, so we only check the MTU. + const INET: NameMtu = NameMtu(None, 1_500); + + #[test] + fn loopback_v4() { + assert_eq!( + interface_and_mtu(IpAddr::V4(Ipv4Addr::LOCALHOST)).unwrap(), + LOOPBACK[0] + ); + } + + #[test] + fn loopback_v6() { + assert_eq!( + interface_and_mtu(IpAddr::V6(Ipv6Addr::LOCALHOST)).unwrap(), + LOOPBACK[1] + ); + } + + #[test] + fn inet_v4() { + assert_eq!( + interface_and_mtu(IpAddr::V4(Ipv4Addr::new( + 104, 16, 132, 229 // cloudflare.com + ))) + .unwrap(), + INET + ); + } + + #[test] + fn inet_v6() { + match interface_and_mtu(IpAddr::V6(Ipv6Addr::new( + 0x2606, 0x4700, 0, 0, 0, 0, 0x6810, 0x84e5, // cloudflare.com + ))) { + Ok(res) => assert_eq!(res, INET), + // The GitHub CI environment does not have IPv6 connectivity. + Err(_) => assert!(env::var("GITHUB_ACTIONS").is_ok()), + } + } +} diff --git a/third_party/rust/mtu/src/linux.rs b/third_party/rust/mtu/src/linux.rs new file mode 100644 index 000000000000..1a33df8d779e --- /dev/null +++ b/third_party/rust/mtu/src/linux.rs @@ -0,0 +1,351 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{ + ffi::CStr, + io::{Error, ErrorKind, Read as _, Result, Write as _}, + net::IpAddr, + num::TryFromIntError, + ptr, slice, +}; + +use libc::{ + c_int, AF_NETLINK, ARPHRD_NONE, IFLA_IFNAME, IFLA_MTU, NETLINK_ROUTE, RTA_DST, RTA_OIF, + RTM_GETLINK, RTM_GETROUTE, RTM_NEWLINK, RTM_NEWROUTE, RTN_UNICAST, RT_SCOPE_UNIVERSE, + RT_TABLE_MAIN, +}; +use static_assertions::{const_assert, const_assert_eq}; + +use crate::{aligned_by, default_err, routesocket::RouteSocket, unlikely_err}; + +#[allow( + clippy::struct_field_names, + non_camel_case_types, + clippy::too_many_lines +)] +mod bindings { + include!(env!("BINDINGS")); +} + +use bindings::{ifinfomsg, nlmsghdr, rtattr, rtmsg}; + +asserted_const_with_type!(AF_INET, u8, libc::AF_INET, i32); +asserted_const_with_type!(AF_INET6, u8, libc::AF_INET6, i32); +asserted_const_with_type!(AF_UNSPEC, u8, libc::AF_UNSPEC, i32); +asserted_const_with_type!(NLM_F_REQUEST, u16, libc::NLM_F_REQUEST, c_int); +asserted_const_with_type!(NLM_F_ACK, u16, libc::NLM_F_ACK, c_int); +asserted_const_with_type!(NLMSG_ERROR, u16, libc::NLMSG_ERROR, c_int); + +const_assert!(std::mem::size_of::() <= u8::MAX as usize); +const_assert!(std::mem::size_of::() <= u8::MAX as usize); +const_assert!(std::mem::size_of::() <= u8::MAX as usize); +const_assert!(std::mem::size_of::() <= u8::MAX as usize); + +const NETLINK_BUFFER_SIZE: usize = 8192; // See netlink(7) man page. + +#[repr(C)] +enum AddrBytes { + V4([u8; 4]), + V6([u8; 16]), +} + +impl AddrBytes { + const fn new(ip: IpAddr) -> Self { + match ip { + IpAddr::V4(ip) => Self::V4(ip.octets()), + IpAddr::V6(ip) => Self::V6(ip.octets()), + } + } + + const fn len(&self) -> usize { + match self { + Self::V4(_) => 4, + Self::V6(_) => 16, + } + } +} + +impl From for [u8; 16] { + fn from(addr: AddrBytes) -> Self { + match addr { + AddrBytes::V4(bytes) => { + let mut v6 = [0; 16]; + v6[..4].copy_from_slice(&bytes); + v6 + } + AddrBytes::V6(bytes) => bytes, + } + } +} + +#[repr(C)] +#[derive(Default)] +struct IfIndexMsg { + nlmsg: nlmsghdr, + rtm: rtmsg, + rt: rtattr, + addr: [u8; 16], +} + +impl IfIndexMsg { + fn new(remote: IpAddr, nlmsg_seq: u32) -> Self { + let addr = AddrBytes::new(remote); + #[allow(clippy::cast_possible_truncation)] + // Structs lens are <= u8::MAX per `const_assert!`s above; `addr_bytes` is max. 16 for IPv6. + let nlmsg_len = (std::mem::size_of::() + + std::mem::size_of::() + + std::mem::size_of::() + + addr.len()) as u32; + Self { + nlmsg: nlmsghdr { + nlmsg_len, + nlmsg_type: RTM_GETROUTE, + nlmsg_flags: NLM_F_REQUEST | NLM_F_ACK, + nlmsg_seq, + ..Default::default() + }, + rtm: rtmsg { + rtm_family: match remote { + IpAddr::V4(_) => AF_INET, + IpAddr::V6(_) => AF_INET6, + }, + rtm_dst_len: match remote { + IpAddr::V4(_) => 32, + IpAddr::V6(_) => 128, + }, + rtm_table: RT_TABLE_MAIN, + rtm_scope: RT_SCOPE_UNIVERSE, + rtm_type: RTN_UNICAST, + ..Default::default() + }, + rt: rtattr { + #[allow(clippy::cast_possible_truncation)] + // Structs len is <= u8::MAX per `const_assert!` above; `addr_bytes` is max. 16 for IPv6. + rta_len: (std::mem::size_of::() + addr.len()) as u16, + rta_type: RTA_DST, + }, + addr: addr.into(), + } + } + + const fn len(&self) -> usize { + let len = self.nlmsg.nlmsg_len as usize; + debug_assert!(len <= std::mem::size_of::()); + len + } +} + +impl From<&IfIndexMsg> for &[u8] { + fn from(value: &IfIndexMsg) -> Self { + unsafe { slice::from_raw_parts(ptr::from_ref(value).cast(), value.len()) } + } +} + +impl TryFrom<&[u8]> for nlmsghdr { + type Error = Error; + + fn try_from(value: &[u8]) -> Result { + if value.len() < std::mem::size_of::() { + return Err(default_err()); + } + Ok(unsafe { ptr::read_unaligned(value.as_ptr().cast()) }) + } +} + +fn parse_c_int(buf: &[u8]) -> Result { + let bytes = <&[u8] as TryInto<[u8; std::mem::size_of::()]>>::try_into( + &buf[..std::mem::size_of::()], + ) + .map_err(|_| default_err())?; + Ok(c_int::from_ne_bytes(bytes)) +} + +fn read_msg_with_seq(fd: &mut RouteSocket, seq: u32, kind: u16) -> Result<(nlmsghdr, Vec)> { + loop { + let buf = &mut [0u8; NETLINK_BUFFER_SIZE]; + let len = fd.read(buf.as_mut_slice())?; + let mut next = &buf[..len]; + while std::mem::size_of::() <= next.len() { + let (hdr, mut msg) = next.split_at(std::mem::size_of::()); + let hdr: nlmsghdr = hdr.try_into()?; + // `msg` has the remainder of this message plus any following messages. + // Strip those it off and assign them to `next`. + debug_assert!(std::mem::size_of::() <= hdr.nlmsg_len as usize); + (msg, next) = msg.split_at(hdr.nlmsg_len as usize - std::mem::size_of::()); + + if hdr.nlmsg_seq != seq { + continue; + } + + if hdr.nlmsg_type == NLMSG_ERROR { + // Extract the error code and return it. + let err = parse_c_int(msg)?; + if err != 0 { + return Err(Error::from_raw_os_error(-err)); + } + } else if hdr.nlmsg_type == kind { + // Return the header and the message. + return Ok((hdr, msg.to_vec())); + } + } + } +} + +impl TryFrom<&[u8]> for rtattr { + type Error = Error; + + fn try_from(value: &[u8]) -> Result { + if value.len() < std::mem::size_of::() { + return Err(default_err()); + } + Ok(unsafe { ptr::read_unaligned(value.as_ptr().cast()) }) + } +} + +struct RtAttr<'a> { + hdr: rtattr, + msg: &'a [u8], +} + +impl<'a> RtAttr<'a> { + fn new(bytes: &'a [u8]) -> Result { + debug_assert!(bytes.len() >= std::mem::size_of::()); + let (hdr, mut msg) = bytes.split_at(std::mem::size_of::()); + let hdr: rtattr = hdr.try_into()?; + let aligned_len = aligned_by(hdr.rta_len.into(), 4); + debug_assert!(std::mem::size_of::() <= aligned_len); + (msg, _) = msg.split_at(aligned_len - std::mem::size_of::()); + Ok(Self { hdr, msg }) + } +} + +struct RtAttrs<'a>(&'a [u8]); + +impl<'a> Iterator for RtAttrs<'a> { + type Item = RtAttr<'a>; + + fn next(&mut self) -> Option { + if std::mem::size_of::() <= self.0.len() { + let attr = RtAttr::new(self.0).ok()?; + let aligned_len = aligned_by(attr.hdr.rta_len.into(), 4); + debug_assert!(self.0.len() >= aligned_len); + self.0 = self.0.split_at(aligned_len).1; + Some(attr) + } else { + None + } + } +} + +fn if_index(remote: IpAddr, fd: &mut RouteSocket) -> Result { + // Send RTM_GETROUTE message to get the interface index associated with the destination. + let msg_seq = RouteSocket::new_seq(); + let msg = IfIndexMsg::new(remote, msg_seq); + fd.write_all((&msg).into())?; + + // Receive RTM_GETROUTE response. + let (_hdr, mut buf) = read_msg_with_seq(fd, msg_seq, RTM_NEWROUTE)?; + debug_assert!(std::mem::size_of::() <= buf.len()); + let buf = buf.split_off(std::mem::size_of::()); + + // Parse through the attributes to find the interface index. + for attr in RtAttrs(buf.as_slice()).by_ref() { + if attr.hdr.rta_type == RTA_OIF { + // We have our interface index. + return parse_c_int(attr.msg); + } + } + Err(default_err()) +} + +#[repr(C)] +struct IfInfoMsg { + nlmsg: nlmsghdr, + ifim: ifinfomsg, +} + +impl IfInfoMsg { + fn new(if_index: i32, nlmsg_seq: u32) -> Self { + #[allow(clippy::cast_possible_truncation)] + // Structs lens are <= u8::MAX per `const_assert!`s above. + let nlmsg_len = (std::mem::size_of::() + std::mem::size_of::()) as u32; + Self { + nlmsg: nlmsghdr { + nlmsg_len, + nlmsg_type: RTM_GETLINK, + nlmsg_flags: NLM_F_REQUEST | NLM_F_ACK, + nlmsg_seq, + ..Default::default() + }, + ifim: ifinfomsg { + ifi_family: AF_UNSPEC, + ifi_type: ARPHRD_NONE, + ifi_index: if_index, + ..Default::default() + }, + } + } + + const fn len(&self) -> usize { + self.nlmsg.nlmsg_len as usize + } +} + +impl From<&IfInfoMsg> for &[u8] { + fn from(value: &IfInfoMsg) -> Self { + debug_assert!(value.len() >= std::mem::size_of::()); + unsafe { slice::from_raw_parts(ptr::from_ref(value).cast(), value.len()) } + } +} + +fn if_name_mtu(if_index: i32, fd: &mut RouteSocket) -> Result<(String, usize)> { + // Send RTM_GETLINK message to get interface information for the given interface index. + let msg_seq = RouteSocket::new_seq(); + let msg = IfInfoMsg::new(if_index, msg_seq); + fd.write_all((&msg).into())?; + + // Receive RTM_GETLINK response. + let (_hdr, mut buf) = read_msg_with_seq(fd, msg_seq, RTM_NEWLINK)?; + debug_assert!(std::mem::size_of::() <= buf.len()); + let buf = buf.split_off(std::mem::size_of::()); + + // Parse through the attributes to find the interface name and MTU. + let mut ifname = None; + let mut mtu = None; + for attr in RtAttrs(buf.as_slice()).by_ref() { + match attr.hdr.rta_type { + IFLA_IFNAME => { + let name = CStr::from_bytes_until_nul(attr.msg) + .map_err(|err| Error::new(ErrorKind::Other, err))?; + ifname = Some( + name.to_str() + .map_err(|err| Error::new(ErrorKind::Other, err))? + .to_string(), + ); + } + IFLA_MTU => { + mtu = Some( + parse_c_int(attr.msg)? + .try_into() + .map_err(|e: TryFromIntError| unlikely_err(e.to_string()))?, + ); + } + _ => (), + } + if let (Some(ifname), Some(mtu)) = (ifname.as_ref(), mtu.as_ref()) { + return Ok((ifname.clone(), *mtu)); + } + } + + Err(default_err()) +} + +pub fn interface_and_mtu_impl(remote: IpAddr) -> Result<(String, usize)> { + // Create a netlink socket. + let mut fd = RouteSocket::new(AF_NETLINK, NETLINK_ROUTE)?; + let if_index = if_index(remote, &mut fd)?; + if_name_mtu(if_index, &mut fd) +} diff --git a/third_party/rust/mtu/src/routesocket.rs b/third_party/rust/mtu/src/routesocket.rs new file mode 100644 index 000000000000..96d3a75d4226 --- /dev/null +++ b/third_party/rust/mtu/src/routesocket.rs @@ -0,0 +1,81 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{ + io::{Error, Read, Result, Write}, + num::TryFromIntError, + os::fd::{AsRawFd, FromRawFd as _, OwnedFd}, + sync::atomic::Ordering, +}; + +use libc::{fsync, read, socket, write, SOCK_RAW}; + +use crate::unlikely_err; + +#[cfg(any(target_os = "linux", target_os = "android"))] +type AtomicRouteSocketSeq = std::sync::atomic::AtomicU32; +#[cfg(any(target_os = "linux", target_os = "android"))] +type RouteSocketSeq = u32; + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +type AtomicRouteSocketSeq = std::sync::atomic::AtomicI32; +#[cfg(not(any(target_os = "linux", target_os = "android")))] +type RouteSocketSeq = i32; + +static SEQ: AtomicRouteSocketSeq = AtomicRouteSocketSeq::new(0); + +pub struct RouteSocket(OwnedFd); + +impl RouteSocket { + pub fn new(domain: libc::c_int, protocol: libc::c_int) -> Result { + let fd = unsafe { socket(domain, SOCK_RAW, protocol) }; + if fd == -1 { + return Err(Error::last_os_error()); + } + Ok(Self(unsafe { OwnedFd::from_raw_fd(fd) })) + } + + pub fn new_seq() -> RouteSocketSeq { + SEQ.fetch_add(1, Ordering::Relaxed) + } +} + +impl AsRawFd for RouteSocket { + fn as_raw_fd(&self) -> i32 { + self.0.as_raw_fd() + } +} + +fn check_result(res: isize) -> Result { + if res == -1 { + Err(Error::last_os_error()) + } else { + Ok(res + .try_into() + .map_err(|e: TryFromIntError| unlikely_err(e.to_string()))?) + } +} + +impl Write for RouteSocket { + fn write(&mut self, buf: &[u8]) -> Result { + let res = unsafe { write(self.as_raw_fd(), buf.as_ptr().cast(), buf.len()) }; + check_result(res) + } + + fn flush(&mut self) -> Result<()> { + let res = unsafe { fsync(self.as_raw_fd()) }; + check_result(res as isize).and(Ok(())) + } +} + +impl Read for RouteSocket { + fn read(&mut self, buf: &mut [u8]) -> Result { + // If we've written a well-formed message into the kernel via `write`, we should be able to + // read a well-formed message back out, and not block. + let res = unsafe { read(self.as_raw_fd(), buf.as_mut_ptr().cast(), buf.len()) }; + check_result(res) + } +} diff --git a/third_party/rust/mtu/src/windows.rs b/third_party/rust/mtu/src/windows.rs new file mode 100644 index 000000000000..cb28eda17c9a --- /dev/null +++ b/third_party/rust/mtu/src/windows.rs @@ -0,0 +1,143 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{ + ffi::CStr, + io::{Error, ErrorKind, Result}, + net::IpAddr, + ptr, slice, +}; + +use windows::Win32::{ + Foundation::NO_ERROR, + NetworkManagement::{ + IpHelper::{ + if_indextoname, FreeMibTable, GetBestInterfaceEx, GetIpInterfaceTable, + MIB_IPINTERFACE_ROW, MIB_IPINTERFACE_TABLE, + }, + Ndis::IF_MAX_STRING_SIZE, + }, + Networking::WinSock::{ + AF_INET, AF_INET6, IN6_ADDR, IN6_ADDR_0, IN_ADDR, IN_ADDR_0, SOCKADDR, SOCKADDR_IN, + SOCKADDR_IN6, SOCKADDR_INET, + }, +}; + +use crate::default_err; + +struct MibTablePtr(*mut MIB_IPINTERFACE_TABLE); + +impl MibTablePtr { + fn mut_ptr_ptr(&mut self) -> *mut *mut MIB_IPINTERFACE_TABLE { + ptr::from_mut(&mut self.0) + } +} + +impl Default for MibTablePtr { + fn default() -> Self { + Self(ptr::null_mut()) + } +} + +impl Drop for MibTablePtr { + fn drop(&mut self) { + if !self.0.is_null() { + // Free the memory allocated by GetIpInterfaceTable. + unsafe { + FreeMibTable(self.0.cast()); + } + } + } +} + +pub fn interface_and_mtu_impl(remote: IpAddr) -> Result<(String, usize)> { + // Convert remote to Windows SOCKADDR_INET format. The SOCKADDR_INET union contains an IPv4 or + // an IPv6 address. + // + // See https://learn.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-sockaddr_inet + let dst = match remote { + IpAddr::V4(ip) => { + // Initialize the `SOCKADDR_IN` variant of `SOCKADDR_INET` based on `ip`. + SOCKADDR_INET { + Ipv4: SOCKADDR_IN { + sin_family: AF_INET, + sin_addr: IN_ADDR { + S_un: IN_ADDR_0 { + S_addr: u32::to_be(ip.into()), + }, + }, + ..Default::default() + }, + } + } + IpAddr::V6(ip) => { + // Initialize the `SOCKADDR_IN6` variant of `SOCKADDR_INET` based on `ip`. + SOCKADDR_INET { + Ipv6: SOCKADDR_IN6 { + sin6_family: AF_INET6, + sin6_addr: IN6_ADDR { + u: IN6_ADDR_0 { Byte: ip.octets() }, + }, + ..Default::default() + }, + } + } + }; + + // Get the interface index of the best outbound interface towards `dst`. + let mut idx = 0; + let res = unsafe { + // We're now casting `&dst` to a `SOCKADDR` pointer. This is OK based on + // https://learn.microsoft.com/en-us/windows/win32/winsock/sockaddr-2. + // With that, we call `GetBestInterfaceEx` to get the interface index into `idx`. + // See https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getbestinterfaceex + GetBestInterfaceEx( + ptr::from_ref(&dst).cast::(), + ptr::from_mut(&mut idx), + ) + }; + if res != 0 { + return Err(Error::last_os_error()); + } + + // Get a list of all interfaces with associated metadata. + let mut if_table = MibTablePtr::default(); + // GetIpInterfaceTable allocates memory, which MibTablePtr::drop will free. + let family = if remote.is_ipv4() { AF_INET } else { AF_INET6 }; + if unsafe { GetIpInterfaceTable(family, if_table.mut_ptr_ptr()) } != NO_ERROR { + return Err(Error::last_os_error()); + } + // Make a slice + let ifaces = unsafe { + slice::from_raw_parts::( + &(*if_table.0).Table[0], + (*if_table.0).NumEntries as usize, + ) + }; + + // Find the local interface matching `idx`. + for iface in ifaces { + if iface.InterfaceIndex == idx { + // Get the MTU. + let mtu: usize = iface.NlMtu.try_into().map_err(|_| default_err())?; + // Get the interface name. + let mut interfacename = [0u8; IF_MAX_STRING_SIZE as usize]; + // if_indextoname writes into the provided buffer. + if unsafe { if_indextoname(iface.InterfaceIndex, &mut interfacename).is_null() } { + return Err(default_err()); + } + // Convert the interface name to a Rust string. + let name = CStr::from_bytes_until_nul(interfacename.as_ref()) + .map_err(|_| default_err())? + .to_str() + .map_err(|err| Error::new(ErrorKind::Other, err))? + .to_string(); + // We found our interface information. + return Ok((name, mtu)); + } + } + Err(default_err()) +} diff --git a/third_party/rust/neqo-bin/.cargo-checksum.json b/third_party/rust/neqo-bin/.cargo-checksum.json index d434dd564008..164a9f7fd196 100644 --- a/third_party/rust/neqo-bin/.cargo-checksum.json +++ b/third_party/rust/neqo-bin/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f45efe77b2a12f3c4b84a412b25a22ebac2cc97c5fd8df8a774f9757267986b6","benches/main.rs":"1f00060094b0f77ac83b2f0817560bb6198c95742a7bf9330258906f3a4f57fe","src/bin/client.rs":"db77efd75dc0745b6dd983ab8fa3bc8f5f9111967f0d90d23cb19140a940246d","src/bin/server.rs":"2f7ab3c7a98117bd162e6fd07abef1d21791d1bb240db3aae61afa6ff72df83a","src/client/http09.rs":"ac3526f3689dfe61ac336c90f936a2113a47b1112eb6e765d2112898f42ff38f","src/client/http3.rs":"40f6b94a31edceb911609a75929df67dcab87d6c88501b14adfca0e31dbb26c0","src/client/mod.rs":"c15859494d447cd777a0cce41bd7e36d9ffc7bbab494ed2f0c9eb7d058e3bdbe","src/lib.rs":"acbf69e2c99d2ca47d3356fad9b4d08acf4a2a9b481e27af2ccb46dc19cd50e6","src/send_data.rs":"7537b7a0f67e9077cf121cc3d0fcd42edb085801dd4baf25b14c22a01f1bf04f","src/server/http09.rs":"3dbde3e801532b6e83bb86eeea5d87ec91294bb43c05c956c3783a7722780a5e","src/server/http3.rs":"7f30864eb165cb614cd5bdbf4d59f736a2409316fe848e6295b8618099e5cbdd","src/server/mod.rs":"d42c2991f3a2854309785800f007b1dafd72232e1f6870a6e9cf60387202382b","src/udp.rs":"4aadb956e50f961241b2850e6f3bdf715ccbac943e3ab585f4b46e755d03d2de"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"30905a8b427891bbf7a6b46b846b49140d553f9dfd978f4e24aaaff43a0d50fa","benches/main.rs":"fcfd00665a1c4eb2118c74dd3e066e451bed655a42ae5c92daee38a31b69c2fb","src/bin/client.rs":"d7dc368d9b3a3a7a391fd982509ce66afa09ede9ca54dc1328bfc222e69379dc","src/bin/server.rs":"f297d7d00613291e5a058772c7e416b55ad8a25e6f0cf438c7b7f836fb470135","src/client/http09.rs":"86726bac98edbcab5a41ee5e4614637944730032fb31354cb68df917992da9bd","src/client/http3.rs":"820d359d83c6d6df1ce463cf2780b4541d0bd880338b8bf7840b6f01f14732ec","src/client/mod.rs":"3a8d426736c892a69acf543ab469540b631a43ab7c18e8f4e1f74aa0f56806e2","src/lib.rs":"68936ae531d5ab903b0063e3c8a7cd49511c2bf87c42706f23e8968e8a5c3d89","src/send_data.rs":"7537b7a0f67e9077cf121cc3d0fcd42edb085801dd4baf25b14c22a01f1bf04f","src/server/http09.rs":"d71cd79bba792799f303abdc15abe10e843bc0dd4de3efa27f3d11bf82798de2","src/server/http3.rs":"56f45922eebcfa30d7d9ceb6bac97d6f725d4c803c7aa0836c6e4d21b8d4588e","src/server/mod.rs":"6286666e692c43e52ddb3e837c9630694a446101c0c8cff520a816ce25c247df","src/udp.rs":"9fbd463a87c7a1f0873a003c36631b3b02af6e1a3d215b5a12a1e2822c207362"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-bin/Cargo.toml b/third_party/rust/neqo-bin/Cargo.toml index 267b01391e29..d794abe8b93f 100644 --- a/third_party/rust/neqo-bin/Cargo.toml +++ b/third_party/rust/neqo-bin/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "neqo-bin" -version = "0.11.0" +version = "0.12.2" authors = ["The Neqo Authors "] build = false autolib = false @@ -39,6 +39,9 @@ categories = [ license = "MIT OR Apache-2.0" repository = "https://github.com/mozilla/neqo/" +[package.metadata.cargo-machete] +ignored = ["log"] + [lib] name = "neqo_bin" path = "src/lib.rs" @@ -112,7 +115,10 @@ default-features = false [dependencies.quinn-udp] version = "0.5.6" -features = ["direct-log"] +features = [ + "direct-log", + "fast-apple-datapath", +] default-features = false [dependencies.regex] @@ -141,16 +147,48 @@ version = "0.5" features = ["async_tokio"] default-features = false +[dev-dependencies.neqo-bin] +path = "." +features = ["draft-29"] + +[dev-dependencies.neqo-http3] +path = "./../neqo-http3" +features = ["draft-29"] + +[dev-dependencies.neqo-transport] +path = "./../neqo-transport" +features = ["draft-29"] + [dev-dependencies.tokio] version = "1" features = ["sync"] default-features = false [features] -bench = ["neqo-transport/bench"] +bench = [ + "neqo-bin/bench", + "neqo-http3/bench", + "neqo-transport/bench", +] +draft-29 = [] [lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" [lints.clippy.cargo] level = "warn" @@ -163,3 +201,19 @@ priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/neqo-bin/benches/main.rs b/third_party/rust/neqo-bin/benches/main.rs index dbdb437709de..b2ef09873992 100644 --- a/third_party/rust/neqo-bin/benches/main.rs +++ b/third_party/rust/neqo-bin/benches/main.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{env, path::PathBuf, str::FromStr}; +use std::{env, path::PathBuf, str::FromStr as _}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; use neqo_bin::{client, server}; @@ -17,7 +17,6 @@ struct Benchmark { } fn transfer(c: &mut Criterion) { - neqo_common::log::init(Some(log::LevelFilter::Off)); neqo_crypto::init_db(PathBuf::from_str("../test-fixture/db").unwrap()).unwrap(); let done_sender = spawn_server(); diff --git a/third_party/rust/neqo-bin/src/bin/client.rs b/third_party/rust/neqo-bin/src/bin/client.rs index 25c0e8753f40..51ecab6a7713 100644 --- a/third_party/rust/neqo-bin/src/bin/client.rs +++ b/third_party/rust/neqo-bin/src/bin/client.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use clap::Parser; +use clap::Parser as _; #[tokio::main] async fn main() -> Result<(), neqo_bin::client::Error> { diff --git a/third_party/rust/neqo-bin/src/bin/server.rs b/third_party/rust/neqo-bin/src/bin/server.rs index e9b30261e4de..022a950f2f7a 100644 --- a/third_party/rust/neqo-bin/src/bin/server.rs +++ b/third_party/rust/neqo-bin/src/bin/server.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use clap::Parser; +use clap::Parser as _; #[tokio::main] async fn main() -> Result<(), neqo_bin::server::Error> { diff --git a/third_party/rust/neqo-bin/src/client/http09.rs b/third_party/rust/neqo-bin/src/client/http09.rs index f7f62bf57a21..21b0cf2883ba 100644 --- a/third_party/rust/neqo-bin/src/client/http09.rs +++ b/third_party/rust/neqo-bin/src/client/http09.rs @@ -10,7 +10,7 @@ use std::{ cell::RefCell, collections::{HashMap, VecDeque}, fs::File, - io::{BufWriter, Write}, + io::{BufWriter, Write as _}, net::SocketAddr, path::PathBuf, rc::Rc, @@ -61,7 +61,7 @@ impl super::Handler for Handler<'_> { self.needs_key_update = false; self.download_urls(client); } - Err(neqo_transport::Error::KeyUpdateBlocked) => (), + Err(Error::KeyUpdateBlocked) => (), Err(e) => return Err(e.into()), } } @@ -213,7 +213,7 @@ impl super::Client for Connection { } fn has_events(&self) -> bool { - neqo_common::event::Provider::has_events(self) + Provider::has_events(self) } } @@ -301,8 +301,7 @@ impl<'b> Handler<'b> { qdebug!("READ[{stream_id}]: {} bytes", read_buffer.len()); } else { qdebug!( - "READ[{}]: {}", - stream_id, + "READ[{stream_id}]: {}", std::str::from_utf8(read_buffer).unwrap() ); } diff --git a/third_party/rust/neqo-bin/src/client/http3.rs b/third_party/rust/neqo-bin/src/client/http3.rs index 3a5a777cb65d..ac4b22dba152 100644 --- a/third_party/rust/neqo-bin/src/client/http3.rs +++ b/third_party/rust/neqo-bin/src/client/http3.rs @@ -11,7 +11,7 @@ use std::{ collections::{HashMap, VecDeque}, fmt::Display, fs::File, - io::{BufWriter, Write}, + io::{BufWriter, Write as _}, net::SocketAddr, path::PathBuf, rc::Rc, @@ -155,7 +155,7 @@ impl super::Client for Http3Client { } fn has_events(&self) -> bool { - neqo_common::event::Provider::has_events(self) + Provider::has_events(self) } } @@ -302,7 +302,7 @@ impl StreamHandler for DownloadStreamHandler { } else if let Ok(txt) = std::str::from_utf8(data) { qdebug!("READ[{stream_id}]: {txt}"); } else { - qdebug!("READ[{}]: 0x{}", stream_id, hex(data)); + qdebug!("READ[{stream_id}]: 0x{}", hex(data)); } if fin { @@ -344,7 +344,7 @@ impl StreamHandler for UploadStreamHandler { qinfo!("Stream ID: {stream_id:?}, Upload time: {upload_time:?}"); } } else { - panic!("Unexpected data [{}]: 0x{}", stream_id, hex(data)); + panic!("Unexpected data [{stream_id}]: 0x{}", hex(data)); } Ok(true) } diff --git a/third_party/rust/neqo-bin/src/client/mod.rs b/third_party/rust/neqo-bin/src/client/mod.rs index 35463cad3168..9da2800d8077 100644 --- a/third_party/rust/neqo-bin/src/client/mod.rs +++ b/third_party/rust/neqo-bin/src/client/mod.rs @@ -11,7 +11,7 @@ use std::{ fmt::{self, Display}, fs::{create_dir_all, File, OpenOptions}, io::{self, BufWriter}, - net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs as _}, path::PathBuf, pin::Pin, process::exit, @@ -21,7 +21,7 @@ use std::{ use clap::Parser; use futures::{ future::{select, Either}, - FutureExt, TryFutureExt, + FutureExt as _, TryFutureExt as _, }; use neqo_common::{qdebug, qerror, qinfo, qlog::NeqoQlog, qwarn, Datagram, Role}; use neqo_crypto::{ @@ -30,6 +30,7 @@ use neqo_crypto::{ }; use neqo_http3::Output; use neqo_transport::{AppError, CloseReason, ConnectionId, Version}; +use neqo_udp::RecvBuf; use tokio::time::Sleep; use url::{Host, Origin, Url}; @@ -47,7 +48,7 @@ pub enum Error { IoError(io::Error), QlogError(qlog::Error), TransportError(neqo_transport::Error), - ApplicationError(neqo_transport::AppError), + ApplicationError(AppError), CryptoError(neqo_crypto::Error), } @@ -81,8 +82,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: neqo_transport::CloseReason) -> Self { +impl From for Error { + fn from(err: CloseReason) -> Self { match err { CloseReason::Transport(e) => Self::TransportError(e), CloseReason::Application(e) => Self::ApplicationError(e), @@ -181,9 +182,9 @@ impl Args { #[cfg(any(test, feature = "bench"))] #[allow(clippy::missing_panics_doc)] pub fn new(requests: &[usize], upload: bool) -> Self { - use std::str::FromStr; + use std::str::FromStr as _; Self { - shared: crate::SharedArgs::default(), + shared: SharedArgs::default(), urls: requests .iter() .map(|r| Url::from_str(&format!("http://[::1]:12345/{r}")).unwrap()) @@ -238,10 +239,14 @@ impl Args { // Only use v1 for most QNS tests. self.shared.quic_parameters.quic_version = vec![Version::Version1]; // This is the default for all tests except http3. - self.shared.use_old_http = true; + self.shared.alpn = String::from("hq-interop"); + // Wireshark can't reassemble sliced CRYPTO frames, which causes tests to fail. + // So let's turn that off by default, and only enable for some known-good QNS tests. + self.shared.quic_parameters.no_sni_slicing = true; match testcase.as_str() { "http3" => { - self.shared.use_old_http = false; + self.shared.quic_parameters.no_sni_slicing = false; + self.shared.alpn = String::from("h3"); if let Some(testcase) = &self.test { if testcase.as_str() != "upload" { qerror!("Unsupported test case: {testcase}"); @@ -264,6 +269,7 @@ impl Args { qerror!("Warning: zerortt test won't work without >1 URL"); exit(127); } + self.shared.quic_parameters.no_sni_slicing = false; self.resume = true; // PMTUD probes inflate what we sent in 1-RTT, causing QNS to fail the test. self.shared.quic_parameters.no_pmtud = true; @@ -284,6 +290,7 @@ impl Args { self.key_update = true; } "v2" => { + self.shared.quic_parameters.no_sni_slicing = false; // Use default version set for this test (which allows compatible vneg.) self.shared.quic_parameters.quic_version.clear(); } @@ -394,7 +401,7 @@ struct Runner<'a, H: Handler> { handler: H, timeout: Option>>, args: &'a Args, - recv_buf: Vec, + recv_buf: RecvBuf, } impl<'a, H: Handler> Runner<'a, H> { @@ -412,7 +419,7 @@ impl<'a, H: Handler> Runner<'a, H> { handler, args, timeout: None, - recv_buf: vec![0; neqo_udp::RECV_BUF_SIZE], + recv_buf: RecvBuf::new(), } } @@ -462,7 +469,7 @@ impl<'a, H: Handler> Runner<'a, H> { self.socket.send(&dgram)?; } Output::Callback(new_timeout) => { - qdebug!("Setting timeout of {:?}", new_timeout); + qdebug!("Setting timeout of {new_timeout:?}"); self.timeout = Some(Box::pin(tokio::time::sleep(new_timeout))); break; } @@ -481,9 +488,6 @@ impl<'a, H: Handler> Runner<'a, H> { let Some(dgrams) = self.socket.recv(self.local_addr, &mut self.recv_buf)? else { break; }; - if dgrams.len() == 0 { - break; - } self.client.process_multiple_input(dgrams, Instant::now()); self.process_output().await?; } @@ -508,9 +512,9 @@ fn qlog_new(args: &Args, hostname: &str, cid: &ConnectionId) -> Res { NeqoQlog::enabled_with_file( qlog_dir, Role::Client, - Some("Example qlog".to_string()), - Some("Example qlog description".to_string()), - format!("{hostname}-{cid}"), + Some("Neqo client qlog".to_string()), + Some("Neqo client qlog".to_string()), + format!("client-{hostname}-{cid}"), ) .map_err(Error::QlogError) } @@ -553,7 +557,7 @@ pub async fn client(mut args: Args) -> Res<()> { for ((host, port), mut urls) in urls_by_origin(&args.urls) { if args.resume && urls.len() < 2 { - qerror!("Resumption to {host} cannot work without at least 2 URLs."); + qerror!("Resumption to {host} cannot work without at least 2 URLs"); exit(127); } @@ -570,10 +574,8 @@ pub async fn client(mut args: Args) -> Res<()> { let mut socket = crate::udp::Socket::bind(local_addr_for(&remote_addr, 0))?; let real_local = socket.local_addr().unwrap(); qinfo!( - "{} Client connecting: {:?} -> {:?}", - if args.shared.use_old_http { "H9" } else { "H3" }, - real_local, - remote_addr, + "{} Client connecting: {real_local:?} -> {remote_addr:?}", + args.shared.alpn ); let hostname = format!("{host}"); @@ -588,21 +590,21 @@ pub async fn client(mut args: Args) -> Res<()> { first = false; - token = if args.shared.use_old_http { - let client = - http09::create_client(&args, real_local, remote_addr, &hostname, token) - .expect("failed to create client"); + token = if args.shared.alpn == "h3" { + let client = http3::create_client(&args, real_local, remote_addr, &hostname, token) + .expect("failed to create client"); - let handler = http09::Handler::new(to_request, &args); + let handler = http3::Handler::new(to_request, &args); Runner::new(real_local, &mut socket, client, handler, &args) .run() .await? } else { - let client = http3::create_client(&args, real_local, remote_addr, &hostname, token) - .expect("failed to create client"); + let client = + http09::create_client(&args, real_local, remote_addr, &hostname, token) + .expect("failed to create client"); - let handler = http3::Handler::new(to_request, &args); + let handler = http09::Handler::new(to_request, &args); Runner::new(real_local, &mut socket, client, handler, &args) .run() diff --git a/third_party/rust/neqo-bin/src/lib.rs b/third_party/rust/neqo-bin/src/lib.rs index 8ab352287a5a..1e25f8690f2f 100644 --- a/third_party/rust/neqo-bin/src/lib.rs +++ b/third_party/rust/neqo-bin/src/lib.rs @@ -9,7 +9,7 @@ use std::{ fmt::{self, Display}, - net::{SocketAddr, ToSocketAddrs}, + net::{SocketAddr, ToSocketAddrs as _}, path::PathBuf, time::Duration, }; @@ -63,10 +63,6 @@ pub struct SharedArgs { /// Enable special behavior for use with QUIC Network Simulator pub qns_test: Option, - #[arg(name = "use-old-http", short = 'o', long)] - /// Use http 0.9 instead of HTTP/3 - pub use_old_http: bool, - #[command(flatten)] pub quic_parameters: QuicParameters, } @@ -83,7 +79,6 @@ impl Default for SharedArgs { max_blocked_streams: 10, ciphers: vec![], qns_test: None, - use_old_http: false, quic_parameters: QuicParameters::default(), } } @@ -117,7 +112,7 @@ pub struct QuicParameters { /// The idle timeout for connections, in seconds. pub idle_timeout: u64, - #[arg(long = "cc", default_value = "newreno")] + #[arg(long = "cc", default_value = "cubic")] /// The congestion controller to use. pub congestion_control: CongestionControlAlgorithm, @@ -129,6 +124,10 @@ pub struct QuicParameters { /// Whether to disable path MTU discovery. pub no_pmtud: bool, + #[arg(long)] + /// Whether to slice the SNI. + pub no_sni_slicing: bool, + #[arg(name = "preferred-address-v4", long)] /// An IPv4 address for the server preferred address. pub preferred_address_v4: Option, @@ -146,11 +145,12 @@ impl Default for QuicParameters { max_streams_bidi: 16, max_streams_uni: 16, idle_timeout: 30, - congestion_control: CongestionControlAlgorithm::NewReno, + congestion_control: CongestionControlAlgorithm::Cubic, no_pacing: false, no_pmtud: false, preferred_address_v4: None, preferred_address_v6: None, + no_sni_slicing: false, } } } @@ -168,9 +168,8 @@ impl QuicParameters { assert_eq!( opt.is_some(), addr.is_some(), - "unable to resolve '{}' to an {} address", + "unable to resolve '{}' to an {v} address", opt.as_ref().unwrap(), - v, ); addr } @@ -224,7 +223,8 @@ impl QuicParameters { .idle_timeout(Duration::from_secs(self.idle_timeout)) .cc_algorithm(self.congestion_control) .pacing(!self.no_pacing) - .pmtud(!self.no_pmtud); + .pmtud(!self.no_pmtud) + .sni_slicing(!self.no_sni_slicing); params = if let Some(pa) = self.preferred_address() { params.preferred_address(pa) } else { @@ -240,10 +240,8 @@ impl QuicParameters { } else { let version = match alpn { "h3" | "hq-interop" => Version::Version1, + #[cfg(feature = "draft-29")] "h3-29" | "hq-29" => Version::Draft29, - "h3-30" | "hq-30" => Version::Draft30, - "h3-31" | "hq-31" => Version::Draft31, - "h3-32" | "hq-32" => Version::Draft32, _ => Version::default(), }; params.versions(version, Version::all()) @@ -273,7 +271,7 @@ impl std::error::Error for Error {} #[cfg(test)] mod tests { - use std::{fs, path::PathBuf, str::FromStr, time::SystemTime}; + use std::{fs, path::PathBuf, str::FromStr as _, time::SystemTime}; use crate::{client, server}; @@ -283,15 +281,14 @@ mod tests { impl TempDir { fn new() -> Self { - let mut dir = std::env::temp_dir(); - dir.push(format!( + let dir = std::env::temp_dir().join(format!( "neqo-bin-test-{}", SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs() )); - fs::create_dir(&dir).unwrap(); + fs::create_dir_all(&dir).unwrap(); Self { path: dir } } diff --git a/third_party/rust/neqo-bin/src/server/http09.rs b/third_party/rust/neqo-bin/src/server/http09.rs index e183a1b04541..7c4fb792db8b 100644 --- a/third_party/rust/neqo-bin/src/server/http09.rs +++ b/third_party/rust/neqo-bin/src/server/http09.rs @@ -6,7 +6,7 @@ use std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt::Display, rc::Rc, time::Instant}; -use neqo_common::{event::Provider, hex, qdebug, qerror, qinfo, qwarn, Datagram}; +use neqo_common::{event::Provider as _, hex, qdebug, qerror, qinfo, qwarn, Datagram}; use neqo_crypto::{generate_ech_keys, random, AllowZeroRtt, AntiReplay}; use neqo_http3::Error; use neqo_transport::{ @@ -82,17 +82,17 @@ impl HttpServer { let url_dbg = String::from_utf8(partial.clone()) .unwrap_or_else(|_| format!("", hex(&partial))); if partial.len() < 4096 { - qdebug!("Saving partial URL: {}", url_dbg); + qdebug!("Saving partial URL: {url_dbg}"); self.read_state.insert(stream_id, partial); } else { - qdebug!("Giving up on partial URL {}", url_dbg); + qdebug!("Giving up on partial URL {url_dbg}"); conn.borrow_mut().stream_stop_sending(stream_id, 0).unwrap(); } } fn stream_readable(&mut self, stream_id: StreamId, conn: &ConnectionRef) { if !stream_id.is_client_initiated() || !stream_id.is_bidi() { - qdebug!("Stream {} not client-initiated bidi, ignoring", stream_id); + qdebug!("Stream {stream_id} not client-initiated bidi, ignoring"); return; } let (sz, fin) = conn diff --git a/third_party/rust/neqo-bin/src/server/http3.rs b/third_party/rust/neqo-bin/src/server/http3.rs index 1d1d7a1cf854..c22b95c6fd5a 100644 --- a/third_party/rust/neqo-bin/src/server/http3.rs +++ b/third_party/rust/neqo-bin/src/server/http3.rs @@ -12,7 +12,7 @@ use std::{ time::Instant, }; -use neqo_common::{hex, qdebug, qerror, qinfo, Datagram, Header}; +use neqo_common::{header::HeadersExt as _, hex, qdebug, qerror, qinfo, Datagram, Header}; use neqo_crypto::{generate_ech_keys, random, AntiReplay}; use neqo_http3::{ Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent, StreamId, @@ -94,15 +94,12 @@ impl super::HttpServer for HttpServer { } => { qdebug!("Headers (request={stream} fin={fin}): {headers:?}"); - if headers - .iter() - .any(|h| h.name() == ":method" && h.value() == "POST") - { + if headers.contains_header(":method", "POST") { self.posts.insert(stream, 0); continue; } - let Some(path) = headers.iter().find(|&h| h.name() == ":path") else { + let Some(path) = headers.find_header(":path") else { stream .cancel_fetch(neqo_http3::Error::HttpRequestIncomplete.code()) .unwrap(); diff --git a/third_party/rust/neqo-bin/src/server/mod.rs b/third_party/rust/neqo-bin/src/server/mod.rs index 3c12691a242e..2d8db660eb3f 100644 --- a/third_party/rust/neqo-bin/src/server/mod.rs +++ b/third_party/rust/neqo-bin/src/server/mod.rs @@ -10,7 +10,7 @@ use std::{ cell::RefCell, fmt::{self, Display}, fs, io, - net::{SocketAddr, ToSocketAddrs}, + net::{SocketAddr, ToSocketAddrs as _}, path::PathBuf, pin::Pin, process::exit, @@ -21,7 +21,7 @@ use std::{ use clap::Parser; use futures::{ future::{select, select_all, Either}, - FutureExt, + FutureExt as _, }; use neqo_common::{qdebug, qerror, qinfo, qwarn, Datagram}; use neqo_crypto::{ @@ -29,6 +29,7 @@ use neqo_crypto::{ init_db, AntiReplay, Cipher, }; use neqo_transport::{Output, RandomConnectionIdGenerator, Version}; +use neqo_udp::RecvBuf; use tokio::time::Sleep; use crate::SharedArgs; @@ -121,9 +122,9 @@ pub struct Args { #[cfg(any(test, feature = "bench"))] impl Default for Args { fn default() -> Self { - use std::str::FromStr; + use std::str::FromStr as _; Self { - shared: crate::SharedArgs::default(), + shared: SharedArgs::default(), hosts: vec!["[::]:12345".to_string()], db: PathBuf::from_str("../test-fixture/db").unwrap(), key: "key".to_string(), @@ -202,7 +203,7 @@ pub struct ServerRunner { server: Box, timeout: Option>>, sockets: Vec<(SocketAddr, crate::udp::Socket)>, - recv_buf: Vec, + recv_buf: RecvBuf, } impl ServerRunner { @@ -217,7 +218,7 @@ impl ServerRunner { server, timeout: None, sockets, - recv_buf: vec![0; neqo_udp::RECV_BUF_SIZE], + recv_buf: RecvBuf::new(), } } @@ -251,7 +252,7 @@ impl ServerRunner { socket.send(&dgram)?; } Output::Callback(new_timeout) => { - qdebug!("Setting timeout of {:?}", new_timeout); + qdebug!("Setting timeout of {new_timeout:?}"); *timeout = Some(Box::pin(tokio::time::sleep(new_timeout))); break; } @@ -263,7 +264,7 @@ impl ServerRunner { async fn read_and_process(&mut self, sockets_index: usize) -> Result<(), io::Error> { loop { - let (host, socket) = self.sockets.get_mut(sockets_index).unwrap(); + let (host, socket) = &mut self.sockets[sockets_index]; let Some(input_dgrams) = socket.recv(*host, &mut self.recv_buf)? else { break; }; @@ -341,8 +342,6 @@ enum Ready { } pub async fn server(mut args: Args) -> Res<()> { - const HQ_INTEROP: &str = "hq-interop"; - neqo_common::log::init( args.shared .verbose @@ -362,17 +361,15 @@ pub async fn server(mut args: Args) -> Res<()> { args.shared.quic_parameters.quic_version = vec![Version::Version1]; } } else { - qwarn!("Both -V and --qns-test were set. Ignoring testcase specific versions."); + qwarn!("Both -V and --qns-test were set. Ignoring testcase specific versions"); } // These are the default for all tests except http3. - args.shared.use_old_http = true; - args.shared.alpn = String::from(HQ_INTEROP); + args.shared.alpn = String::from("hq-interop"); // TODO: More options to deduplicate with client? match testcase.as_str() { "http3" => { - args.shared.use_old_http = false; - args.shared.alpn = "h3".into(); + args.shared.alpn = String::from("h3"); } "zerortt" => args.shared.quic_parameters.max_streams_bidi = 100, "handshake" | "transfer" | "resumption" | "multiconnect" | "v2" | "ecn" => {} @@ -396,7 +393,7 @@ pub async fn server(mut args: Args) -> Res<()> { let hosts = args.listen_addresses(); if hosts.is_empty() { qerror!("No valid hosts defined"); - Err(io::Error::new(io::ErrorKind::InvalidInput, "No hosts"))?; + return Err(io::Error::new(io::ErrorKind::InvalidInput, "No hosts").into()); } let sockets = hosts .into_iter() @@ -414,12 +411,12 @@ pub async fn server(mut args: Args) -> Res<()> { .expect("unable to setup anti-replay"); let cid_mgr = Rc::new(RefCell::new(RandomConnectionIdGenerator::new(10))); - let server: Box = if args.shared.use_old_http { + let server: Box = if args.shared.alpn == "h3" { + Box::new(http3::HttpServer::new(&args, anti_replay, cid_mgr)) + } else { Box::new( http09::HttpServer::new(&args, anti_replay, cid_mgr).expect("We cannot make a server!"), ) - } else { - Box::new(http3::HttpServer::new(&args, anti_replay, cid_mgr)) }; ServerRunner::new(Box::new(move || args.now()), server, sockets) diff --git a/third_party/rust/neqo-bin/src/udp.rs b/third_party/rust/neqo-bin/src/udp.rs index 8bc78c2665d2..bd8d0eef8567 100644 --- a/third_party/rust/neqo-bin/src/udp.rs +++ b/third_party/rust/neqo-bin/src/udp.rs @@ -7,7 +7,7 @@ use std::{io, net::SocketAddr}; use neqo_common::Datagram; -use neqo_udp::DatagramIter; +use neqo_udp::{DatagramIter, RecvBuf}; /// Ideally this would live in [`neqo-udp`]. [`neqo-udp`] is used in Firefox. /// @@ -59,7 +59,7 @@ impl Socket { pub fn recv<'a>( &self, local_address: SocketAddr, - recv_buf: &'a mut [u8], + recv_buf: &'a mut RecvBuf, ) -> Result>, io::Error> { self.inner .try_io(tokio::io::Interest::READABLE, || { diff --git a/third_party/rust/neqo-common/.cargo-checksum.json b/third_party/rust/neqo-common/.cargo-checksum.json index 3e9be7bf3773..ac273bfe710e 100644 --- a/third_party/rust/neqo-common/.cargo-checksum.json +++ b/third_party/rust/neqo-common/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d7f253814c9d1e8fcae6916ca37c18efafd511895d85b6b193b4cc648a1b3fca","build.rs":"ee5dc521f3d8e18c2b617192d6b6e678f7f2f9886fdd34c0c1c5ef841419b248","src/codec.rs":"6c12d9db7066497f2566e83efc825ae984d04a6b5176010c93d394904103aeed","src/datagram.rs":"e8bf176d3b120028731388c17344d03b8195e5fd70f4d03e37144ac5ae5951f5","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"1ca74a34bdc97fedecf8a63c4a13cc487d1b2212398fb76f67792c822002138d","src/header.rs":"480a7848466249a78acddbf0bc0b4a096189abc14a89ad1a0943be571add2c2b","src/hrtime.rs":"37447c51c7fd84baad31bc420bf9170c1f4e71356bb6d102bd5651ddf69a2f89","src/incrdecoder.rs":"5c45034e61e75c76d2bca8b075c3e7a3cdd8af8c82b67c76283a2b08ab11846b","src/lib.rs":"2381fc00127a7eaf2265c3a13dc1e1d5843e048f3a8a1c97f1e6621c038de380","src/log.rs":"6ed99e15707c4256ae793011ed2f4b33aa81fed70205aaf5f8d3cd11ad451cf0","src/qlog.rs":"c230d1e3b6f80489253dc689eab44c9df75ef0c5170ab91ddd2dc9e4dc9234a2","src/tos.rs":"28fd9acfce06f68ac6691efd2609618850182f77ef3717ce2db07bfac19a9396","tests/log.rs":"a11e21fb570258ca93bb40e3923817d381e1e605accbc3aed1df5a0a9918b41d"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"40a22ca3fd5fd76384120c87a895e923701d78d4b1ec30481f80afff82cbf3f6","benches/decoder.rs":"e7fab506974d7b6b4f41fe51036151b15f0d693b7e45b80cf9e2141bb1f6298f","build.rs":"ee5dc521f3d8e18c2b617192d6b6e678f7f2f9886fdd34c0c1c5ef841419b248","src/codec.rs":"8aea4a5041d1b06e4928d29fefcc8166d515b72f9a744e572d3c92b90e9ea268","src/datagram.rs":"e8bf176d3b120028731388c17344d03b8195e5fd70f4d03e37144ac5ae5951f5","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"9e0f2dca1832ef49b93b214e8d5f1ca2f5f8cb84a856fead344f62a722c370db","src/header.rs":"a316f48735375da268142ad9ac3430d240162c9df67114546f4a094c25a10024","src/hrtime.rs":"754f90ae3f3839e59ccaa34a9f07a2742ec7080f2df539f4b7691c7771dd4856","src/incrdecoder.rs":"2128bb6aa737932b484cdff8213efe8eac46004ef2d9219b6f48ac4d664297ac","src/lib.rs":"002f6a740464b618036e699db4ebea1fc803b9c9c154c0478f6f8721932f4300","src/log.rs":"2ea3f00b1776e085cbf6b46dc7489259b4e58a2dada7edaf94e746de3defb222","src/qlog.rs":"f335b4f4340ae0bfaeb6742bd5a2cb8b6f16292a40b410ed3f72ce309b171106","src/tos.rs":"206410cf0d164a0c1a1c3de19ddcd224e311601707bedc7af100a30a950d12f9","tests/log.rs":"671a963f938599b76c0678f3931592e1782765ed4ea13e6cbfec2ab97c36e2c9"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-common/Cargo.toml b/third_party/rust/neqo-common/Cargo.toml index af8eabf0dcff..1b6604fbc721 100644 --- a/third_party/rust/neqo-common/Cargo.toml +++ b/third_party/rust/neqo-common/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "neqo-common" -version = "0.11.0" +version = "0.12.2" authors = ["The Neqo Authors "] build = "build.rs" autolib = false @@ -48,6 +48,12 @@ bench = false name = "log" path = "tests/log.rs" +[[bench]] +name = "decoder" +path = "benches/decoder.rs" +harness = false +required-features = ["bench"] + [dependencies.enum-map] version = "2.7" default-features = false @@ -70,6 +76,13 @@ default-features = false version = "0.13" default-features = false +[dev-dependencies.criterion] +version = "0.5" +default-features = false + +[dev-dependencies.neqo-crypto] +path = "../neqo-crypto" + [dev-dependencies.regex] version = "1.9" features = ["unicode-perl"] @@ -79,8 +92,13 @@ default-features = false path = "../test-fixture" [features] +bench = [ + "neqo-crypto/bench", + "test-fixture/bench", +] build-fuzzing-corpus = ["hex"] ci = [] +test-fixture = [] [target."cfg(windows)".dependencies.windows] version = "0.58" @@ -88,7 +106,22 @@ features = ["Win32_Media"] default-features = false [lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" [lints.clippy.cargo] level = "warn" @@ -101,3 +134,19 @@ priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/neqo-common/benches/decoder.rs b/third_party/rust/neqo-common/benches/decoder.rs new file mode 100644 index 000000000000..e15b1bec647e --- /dev/null +++ b/third_party/rust/neqo-common/benches/decoder.rs @@ -0,0 +1,52 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use neqo_common::Decoder; +use neqo_crypto::{init, randomize}; + +fn randomize_buffer(n: usize, mask: u8) -> Vec { + let mut buf = vec![0; n]; + // NSS doesn't like randomizing larger buffers, so chunk them up. + // https://searchfox.org/nss/rev/968939484921b0ceecca189cd1b66e97950c39da/lib/freebl/drbg.c#29 + for chunk in buf.chunks_mut(0x10000) { + randomize(chunk); + } + // Masking the top bits off causes the resulting values to be interpreted as + // smaller varints, which stresses the decoder differently. + // This is worth testing because most varints contain small values. + for x in &mut buf[..] { + *x &= mask; + } + buf +} + +fn decoder(c: &mut Criterion, count: usize, mask: u8) { + c.bench_function(&format!("decode {count} bytes, mask {mask:x}"), |b| { + b.iter_batched_ref( + || randomize_buffer(count, mask), + |buf| { + let mut dec = Decoder::new(&buf[..]); + while black_box(dec.decode_varint()).is_some() { + // Do nothing; + } + }, + criterion::BatchSize::SmallInput, + ); + }); +} + +fn benchmark_decoder(c: &mut Criterion) { + init().unwrap(); + for mask in [0xff, 0x7f, 0x3f] { + for exponent in [12, 20] { + decoder(c, 1 << exponent, mask); + } + } +} + +criterion_group!(benches, benchmark_decoder); +criterion_main!(benches); diff --git a/third_party/rust/neqo-common/src/codec.rs b/third_party/rust/neqo-common/src/codec.rs index afeb095781cb..f772c5949b38 100644 --- a/third_party/rust/neqo-common/src/codec.rs +++ b/third_party/rust/neqo-common/src/codec.rs @@ -44,34 +44,28 @@ impl<'a> Decoder<'a> { } /// Skip helper that panics if `n` is `None` or not able to fit in `usize`. + /// Only use this for tests because we panic rather than reporting a result. + #[cfg(any(test, feature = "test-fixture"))] fn skip_inner(&mut self, n: Option) { self.skip(usize::try_from(n.expect("invalid length")).unwrap()); } /// Skip a vector. Panics if there isn't enough space. /// Only use this for tests because we panic rather than reporting a result. + #[cfg(any(test, feature = "test-fixture"))] pub fn skip_vec(&mut self, n: usize) { - let len = self.decode_uint(n); + let len = self.decode_n(n); self.skip_inner(len); } /// Skip a variable length vector. Panics if there isn't enough space. /// Only use this for tests because we panic rather than reporting a result. + #[cfg(any(test, feature = "test-fixture"))] pub fn skip_vvec(&mut self) { let len = self.decode_varint(); self.skip_inner(len); } - /// Decodes (reads) a single byte. - pub fn decode_byte(&mut self) -> Option { - if self.remaining() < 1 { - return None; - } - let b = self.buf[self.offset]; - self.offset += 1; - Some(b) - } - /// Provides the next byte without moving the read position. #[must_use] pub const fn peek_byte(&self) -> Option { @@ -92,33 +86,43 @@ impl<'a> Decoder<'a> { Some(res) } - /// Decodes an unsigned integer of length 1..=8. - /// - /// # Panics - /// - /// This panics if `n` is not in the range `1..=8`. - pub fn decode_uint(&mut self, n: usize) -> Option { - assert!(n > 0 && n <= 8); + #[inline] + pub(crate) fn decode_n(&mut self, n: usize) -> Option { + debug_assert!(n > 0 && n <= 8); if self.remaining() < n { return None; } - let mut v = 0_u64; - for i in 0..n { - let b = self.buf[self.offset + i]; - v = v << 8 | u64::from(b); - } - self.offset += n; - Some(v) + Some(if n == 1 { + let v = u64::from(self.buf[self.offset]); + self.offset += 1; + v + } else { + let mut buf = [0; 8]; + buf[8 - n..].copy_from_slice(&self.buf[self.offset..self.offset + n]); + self.offset += n; + u64::from_be_bytes(buf) + }) + } + + /// Decodes a big-endian, unsigned integer value into the target type. + /// This returns `None` if there is not enough data remaining + /// or if the conversion to the identified type fails. + /// Conversion is via `u64`, so failures are impossible for + /// unsigned integer types: `u8`, `u16`, `u32`, or `u64`. + /// Signed types will fail if the high bit is set. + pub fn decode_uint>(&mut self) -> Option { + let v = self.decode_n(std::mem::size_of::()); + v.and_then(|v| T::try_from(v).ok()) } /// Decodes a QUIC varint. pub fn decode_varint(&mut self) -> Option { - let b1 = self.decode_byte()?; + let b1 = self.decode_n(1)?; match b1 >> 6 { - 0 => Some(u64::from(b1 & 0x3f)), - 1 => Some((u64::from(b1 & 0x3f) << 8) | self.decode_uint(1)?), - 2 => Some((u64::from(b1 & 0x3f) << 24) | self.decode_uint(3)?), - 3 => Some((u64::from(b1 & 0x3f) << 56) | self.decode_uint(7)?), + 0 => Some(b1), + 1 => Some(((b1 & 0x3f) << 8) | self.decode_n(1)?), + 2 => Some(((b1 & 0x3f) << 24) | self.decode_n(3)?), + 3 => Some(((b1 & 0x3f) << 56) | self.decode_n(7)?), _ => unreachable!(), } } @@ -143,7 +147,7 @@ impl<'a> Decoder<'a> { /// Decodes a TLS-style length-prefixed buffer. pub fn decode_vec(&mut self, n: usize) -> Option<&'a [u8]> { - let len = self.decode_uint(n); + let len = self.decode_n(n); self.decode_checked(len) } @@ -272,6 +276,7 @@ impl Encoder { /// # Panics /// /// When `s` contains non-hex values or an odd number of values. + #[cfg(any(test, feature = "test-fixture"))] #[must_use] pub fn from_hex(s: impl AsRef) -> Self { let s = s.as_ref(); @@ -481,16 +486,28 @@ mod tests { let enc = Encoder::from_hex("0123"); let mut dec = enc.as_decoder(); - assert_eq!(dec.decode_byte().unwrap(), 0x01); - assert_eq!(dec.decode_byte().unwrap(), 0x23); - assert!(dec.decode_byte().is_none()); + assert_eq!(dec.decode_uint::().unwrap(), 0x01); + assert_eq!(dec.decode_uint::().unwrap(), 0x23); + assert!(dec.decode_uint::().is_none()); + } + + #[test] + fn peek_byte() { + let enc = Encoder::from_hex("01"); + let mut dec = enc.as_decoder(); + + assert_eq!(dec.offset(), 0); + assert_eq!(dec.peek_byte().unwrap(), 0x01); + dec.skip(1); + assert_eq!(dec.offset(), 1); + assert!(dec.peek_byte().is_none()); } #[test] fn decode_byte_short() { let enc = Encoder::from_hex(""); let mut dec = enc.as_decoder(); - assert!(dec.decode_byte().is_none()); + assert!(dec.decode_uint::().is_none()); } #[test] @@ -501,7 +518,7 @@ mod tests { assert!(dec.decode(2).is_none()); let mut dec = Decoder::from(&[]); - assert_eq!(dec.decode_remainder().len(), 0); + assert!(dec.decode_remainder().is_empty()); } #[test] diff --git a/third_party/rust/neqo-common/src/fuzz.rs b/third_party/rust/neqo-common/src/fuzz.rs index d0a35a49aed8..b7fdd13f2e8b 100644 --- a/third_party/rust/neqo-common/src/fuzz.rs +++ b/third_party/rust/neqo-common/src/fuzz.rs @@ -7,7 +7,7 @@ use std::{ collections::hash_map::DefaultHasher, fs::File, - hash::{Hash, Hasher}, + hash::{Hash as _, Hasher as _}, io::Write, path::Path, }; diff --git a/third_party/rust/neqo-common/src/header.rs b/third_party/rust/neqo-common/src/header.rs index 73f2e85da1b4..a480eb67ca7c 100644 --- a/third_party/rust/neqo-common/src/header.rs +++ b/third_party/rust/neqo-common/src/header.rs @@ -46,3 +46,29 @@ impl Header { &self.value } } + +impl, U: AsRef> PartialEq<(T, U)> for Header { + fn eq(&self, other: &(T, U)) -> bool { + self.name == other.0.as_ref() && self.value == other.1.as_ref() + } +} + +pub trait HeadersExt<'h> { + fn contains_header, U: AsRef>(self, name: T, value: U) -> bool; + fn find_header + 'h>(self, name: T) -> Option<&'h Header>; +} + +impl<'h, H> HeadersExt<'h> for H +where + H: IntoIterator + 'h, +{ + fn contains_header, U: AsRef>(self, name: T, value: U) -> bool { + let (name, value) = (name.as_ref(), value.as_ref()); + self.into_iter().any(|h| h == &(name, value)) + } + + fn find_header + 'h>(self, name: T) -> Option<&'h Header> { + let name = name.as_ref(); + self.into_iter().find(|h| h.name == name) + } +} diff --git a/third_party/rust/neqo-common/src/hrtime.rs b/third_party/rust/neqo-common/src/hrtime.rs index 7187b7727dbc..b4f23d73cfbb 100644 --- a/third_party/rust/neqo-common/src/hrtime.rs +++ b/third_party/rust/neqo-common/src/hrtime.rs @@ -80,7 +80,7 @@ impl PeriodSet { #[cfg(target_os = "macos")] #[allow(non_camel_case_types)] mod mac { - use std::{mem::size_of, ptr::addr_of_mut}; + use std::ptr::addr_of_mut; // These are manually extracted from the many bindings generated // by bindgen when provided with the simple header: @@ -126,7 +126,7 @@ mod mac { const THREAD_TIME_CONSTRAINT_POLICY: thread_policy_flavor_t = 2; #[allow(clippy::cast_possible_truncation)] const THREAD_TIME_CONSTRAINT_POLICY_COUNT: mach_msg_type_number_t = - (size_of::() / size_of::()) + (std::mem::size_of::() / std::mem::size_of::()) as mach_msg_type_number_t; // These function definitions are taken from a comment in . @@ -370,14 +370,9 @@ impl Drop for Time { } } -// Only run these tests in CI on platforms other than MacOS and Windows, where the timer -// inaccuracies are too high to pass the tests. -#[cfg(all( - test, - not(all(any(target_os = "macos", target_os = "windows"), feature = "ci")), - // Sanitizers are too slow to uphold timing assumptions. - not(neqo_sanitize), -))] +// Only run these tests in CI on Linux, where the timer accuracies are OK enough to pass the tests, +// but only when not running sanitizers. +#[cfg(all(test, target_os = "linux", not(neqo_sanitize)))] mod test { use std::{ thread::{sleep, spawn}, diff --git a/third_party/rust/neqo-common/src/incrdecoder.rs b/third_party/rust/neqo-common/src/incrdecoder.rs index 43a135f49789..f094d25f1c9b 100644 --- a/third_party/rust/neqo-common/src/incrdecoder.rs +++ b/third_party/rust/neqo-common/src/incrdecoder.rs @@ -31,15 +31,11 @@ impl IncrementalDecoderUint { if amount < 8 { self.v <<= amount * 8; } - self.v |= dv.decode_uint(amount).unwrap(); + self.v |= dv.decode_n(amount).unwrap(); *r -= amount; - if *r == 0 { - Some(self.v) - } else { - None - } + (*r == 0).then_some(self.v) } else { - let (v, remaining) = dv.decode_byte().map_or_else( + let (v, remaining) = dv.decode_uint::().map_or_else( || unreachable!(), |b| { ( @@ -56,11 +52,7 @@ impl IncrementalDecoderUint { ); self.remaining = Some(remaining); self.v = v; - if remaining == 0 { - Some(v) - } else { - None - } + (remaining == 0).then_some(v) } } @@ -100,11 +92,7 @@ impl IncrementalDecoderBuffer { let b = dv.decode(amount).unwrap(); self.v.extend_from_slice(b); self.remaining -= amount; - if self.remaining == 0 { - Some(mem::take(&mut self.v)) - } else { - None - } + (self.remaining == 0).then(|| mem::take(&mut self.v)) } } diff --git a/third_party/rust/neqo-common/src/lib.rs b/third_party/rust/neqo-common/src/lib.rs index 5b212f99980c..1e7a53ad1953 100644 --- a/third_party/rust/neqo-common/src/lib.rs +++ b/third_party/rust/neqo-common/src/lib.rs @@ -18,7 +18,7 @@ pub mod log; pub mod qlog; pub mod tos; -use std::fmt::Write; +use std::fmt::Write as _; use enum_map::Enum; diff --git a/third_party/rust/neqo-common/src/log.rs b/third_party/rust/neqo-common/src/log.rs index 04028a26bdaf..ac331ede08ee 100644 --- a/third_party/rust/neqo-common/src/log.rs +++ b/third_party/rust/neqo-common/src/log.rs @@ -7,44 +7,13 @@ #![allow(clippy::module_name_repetitions)] use std::{ - io::Write, + io::Write as _, sync::{Once, OnceLock}, time::{Duration, Instant}, }; use env_logger::Builder; -#[macro_export] -macro_rules! do_log { - (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ - let lvl = $lvl; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::logger().log( - &::log::Record::builder() - .args(format_args!($($arg)+)) - .level(lvl) - .target($target) - .module_path_static(Some(module_path!())) - .file_static(Some(file!())) - .line(Some(line!())) - .build() - ); - } - }); - ($lvl:expr, $($arg:tt)+) => ($crate::do_log!(target: module_path!(), $lvl, $($arg)+)) -} - -#[macro_export] -macro_rules! log_subject { - ($lvl:expr, $subject:expr) => {{ - if $lvl <= ::log::max_level() { - format!("{}", $subject) - } else { - String::new() - } - }}; -} - fn since_start() -> Duration { static START_TIME: OnceLock = OnceLock::new(); START_TIME.get_or_init(Instant::now).elapsed() @@ -66,7 +35,7 @@ pub fn init(level_filter: Option) { let elapsed = since_start(); writeln!( buf, - "{}s{:3}ms {} {}", + "{}.{:03} {} {}", elapsed.as_secs(), elapsed.as_millis() % 1000, record.level(), @@ -74,42 +43,55 @@ pub fn init(level_filter: Option) { ) }); if let Err(e) = builder.try_init() { - do_log!(::log::Level::Warn, "Logging initialization error {:?}", e); + eprintln!("Logging initialization error {e:?}"); } else { - do_log!(::log::Level::Debug, "Logging initialized"); + ::log::debug!("Logging initialized"); } }); } #[macro_export] -macro_rules! log_invoke { - ($lvl:expr, $ctx:expr, $($arg:tt)*) => ( { - ::neqo_common::log::init(None); - ::neqo_common::do_log!($lvl, "[{}] {}", $ctx, format!($($arg)*)); - } ) -} -#[macro_export] +// TODO: Enable `#[clippy::format_args]` once our MSRV is >= 1.84 macro_rules! qerror { - ([$ctx:expr], $($arg:tt)*) => (::neqo_common::log_invoke!(::log::Level::Error, $ctx, $($arg)*);); - ($($arg:tt)*) => ( { ::neqo_common::log::init(None); ::neqo_common::do_log!(::log::Level::Error, $($arg)*); } ); + ($($arg:tt)*) => ( { + #[cfg(any(test, feature = "bench"))] + ::neqo_common::log::init(None); + ::log::error!($($arg)*); + } ); } #[macro_export] +// TODO: Enable `#[clippy::format_args]` once our MSRV is >= 1.84 macro_rules! qwarn { - ([$ctx:expr], $($arg:tt)*) => (::neqo_common::log_invoke!(::log::Level::Warn, $ctx, $($arg)*);); - ($($arg:tt)*) => ( { ::neqo_common::log::init(None); ::neqo_common::do_log!(::log::Level::Warn, $($arg)*); } ); + ($($arg:tt)*) => ( { + #[cfg(any(test, feature = "bench"))] + ::neqo_common::log::init(None); + ::log::warn!($($arg)*); + } ); } #[macro_export] +// TODO: Enable `#[clippy::format_args]` once our MSRV is >= 1.84 macro_rules! qinfo { - ([$ctx:expr], $($arg:tt)*) => (::neqo_common::log_invoke!(::log::Level::Info, $ctx, $($arg)*);); - ($($arg:tt)*) => ( { ::neqo_common::log::init(None); ::neqo_common::do_log!(::log::Level::Info, $($arg)*); } ); + ($($arg:tt)*) => ( { + #[cfg(any(test, feature = "bench"))] + ::neqo_common::log::init(None); + ::log::info!($($arg)*); + } ); } #[macro_export] +// TODO: Enable `#[clippy::format_args]` once our MSRV is >= 1.84 macro_rules! qdebug { - ([$ctx:expr], $($arg:tt)*) => (::neqo_common::log_invoke!(::log::Level::Debug, $ctx, $($arg)*);); - ($($arg:tt)*) => ( { ::neqo_common::log::init(None); ::neqo_common::do_log!(::log::Level::Debug, $($arg)*); } ); + ($($arg:tt)*) => ( { + #[cfg(any(test, feature = "bench"))] + ::neqo_common::log::init(None); + ::log::debug!($($arg)*); + } ); } #[macro_export] +// TODO: Enable `#[clippy::format_args]` once our MSRV is >= 1.84 macro_rules! qtrace { - ([$ctx:expr], $($arg:tt)*) => (::neqo_common::log_invoke!(::log::Level::Trace, $ctx, $($arg)*);); - ($($arg:tt)*) => ( { ::neqo_common::log::init(None); ::neqo_common::do_log!(::log::Level::Trace, $($arg)*); } ); + ($($arg:tt)*) => ( { + #[cfg(any(test, feature = "bench"))] + ::neqo_common::log::init(None); + ::log::trace!($($arg)*); + } ); } diff --git a/third_party/rust/neqo-common/src/qlog.rs b/third_party/rust/neqo-common/src/qlog.rs index 34f1e1c2ca74..7401e21a5401 100644 --- a/third_party/rust/neqo-common/src/qlog.rs +++ b/third_party/rust/neqo-common/src/qlog.rs @@ -59,7 +59,7 @@ impl NeqoQlog { title, description, None, - std::time::Instant::now(), + Instant::now(), new_trace(role), qlog::events::EventImportance::Base, Box::new(BufWriter::new(file)), @@ -149,11 +149,7 @@ impl NeqoQlog { { if let Some(inner) = self.inner.borrow_mut().as_mut() { if let Err(e) = f(&mut inner.streamer) { - crate::do_log!( - ::log::Level::Error, - "Qlog event generation failed with error {}; closing qlog.", - e - ); + log::error!("Qlog event generation failed with error {e}; closing qlog."); *self.inner.borrow_mut() = None; } } @@ -169,13 +165,13 @@ impl fmt::Debug for NeqoQlogShared { impl Drop for NeqoQlogShared { fn drop(&mut self) { if let Err(e) = self.streamer.finish_log() { - crate::do_log!(::log::Level::Error, "Error dropping NeqoQlog: {}", e); + log::error!("Error dropping NeqoQlog: {e}"); } } } #[must_use] -pub fn new_trace(role: Role) -> qlog::TraceSeq { +pub fn new_trace(role: Role) -> TraceSeq { TraceSeq { vantage_point: VantagePoint { name: Some(format!("neqo-{role}")), @@ -186,7 +182,7 @@ pub fn new_trace(role: Role) -> qlog::TraceSeq { flow: None, }, title: Some(format!("neqo-{role} trace")), - description: Some("Example qlog trace description".to_string()), + description: Some(format!("neqo-{role} trace")), configuration: Some(Configuration { time_offset: Some(0.0), original_uris: None, @@ -233,7 +229,7 @@ mod test { let (log, contents) = test_fixture::new_neqo_qlog(); log.add_event_with_instant(|| Some(Event::with_time(0.0, EV_DATA)), Instant::now()); assert_eq!( - Regex::new("\"time\":[0-9].[0-9]*,") + Regex::new("\"time\":[0-9]+.[0-9]+,") .unwrap() .replace(&contents.to_string(), "\"time\":0.0,"), format!("{EXPECTED_LOG_HEADER}{EXPECTED_LOG_EVENT}"), diff --git a/third_party/rust/neqo-common/src/tos.rs b/third_party/rust/neqo-common/src/tos.rs index 9661d82ecf54..ed6a5d2724d2 100644 --- a/third_party/rust/neqo-common/src/tos.rs +++ b/third_party/rust/neqo-common/src/tos.rs @@ -62,7 +62,7 @@ impl IpTosEcn { } } -/// Diffserv Codepoints, mapped to the upper six bits of the TOS field. +/// Diffserv codepoints, mapped to the upper six bits of the TOS field. /// #[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug)] #[repr(u8)] diff --git a/third_party/rust/neqo-common/tests/log.rs b/third_party/rust/neqo-common/tests/log.rs index 135a667146dd..9cdec162cd0f 100644 --- a/third_party/rust/neqo-common/tests/log.rs +++ b/third_party/rust/neqo-common/tests/log.rs @@ -19,40 +19,9 @@ fn basic() { fn args() { let num = 1; let obj = std::time::Instant::now(); - qerror!("error {} {:?}", num, obj); - qwarn!("warn {} {:?}", num, obj); - qinfo!("info {} {:?}", num, obj); - qdebug!("debug {} {:?}", num, obj); - qtrace!("trace {} {:?}", num, obj); -} - -#[test] -fn context() { - let context = "context"; - qerror!([context], "error"); - qwarn!([context], "warn"); - qinfo!([context], "info"); - qdebug!([context], "debug"); - qtrace!([context], "trace"); -} - -#[test] -fn context_comma() { - let obj = vec![1, 2, 3]; - let context = "context"; - qerror!([context], "error {:?}", obj); - qwarn!([context], "warn {:?}", obj); - qinfo!([context], "info {:?}", obj); - qdebug!([context], "debug {:?}", obj); - qtrace!([context], "trace {:?}", obj); -} - -#[test] -fn context_expr() { - let context = vec![1, 2, 3]; - qerror!([format!("{:x?}", context)], "error"); - qwarn!([format!("{:x?}", context)], "warn"); - qinfo!([format!("{:x?}", context)], "info"); - qdebug!([format!("{:x?}", context)], "debug"); - qtrace!([format!("{:x?}", context)], "trace"); + qerror!("error {num} {obj:?}"); + qwarn!("warn {num} {obj:?}"); + qinfo!("info {num} {obj:?}"); + qdebug!("debug {num} {obj:?}"); + qtrace!("trace {num} {obj:?}"); } diff --git a/third_party/rust/neqo-crypto/.cargo-checksum.json b/third_party/rust/neqo-crypto/.cargo-checksum.json index 02da10339513..ae80f6d57075 100644 --- a/third_party/rust/neqo-crypto/.cargo-checksum.json +++ b/third_party/rust/neqo-crypto/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"4c2750f8c99df82e117073f3958e83fd51e03f0d8ca3aaba4c81990f4875fb64","bindings/bindings.toml":"e7e4b75736cfcf4d52febacb99a6f6c6c7b1d648ed8bdc424648be876c850e91","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"dfc3b2c8038c4b1c69d7a10bd06c4226e36935e7597225aba26039f700cc8f4f","min_version.txt":"04b271df436ebebd03df52ef009d6814f6a64e55203988790a6fcee7b2dc27af","src/aead.rs":"6410bcbe717a6b9ea6f11209b0888033358113ebc05b8a95cec1980d1360be4d","src/aead_null.rs":"81163fafef59bd2800bd0a078d53d0f05ee114f0e22165717823a5ff1cb908af","src/agent.rs":"38eb130b2b66edfaae05f154cdb718aee4a8c4dcffbf349b0ceb2287d4cbbb6e","src/agentio.rs":"6d86ff8d6319bf6c3dd7124b8d60271e3e1accd07a7b43ba54e81be51c8d2a98","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"8e75e69ec3544474b21f8915a7559463889c2f608b201dee274a8d701880950e","src/constants.rs":"58e296e314825753b2ab1d6effe9a1386421dc568f6ebfa8e95a95acb87205da","src/ech.rs":"75dd192423e8996d9061da5e9c20d30bff5153b9344132eda4fe321c4c141870","src/err.rs":"2366501e0b48933a6a2e1c5b934aa55108c093729c84878b45e1e012e4e45d51","src/exp.rs":"d953873e87430b1c84d4a83c8eb3815041f5585b210bbaf59ae2c4d0057f5edd","src/ext.rs":"cbf7d9f5ecabf4b8c9efd6c334637ab1596ec5266d38ab8d2d6ceae305283deb","src/hkdf.rs":"8745ba761be821c1819cedf6dfd91f8b3148c6718053a4a74f33eb50c7d0cc40","src/hp.rs":"510a4a7f278203aa306ead05608f99397edc3806dc22b0af9e28c665b43ae56c","src/lib.rs":"30632dacb1b6ed9321e42ca1aaa2b71db8d4878eeb27c608e4eabdc0b76bcdba","src/min_version.rs":"c6e1f98b9f56db0622ac38c1be131c55acf4a0f09ed0d6283f4d6308e2d1301a","src/p11.rs":"375397b18fcdf36dcdd22c164c8572dd83caf01b8d0065be3029444b197e1464","src/prio.rs":"5cf0105e78b1db43c65283208174abc3714a41dbb4d5cd80ac547a5a5a7c627c","src/replay.rs":"5cda39bc8fa8a07c493b761b8dfb5cbc9f669f97a2df7832a028ab366b3426be","src/result.rs":"0587cbb6aace71a7f9765ef7c01dcd9f73a49dcc6331e1d8fe4de2aef6ca65b6","src/secrets.rs":"2c47935c5b8c42363897881eaa0c171e84cf031e57a6e1387b99327080e8dd60","src/selfencrypt.rs":"018c2dacabd3e463fdadd5707715b23c26c261c4c7d86e66c62f0acec986cad9","src/ssl.rs":"450cf9fb327515de612b29e3a0f6e15499e6c0b523790e5986fd71a9ea5e76af","src/time.rs":"ade63a72ae90796d7fcccadbb15efc4594fcdb68913a914a657d4556fde88f62","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"cbd0011f1d33281883a45d433228221062424c94e86decade5697731c08a1c52","tests/ext.rs":"57af4e2df211fa8afdb73125d4344ef5c70c1ea4579107c3e6f5746308ee3e7b","tests/handshake.rs":"aa904736d36cc5d5cc0c4f6053b529987f33f944a73411bf08e01d30c4867186","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"ccda23018dac70b3ff3742afcb0fbae0735be9aeb36644a4ae2b1d7c9126801c","tests/init.rs":"3e15150c4b324c06ca5e8935618e4008da53dc0ef4b69325d150831e87dc0b63","tests/selfencrypt.rs":"8d10840b41629bf449a6b3a551377315e8a05ca26c6b041548748196652c5909"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"6953ac93fcc661e47b15e627f031ac21f4b4ab77fa125871a339cc964b812cb3","bindings/bindings.toml":"e7e4b75736cfcf4d52febacb99a6f6c6c7b1d648ed8bdc424648be876c850e91","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"dfc3b2c8038c4b1c69d7a10bd06c4226e36935e7597225aba26039f700cc8f4f","min_version.txt":"04b271df436ebebd03df52ef009d6814f6a64e55203988790a6fcee7b2dc27af","src/aead.rs":"018b826284ea4ddba7d65ff56f3ce9744e24ac8d26b1364b08f6e8b12b259be5","src/aead_null.rs":"81163fafef59bd2800bd0a078d53d0f05ee114f0e22165717823a5ff1cb908af","src/agent.rs":"6b6bcd735cb12d3e3ddebbb04ebd705d192a9cbce6e2a967e86e7b41cccf0a8d","src/agentio.rs":"237f85faacdb6ee5b3a6efa8a620fcf109094f5fd9dfb69d2c74986f11ccdb0e","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"4fdaa3834d8a72f41198449010fd5c3f6be6a54e429427c37bde5aab9421585c","src/constants.rs":"58e296e314825753b2ab1d6effe9a1386421dc568f6ebfa8e95a95acb87205da","src/ech.rs":"869e36414418b8747e6ebb45af24159c1908fc829439c16d79cdd89e355d2111","src/err.rs":"2366501e0b48933a6a2e1c5b934aa55108c093729c84878b45e1e012e4e45d51","src/exp.rs":"d953873e87430b1c84d4a83c8eb3815041f5585b210bbaf59ae2c4d0057f5edd","src/ext.rs":"cbf7d9f5ecabf4b8c9efd6c334637ab1596ec5266d38ab8d2d6ceae305283deb","src/hkdf.rs":"8745ba761be821c1819cedf6dfd91f8b3148c6718053a4a74f33eb50c7d0cc40","src/hp.rs":"510a4a7f278203aa306ead05608f99397edc3806dc22b0af9e28c665b43ae56c","src/lib.rs":"cfbf92759c6d1b888d89b9c28adbd96839bff60fc8106169a043eafce0f8a21e","src/min_version.rs":"c6e1f98b9f56db0622ac38c1be131c55acf4a0f09ed0d6283f4d6308e2d1301a","src/p11.rs":"120c45dc037c243a1551b79c7a32613acf22e2961f2ea1e11c73bbce9d1f76dc","src/prio.rs":"5cf0105e78b1db43c65283208174abc3714a41dbb4d5cd80ac547a5a5a7c627c","src/replay.rs":"5cda39bc8fa8a07c493b761b8dfb5cbc9f669f97a2df7832a028ab366b3426be","src/result.rs":"5a76688787741de7a935dbbab4bcb917d481d1c9c50a34df7e510036feb3da17","src/secrets.rs":"c09caca2bf7b60fc7855fc2ad56094a291cb0596308eadf46ab51af0e271a9f0","src/selfencrypt.rs":"80efac0f116b22d86f88f07d694ff2f822bd87b792b3dff8d6376a251394de39","src/ssl.rs":"450cf9fb327515de612b29e3a0f6e15499e6c0b523790e5986fd71a9ea5e76af","src/time.rs":"27d0185c16e150dc381cd6c01ef85fdf7881e5349386466e175d641aab9ab30f","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"cbd0011f1d33281883a45d433228221062424c94e86decade5697731c08a1c52","tests/ext.rs":"57af4e2df211fa8afdb73125d4344ef5c70c1ea4579107c3e6f5746308ee3e7b","tests/handshake.rs":"efae67a40f87419aea30c7ab7eb1007faf7f56a83dbf1a18e24fbc0cb92ec901","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"c74070a8f877aaa6305b9411f6e60d8b509b0ac1bef2988cc44b8a48552c953c","tests/init.rs":"3e15150c4b324c06ca5e8935618e4008da53dc0ef4b69325d150831e87dc0b63","tests/selfencrypt.rs":"8d10840b41629bf449a6b3a551377315e8a05ca26c6b041548748196652c5909"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-crypto/Cargo.toml b/third_party/rust/neqo-crypto/Cargo.toml index 842b47e7e30a..453adefcab15 100644 --- a/third_party/rust/neqo-crypto/Cargo.toml +++ b/third_party/rust/neqo-crypto/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "neqo-crypto" -version = "0.11.0" +version = "0.12.2" authors = ["The Neqo Authors "] build = "build.rs" autolib = false @@ -113,12 +113,28 @@ version = "0.5" default-features = false [features] +bench = [] disable-encryption = [] disable-random = [] gecko = ["mozbuild"] [lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" [lints.clippy.cargo] level = "warn" @@ -131,3 +147,19 @@ priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/neqo-crypto/src/aead.rs b/third_party/rust/neqo-crypto/src/aead.rs index 0678d147fb27..059e9acb6159 100644 --- a/third_party/rust/neqo-crypto/src/aead.rs +++ b/third_party/rust/neqo-crypto/src/aead.rs @@ -17,7 +17,7 @@ use crate::{ experimental_api, p11::{PK11SymKey, SymKey}, scoped_ptr, - ssl::{self, PRUint16, PRUint64, PRUint8, SSLAeadContext}, + ssl::{PRUint16, PRUint64, PRUint8, SSLAeadContext}, }; experimental_api!(SSL_MakeAead( @@ -80,7 +80,7 @@ impl RealAead { prefix: &str, ) -> Res { let p = prefix.as_bytes(); - let mut ctx: *mut ssl::SSLAeadContext = null_mut(); + let mut ctx: *mut SSLAeadContext = null_mut(); SSL_MakeAead( version, cipher, diff --git a/third_party/rust/neqo-crypto/src/agent.rs b/third_party/rust/neqo-crypto/src/agent.rs index b3e76ca39b0c..665efbf1a006 100644 --- a/third_party/rust/neqo-crypto/src/agent.rs +++ b/third_party/rust/neqo-crypto/src/agent.rs @@ -7,7 +7,7 @@ use std::{ cell::RefCell, ffi::{CStr, CString}, - mem::{self, MaybeUninit}, + mem::MaybeUninit, ops::{Deref, DerefMut}, os::raw::{c_uint, c_void}, pin::Pin, @@ -107,7 +107,7 @@ fn get_alpn(fd: *mut ssl::PRFileDesc, pre: bool) -> Res> { } _ => None, }; - qtrace!([format!("{fd:p}")], "got ALPN {:?}", alpn); + qtrace!("[{fd:p}] got ALPN {alpn:?}"); Ok(alpn) } @@ -135,7 +135,7 @@ impl SecretAgentPreInfo { ssl::SSL_GetPreliminaryChannelInfo( fd, info.as_mut_ptr(), - c_uint::try_from(mem::size_of::())?, + c_uint::try_from(std::mem::size_of::())?, ) })?; @@ -222,7 +222,7 @@ impl SecretAgentInfo { ssl::SSL_GetChannelInfo( fd, info.as_mut_ptr(), - c_uint::try_from(mem::size_of::())?, + c_uint::try_from(std::mem::size_of::())?, ) })?; let info = unsafe { info.assume_init() }; @@ -337,7 +337,9 @@ impl SecretAgent { ssl::SSL_ImportFD(null_mut(), base_fd.cast()) }; if fd.is_null() { - unsafe { prio::PR_Close(base_fd) }; + unsafe { + prio::PR_Close(base_fd); + } return Err(Error::CreateSslSocket); } Ok(fd) @@ -347,8 +349,8 @@ impl SecretAgent { unsafe extern "C" fn auth_complete_hook( arg: *mut c_void, _fd: *mut ssl::PRFileDesc, - _check_sig: ssl::PRBool, - _is_server: ssl::PRBool, + _check_sig: PRBool, + _is_server: PRBool, ) -> ssl::SECStatus { let auth_required_ptr = arg.cast::(); *auth_required_ptr = true; @@ -369,7 +371,7 @@ impl SecretAgent { if st.is_none() { *st = Some(alert.description); } else { - qwarn!([format!("{fd:p}")], "duplicate alert {}", alert.description); + qwarn!("[{fd:p}] duplicate alert {}", alert.description); } } } @@ -394,7 +396,7 @@ impl SecretAgent { self.now.bind(self.fd)?; self.configure(grease)?; - secstatus_to_res(unsafe { ssl::SSL_ResetHandshake(self.fd, ssl::PRBool::from(is_server)) }) + secstatus_to_res(unsafe { ssl::SSL_ResetHandshake(self.fd, PRBool::from(is_server)) }) } /// Default configuration. @@ -429,7 +431,7 @@ impl SecretAgent { /// If NSS can't enable or disable ciphers. pub fn set_ciphers(&mut self, ciphers: &[Cipher]) -> Res<()> { if self.state != HandshakeState::New { - qwarn!([self], "Cannot enable ciphers in state {:?}", self.state); + qwarn!("[{self}] Cannot enable ciphers in state {:?}", self.state); return Err(Error::InternalError); } @@ -438,13 +440,13 @@ impl SecretAgent { for i in 0..cipher_count { let p = all_ciphers.wrapping_add(i); secstatus_to_res(unsafe { - ssl::SSL_CipherPrefSet(self.fd, i32::from(*p), ssl::PRBool::from(false)) + ssl::SSL_CipherPrefSet(self.fd, i32::from(*p), PRBool::from(false)) })?; } for c in ciphers { secstatus_to_res(unsafe { - ssl::SSL_CipherPrefSet(self.fd, i32::from(*c), ssl::PRBool::from(true)) + ssl::SSL_CipherPrefSet(self.fd, i32::from(*c), PRBool::from(true)) })?; } Ok(()) @@ -600,8 +602,8 @@ impl SecretAgent { /// Calling this function returns None until the connection is complete. #[must_use] pub const fn info(&self) -> Option<&SecretAgentInfo> { - match self.state { - HandshakeState::Complete(ref info) => Some(info), + match &self.state { + HandshakeState::Complete(info) => Some(info), _ => None, } } @@ -644,7 +646,7 @@ impl SecretAgent { fn capture_error(&mut self, res: Res) -> Res { if let Err(e) = res { let e = ech::convert_ech_error(self.fd, e); - qwarn!([self], "error: {:?}", e); + qwarn!("[{self}] error: {e:?}"); self.state = HandshakeState::Failed(e.clone()); Err(e) } else { @@ -669,7 +671,7 @@ impl SecretAgent { let info = self.capture_error(SecretAgentInfo::new(self.fd))?; HandshakeState::Complete(info) }; - qdebug!([self], "state -> {:?}", self.state); + qdebug!("[{self}] state -> {:?}", self.state); Ok(()) } @@ -692,8 +694,8 @@ impl SecretAgent { // Within this scope, _h maintains a mutable reference to self.io. let _h = self.io.wrap(input); match self.state { - HandshakeState::Authenticated(ref err) => unsafe { - ssl::SSL_AuthCertificateComplete(self.fd, *err) + HandshakeState::Authenticated(err) => unsafe { + ssl::SSL_AuthCertificateComplete(self.fd, err) }, _ => unsafe { ssl::SSL_ForceHandshake(self.fd) }, } @@ -726,10 +728,10 @@ impl SecretAgent { let records = self.setup_raw()?; // Fire off any authentication we might need to complete. - if let HandshakeState::Authenticated(ref err) = self.state { + if let HandshakeState::Authenticated(err) = self.state { let result = - secstatus_to_res(unsafe { ssl::SSL_AuthCertificateComplete(self.fd, *err) }); - qdebug!([self], "SSL_AuthCertificateComplete: {:?}", result); + secstatus_to_res(unsafe { ssl::SSL_AuthCertificateComplete(self.fd, err) }); + qdebug!("[{self}] SSL_AuthCertificateComplete: {result:?}"); // This should return SECSuccess, so don't use update_state(). self.capture_error(result)?; } @@ -758,11 +760,15 @@ impl SecretAgent { if self.raw == Some(true) { // Need to hold the record list in scope until the close is done. let _records = self.setup_raw().expect("Can only close"); - unsafe { prio::PR_Close(self.fd.cast()) }; + unsafe { + prio::PR_Close(self.fd.cast()); + } } else { // Need to hold the IO wrapper in scope until the close is done. let _io = self.io.wrap(&[]); - unsafe { prio::PR_Close(self.fd.cast()) }; + unsafe { + prio::PR_Close(self.fd.cast()); + } }; let _output = self.io.take_output(); self.fd = null_mut(); @@ -876,7 +882,7 @@ impl Client { token, len, info.as_mut_ptr(), - c_uint::try_from(mem::size_of::()).unwrap(), + c_uint::try_from(std::mem::size_of::()).unwrap(), ); if info_res.is_err() { // Ignore the token. @@ -891,11 +897,7 @@ impl Client { let len = usize::try_from(len).unwrap(); let mut v = Vec::with_capacity(len); v.extend_from_slice(null_safe_slice(token, len)); - qdebug!( - [format!("{fd:p}")], - "Got resumption token {}", - hex_snip_middle(&v) - ); + qdebug!("[{fd:p}] Got resumption token {}", hex_snip_middle(&v)); if resumption.len() >= MAX_TICKETS { resumption.remove(0); @@ -965,7 +967,7 @@ impl Client { /// Error returned when the configuration is invalid. pub fn enable_ech(&mut self, ech_config_list: impl AsRef<[u8]>) -> Res<()> { let config = ech_config_list.as_ref(); - qdebug!([self], "Enable ECH for a server: {}", hex_with_len(config)); + qdebug!("[{self}] Enable ECH for a server: {}", hex_with_len(config)); self.ech_config = Vec::from(config); if config.is_empty() { unsafe { ech::SSL_EnableTls13GreaseEch(self.agent.fd, PRBool::from(true)) } @@ -1016,7 +1018,7 @@ pub enum ZeroRttCheckResult { /// A `ZeroRttChecker` is used by the agent to validate the application token (as provided by /// `send_ticket`) -pub trait ZeroRttChecker: std::fmt::Debug + std::marker::Unpin { +pub trait ZeroRttChecker: std::fmt::Debug + Unpin { fn check(&self, token: &[u8]) -> ZeroRttCheckResult; } @@ -1068,7 +1070,7 @@ impl Server { return Err(Error::CertificateLoading); }; let key_ptr = unsafe { p11::PK11_FindKeyByAnyCert(*cert, null_mut()) }; - let Ok(key) = p11::PrivateKey::from_ptr(key_ptr) else { + let Ok(key) = PrivateKey::from_ptr(key_ptr) else { return Err(Error::CertificateLoading); }; secstatus_to_res(unsafe { @@ -1175,7 +1177,7 @@ impl Server { pk: &PublicKey, ) -> Res<()> { let cfg = ech::encode_config(config, public_name, pk)?; - qdebug!([self], "Enable ECH for a server: {}", hex_with_len(&cfg)); + qdebug!("[{self}] Enable ECH for a server: {}", hex_with_len(&cfg)); unsafe { ech::SSL_SetServerEchConfigs( self.agent.fd, @@ -1213,8 +1215,8 @@ impl ::std::fmt::Display for Server { /// A generic container for Client or Server. #[derive(Debug)] pub enum Agent { - Client(crate::agent::Client), - Server(crate::agent::Server), + Client(Client), + Server(Server), } impl Deref for Agent { diff --git a/third_party/rust/neqo-crypto/src/agentio.rs b/third_party/rust/neqo-crypto/src/agentio.rs index f2173bfd8d00..7bf14f941be6 100644 --- a/third_party/rust/neqo-crypto/src/agentio.rs +++ b/third_party/rust/neqo-crypto/src/agentio.rs @@ -52,7 +52,7 @@ impl Record { // Shoves this record into the socket, returns true if blocked. pub(crate) fn write(self, fd: *mut ssl::PRFileDesc) -> Res<()> { - qtrace!("write {:?}", self); + qtrace!("write {self:?}"); unsafe { ssl::SSL_RecordLayerData( fd, @@ -177,7 +177,7 @@ impl AgentIoInput { #[allow(clippy::disallowed_methods)] // We just checked if this was empty. let src = unsafe { std::slice::from_raw_parts(self.input, amount) }; - qtrace!([self], "read {}", hex(src)); + qtrace!("[{self}] read {}", hex(src)); let dst = unsafe { std::slice::from_raw_parts_mut(buf, amount) }; dst.copy_from_slice(src); self.input = self.input.wrapping_add(amount); @@ -186,7 +186,7 @@ impl AgentIoInput { } fn reset(&mut self) { - qtrace!([self], "reset"); + qtrace!("[{self}] reset"); self.input = null(); self.available = 0; } @@ -230,12 +230,12 @@ impl AgentIo { // Stage output from TLS into the output buffer. fn save_output(&mut self, buf: *const u8, count: usize) { let slice = unsafe { null_safe_slice(buf, count) }; - qtrace!([self], "save output {}", hex(slice)); + qtrace!("[{self}] save output {}", hex(slice)); self.output.extend_from_slice(slice); } pub fn take_output(&mut self) -> Vec { - qtrace!([self], "take output"); + qtrace!("[{self}] take output"); mem::take(&mut self.output) } } diff --git a/third_party/rust/neqo-crypto/src/cert.rs b/third_party/rust/neqo-crypto/src/cert.rs index 80609f53166d..e335a70bebbe 100644 --- a/third_party/rust/neqo-crypto/src/cert.rs +++ b/third_party/rust/neqo-crypto/src/cert.rs @@ -46,7 +46,7 @@ fn stapled_ocsp_responses(fd: *mut PRFileDesc) -> Option>> { Some(ocsp_ptr) => { let mut ocsp_helper: Vec> = Vec::new(); let Ok(len) = isize::try_from(unsafe { ocsp_ptr.as_ref().len }) else { - qerror!([format!("{fd:p}")], "Received illegal OSCP length"); + qerror!("[{fd:p}] Received illegal OSCP length"); return None; }; for idx in 0..len { @@ -72,23 +72,6 @@ fn signed_cert_timestamp(fd: *mut PRFileDesc) -> Option> { }) } -impl CertificateInfo { - pub(crate) fn new(fd: *mut PRFileDesc) -> Option { - peer_certificate_chain(fd).map(|certs| Self { - certs, - stapled_ocsp_responses: stapled_ocsp_responses(fd), - signed_cert_timestamp: signed_cert_timestamp(fd), - }) - } -} - -impl CertificateInfo { - #[must_use] - pub fn iter(&self) -> ItemArrayIterator<'_> { - self.certs.into_iter() - } -} - impl<'a> IntoIterator for &'a CertificateInfo { type IntoIter = ItemArrayIterator<'a>; type Item = &'a [u8]; @@ -98,6 +81,19 @@ impl<'a> IntoIterator for &'a CertificateInfo { } impl CertificateInfo { + pub(crate) fn new(fd: *mut PRFileDesc) -> Option { + peer_certificate_chain(fd).map(|certs| Self { + certs, + stapled_ocsp_responses: stapled_ocsp_responses(fd), + signed_cert_timestamp: signed_cert_timestamp(fd), + }) + } + + #[must_use] + pub fn iter(&self) -> ItemArrayIterator<'_> { + self.certs.into_iter() + } + #[must_use] pub const fn stapled_ocsp_responses(&self) -> &Option>> { &self.stapled_ocsp_responses diff --git a/third_party/rust/neqo-crypto/src/ech.rs b/third_party/rust/neqo-crypto/src/ech.rs index 76fd362c1454..29c4d2a37079 100644 --- a/third_party/rust/neqo-crypto/src/ech.rs +++ b/third_party/rust/neqo-crypto/src/ech.rs @@ -146,7 +146,7 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> { assert_eq!(secret_ptr.is_null(), public_ptr.is_null()); let sk = PrivateKey::from_ptr(secret_ptr)?; let pk = PublicKey::from_ptr(public_ptr)?; - qtrace!("Generated key pair: sk={:?} pk={:?}", sk, pk); + qtrace!("Generated key pair: sk={sk:?} pk={pk:?}"); Ok((sk, pk)) } diff --git a/third_party/rust/neqo-crypto/src/lib.rs b/third_party/rust/neqo-crypto/src/lib.rs index 1816440d633b..44c24fcc8f6b 100644 --- a/third_party/rust/neqo-crypto/src/lib.rs +++ b/third_party/rust/neqo-crypto/src/lib.rs @@ -70,7 +70,7 @@ mod nss { // Need to map the types through. fn secstatus_to_res(code: nss::SECStatus) -> Res<()> { - crate::err::secstatus_to_res(code as crate::ssl::SECStatus) + err::secstatus_to_res(code) } enum NssLoaded { @@ -106,7 +106,7 @@ fn version_check() -> Res<()> { /// This allows us to use SSLTRACE in all of our unit tests and programs. #[cfg(debug_assertions)] fn enable_ssl_trace() -> Res<()> { - let opt = ssl::Opt::Locking.as_int(); + let opt = Opt::Locking.as_int(); let mut v: ::std::os::raw::c_int = 0; secstatus_to_res(unsafe { ssl::SSL_OptionGetDefault(opt, &mut v) }) } diff --git a/third_party/rust/neqo-crypto/src/p11.rs b/third_party/rust/neqo-crypto/src/p11.rs index 20a88ba70f1b..96d149ad829b 100644 --- a/third_party/rust/neqo-crypto/src/p11.rs +++ b/third_party/rust/neqo-crypto/src/p11.rs @@ -11,7 +11,6 @@ use std::{ cell::RefCell, - mem, ops::{Deref, DerefMut}, os::raw::c_uint, ptr::null_mut, @@ -265,7 +264,7 @@ impl Item { SECItem { type_: SECItemType::siBuffer, data: data.cast_mut().cast(), - len: c_uint::try_from(mem::size_of::()).unwrap(), + len: c_uint::try_from(std::mem::size_of::()).unwrap(), } } diff --git a/third_party/rust/neqo-crypto/src/result.rs b/third_party/rust/neqo-crypto/src/result.rs index e304fcea7f06..4c0c73e6fc21 100644 --- a/third_party/rust/neqo-crypto/src/result.rs +++ b/third_party/rust/neqo-crypto/src/result.rs @@ -83,7 +83,7 @@ mod tests { assert_eq!(code, -12273); assert_eq!( desc, - "SSL received a record with an incorrect Message Authentication Code." + "SSL received a record with an incorrect Message Authentication Code" ); } _ => unreachable!(), diff --git a/third_party/rust/neqo-crypto/src/secrets.rs b/third_party/rust/neqo-crypto/src/secrets.rs index 3d637fb958c0..5d17d5fcdefa 100644 --- a/third_party/rust/neqo-crypto/src/secrets.rs +++ b/third_party/rust/neqo-crypto/src/secrets.rs @@ -88,7 +88,7 @@ impl Secrets { } fn put(&mut self, dir: SecretDirection, epoch: Epoch, key: SymKey) { - qdebug!("{:?} secret available for {:?}: {:?}", dir, epoch, key); + qdebug!("{dir:?} secret available for {epoch:?}: {key:?}"); let keys = match dir { SecretDirection::Read => &mut self.r, SecretDirection::Write => &mut self.w, diff --git a/third_party/rust/neqo-crypto/src/selfencrypt.rs b/third_party/rust/neqo-crypto/src/selfencrypt.rs index 1618a971a99c..7e5c6bb96424 100644 --- a/third_party/rust/neqo-crypto/src/selfencrypt.rs +++ b/third_party/rust/neqo-crypto/src/selfencrypt.rs @@ -61,7 +61,7 @@ impl SelfEncrypt { self.old_key = Some(mem::replace(&mut self.key, new_key)); let (kid, _) = self.key_id.overflowing_add(1); self.key_id = kid; - qinfo!(["SelfEncrypt"], "Rotated keys to {}", self.key_id); + qinfo!("[SelfEncrypt] Rotated keys to {}", self.key_id); Ok(()) } @@ -99,8 +99,7 @@ impl SelfEncrypt { output.resize(encoded_len, 0); cipher.encrypt(0, extended_aad.as_ref(), plaintext, &mut output[offset..])?; qtrace!( - ["SelfEncrypt"], - "seal {} {} -> {}", + "[SelfEncrypt] seal {} {} -> {}", hex(aad), hex(plaintext), hex(&output) @@ -150,8 +149,7 @@ impl SelfEncrypt { let final_len = decrypted.len(); output.truncate(final_len); qtrace!( - ["SelfEncrypt"], - "open {} {} -> {}", + "[SelfEncrypt] open {} {} -> {}", hex(aad), hex(ciphertext), hex(&output) diff --git a/third_party/rust/neqo-crypto/src/time.rs b/third_party/rust/neqo-crypto/src/time.rs index 79ddcfbc02f1..5375833df9bd 100644 --- a/third_party/rust/neqo-crypto/src/time.rs +++ b/third_party/rust/neqo-crypto/src/time.rs @@ -233,7 +233,7 @@ mod test { init(); let base = get_base(); let delta_micros = PRTime::try_from(DELTA.as_micros()).unwrap(); - println!("{} - {}", base.prtime, delta_micros); + println!("{} - {delta_micros}", base.prtime); let t = Time::try_from(base.prtime - delta_micros).unwrap(); assert_eq!(Instant::from(t) + DELTA, base.instant); } diff --git a/third_party/rust/neqo-crypto/tests/handshake.rs b/third_party/rust/neqo-crypto/tests/handshake.rs index 799ccba34e0a..820c5235aa12 100644 --- a/third_party/rust/neqo-crypto/tests/handshake.rs +++ b/third_party/rust/neqo-crypto/tests/handshake.rs @@ -116,7 +116,7 @@ impl ZeroRttChecker for PermissiveZeroRttChecker { } fn zero_rtt_setup(mode: Resumption, client: &Client, server: &mut Server) -> Option { - if matches!(mode, Resumption::WithZeroRtt) { + matches!(mode, Resumption::WithZeroRtt).then(|| { client.enable_0rtt().expect("should enable 0-RTT on client"); let anti_replay = anti_replay(); @@ -127,10 +127,8 @@ fn zero_rtt_setup(mode: Resumption, client: &Client, server: &mut Server) -> Opt Box::new(PermissiveZeroRttChecker { resuming: false }), ) .expect("should enable 0-RTT on server"); - Some(anti_replay) - } else { - None - } + anti_replay + }) } #[allow(clippy::missing_panics_doc)] diff --git a/third_party/rust/neqo-crypto/tests/hp.rs b/third_party/rust/neqo-crypto/tests/hp.rs index 1a3c39e1d743..4524720e14bc 100644 --- a/third_party/rust/neqo-crypto/tests/hp.rs +++ b/third_party/rust/neqo-crypto/tests/hp.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; - use neqo_crypto::{ constants::{ Cipher, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, @@ -71,12 +69,12 @@ fn chacha20_ctr() { #[should_panic(expected = "out of range")] fn aes_short() { let hp = make_hp(TLS_AES_128_GCM_SHA256); - mem::drop(hp.mask(&[0; 15])); + drop(hp.mask(&[0; 15])); } #[test] #[should_panic(expected = "out of range")] fn chacha20_short() { let hp = make_hp(TLS_CHACHA20_POLY1305_SHA256); - mem::drop(hp.mask(&[0; 15])); + drop(hp.mask(&[0; 15])); } diff --git a/third_party/rust/neqo-http3/.cargo-checksum.json b/third_party/rust/neqo-http3/.cargo-checksum.json index 57bcecfbf605..1631a86d3706 100644 --- a/third_party/rust/neqo-http3/.cargo-checksum.json +++ b/third_party/rust/neqo-http3/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"98ce446932fc062c3a45558e73380b08d0dfbeac321ed0111a62062720451b6f","src/buffered_send_stream.rs":"dfb248c66ea65418b0c7798c2ecaa3ed70ef1af818ef58d53ef742b3445077b7","src/client_events.rs":"77fedca72ce54956eaba3fb7103085d196a631b764662584ea2629224c5c234e","src/conn_params.rs":"7f0df52bceda1923aef2b7c5c64a532f49ea083ea45e3dcd5bd4b03031b89643","src/connection.rs":"c82b016f839c5d3b1ec24cd76b372aec4f0e832ed68d792171579f9e649b3824","src/connection_client.rs":"a27423973be27501bb8e8ae169938fa215322fa78f7f5b95cb418adc6fa8b7a1","src/connection_server.rs":"cf4da2cdd823e31d2352e45de84d366c45bd3d8adf38c9151a84d808bda80209","src/control_stream_local.rs":"20917762c7e7c1112c56abf1cbaf0ad7f0eab97d8db9a3b10ff524315a235670","src/control_stream_remote.rs":"3729f67aa0681b1dbd4147063890f8440f27d82454776500ae964a17cda4d6b5","src/features/extended_connect/mod.rs":"f9a08a6ec1dde79133c18c21b85f6b9a01468d98bace838f559340383cc603e7","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"51d6f3828c44b438eb1776e8dcce531af520f28bc0d715807d3f53a0eaa071d1","src/features/extended_connect/tests/webtransport/mod.rs":"7828af3887acc5b141ec1af459069eeb4f2d95e7c9e5639047006c179ce6a355","src/features/extended_connect/tests/webtransport/negotiation.rs":"6ddb604a0aa521335ab84ff07718e485f926a27da730d5697c33d6df62af39d6","src/features/extended_connect/tests/webtransport/sessions.rs":"6ed8c6247a84916cf6bb6dc4eeded20f1d80c6d2ea8f256975786c5f3ab2efcb","src/features/extended_connect/tests/webtransport/streams.rs":"eab84efc920b766ea105a47d34bec565f79f64f6c6be1b7f4945d78bddb462fd","src/features/extended_connect/webtransport_session.rs":"debe63b81c8c3c49da9f2b9abb92ea05fb95745a8ee725a956dfeffa53dc9574","src/features/extended_connect/webtransport_streams.rs":"9855d77705acb7d21566333c4b297816e363be2ade14b8685fd1df4a4861cf74","src/features/mod.rs":"89056df3a868cb0037963c942fc27093cc16d84538ffca2d4759f9a6a6c74c7f","src/frames/hframe.rs":"de2c3d1a9205b0459fe676d7d5e1c0e463d3c1dd9e5f518a07b2e4ebbe66e3ec","src/frames/mod.rs":"0e6d49888d723b2c2c73df11020ceb88d9f062e9d4dc436eb38173e0b772d905","src/frames/reader.rs":"01acff3c6bb9d2a0c2ff68b054276fab8d61a47679bec9084d75c4f680a959b3","src/frames/tests/hframe.rs":"53941fd7656f5e424d499278e6d9ba93ce716f219e86fe6fa08c058ea92f8d7b","src/frames/tests/mod.rs":"6cb78d24bbab27f877d0526deb3e9a26694a23a9ce8ebe664947a852a3d92747","src/frames/tests/reader.rs":"6fb66c7a03acfc2e231e7bb3d020c902b59366a7523e488d118b24440ac68501","src/frames/tests/wtframe.rs":"c6598d24f5e12972f02de6e1394362671633982db637a07e1c0bb9b56d93ea2a","src/frames/wtframe.rs":"0f0366e590f7409580459e8a8b86fc48308ca7585837dddd7c319581a9a5a972","src/headers_checks.rs":"69964deb121721be01df7174c177543c161389295ce1450d348369279e312ba4","src/lib.rs":"3fb980eee46bee8dcb97ad9d55014555d8994a7a2d040ca223f2d28fe7d923ef","src/priority.rs":"946307329f31819d969093406ae5448f7923343ccc112221ea6eedf86cf447dc","src/push_controller.rs":"7f8b668d7ff16372693830ac4d3e6834e77465762a0a8d77ab7f9e883c2fb919","src/qlog.rs":"85187b6eee73d0ce085bc42dfc30999f4a51f92daa02a1a1ac1228a490131082","src/qpack_decoder_receiver.rs":"eb06c4be59da567fef70c20daa2c0f165c768131165479a210e69659f168b88f","src/qpack_encoder_receiver.rs":"831f3da9ec17966286786ba3f2c723395a132e65d6a33b4ec341fe7640c1a53d","src/recv_message.rs":"8b2fb49850560b32dcdd7a90933361ef7d61bc42daad3f2952462913d49e8787","src/request_target.rs":"9720b9f87d66a7c2301bba7de5a5a9300f547613a63153a4d35c7a7506a59b31","src/send_message.rs":"be4e9f64db2c25eb7176b84695e608e768115d62e615d389a33d26f7cd5b0c6c","src/server.rs":"c6a231fea182acd4f7e064578a1ad85a5fa0f618f3e0842d499f84f841bbf9da","src/server_connection_events.rs":"1396baab265a814045ccfe63d637a4fdc32a667b5eb2925fa4951f5c3078fb20","src/server_events.rs":"02fc8c0711efd758fb1ddee27d257c12ed35e2a989e7bf3de44bd662dc8234e3","src/settings.rs":"d0f8c546e70161422a029a40564b9e9b953fe671c60835196b16f3364779eaf9","src/stream_type_reader.rs":"115d50bbaa304a74d601614b755bcb626572ab89d5db7bfae9fff8ad64270722","tests/httpconn.rs":"72b4f66fc9b9efeb070907da35f1db2d320d232ef74380fd36ad7c2ddd213076","tests/priority.rs":"3b0e03d6a8fbde52c695130bb3e40d3b70cb74ee826af28db577060911bcbc03","tests/send_message.rs":"9540259485e8b7df1d07ff8abdc8cb86d5f32d736aea3bce28e8b0ecc00a9f5b","tests/webtransport.rs":"3bfcfddd57a8fe262c597b756982d671065a593d99d09d42b04f954a27a2a5fa"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"a3bea7b8e1efb0a5a78f4184ffa79bc436836b516e34d313bab8f450cdfb02df","src/buffered_send_stream.rs":"d74c520af97bcdaa48862a396e6510c9f95124358dcf46a7722e4daf821fff2c","src/client_events.rs":"96d38deba366edbbe5f6e73d56d74ae36e239e35393ae3ac094d73063b564f68","src/conn_params.rs":"7f0df52bceda1923aef2b7c5c64a532f49ea083ea45e3dcd5bd4b03031b89643","src/connection.rs":"d225b55f1229988568085f133dac1cfe5d4adfd91864a7e1fc344a784a4b5594","src/connection_client.rs":"9a48949fe885e1139ae2c056a5504a3e336c8d75aae4cdcc2ad92355ad5aa623","src/connection_server.rs":"d16f73685ae29492e2d32321158b6206349fe1b0016d89bc50c2727f47c64140","src/control_stream_local.rs":"9325e5c8857036c68f7e49b81c898d5de51d43cb262e523385e6b2b7366c2cea","src/control_stream_remote.rs":"e7d0b5a195e3ef482b36972eac979b7d761215fcb76699112f2d4919708fcf26","src/features/extended_connect/mod.rs":"f9a08a6ec1dde79133c18c21b85f6b9a01468d98bace838f559340383cc603e7","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"51d6f3828c44b438eb1776e8dcce531af520f28bc0d715807d3f53a0eaa071d1","src/features/extended_connect/tests/webtransport/mod.rs":"9c0de1da3cfe9fac75f2d2faf3e0e0500261519e7862c6b5fec5097ab47f72f1","src/features/extended_connect/tests/webtransport/negotiation.rs":"8b505384d5b8a9c8e17194360a33d9ecbdb350c3359245b9f2bed9dc8cec7423","src/features/extended_connect/tests/webtransport/sessions.rs":"64b29ec9ba34e636b1109d99ab588666d85c85442565faa9071b743f4f764d6e","src/features/extended_connect/tests/webtransport/streams.rs":"eb0e793dc43ca9296334d29ced70d5ab3d90fd0c4ca3a485abad06c14eec29a4","src/features/extended_connect/webtransport_session.rs":"09a06af84e101f628f1ff2e9be344463662212f2d8914fe84b9675d9f0488af5","src/features/extended_connect/webtransport_streams.rs":"9855d77705acb7d21566333c4b297816e363be2ade14b8685fd1df4a4861cf74","src/features/mod.rs":"6f192996e6e2231a97f3fcae2aa02d648e571a6ec5e14b4a23b24b87888d117c","src/frames/hframe.rs":"5fcd9145a88e8ebf9ec1832c8ab61357a9afd362690e26d5a32595b2ae135395","src/frames/mod.rs":"0e6d49888d723b2c2c73df11020ceb88d9f062e9d4dc436eb38173e0b772d905","src/frames/reader.rs":"fff71d4e5a75ac16ed455c5cb7a12f355d56fe8bf7b33d6fb160e4bc48ee94cd","src/frames/tests/hframe.rs":"43a7735fc859692633e7f3c031710a9fb635611756cb4b9f387bac0a38c0fa09","src/frames/tests/mod.rs":"ee2eb2d88132e500640b156d5ae6b6ef5051e86eae09464a9cec827142ef6b73","src/frames/tests/reader.rs":"eaff7faa62aec5caf2ed21c6bd9e869654433b030df7676cc4843e2b15d1a6c1","src/frames/tests/wtframe.rs":"c6598d24f5e12972f02de6e1394362671633982db637a07e1c0bb9b56d93ea2a","src/frames/wtframe.rs":"544bc8fa74e3b15cde6e45ba47bcc52f098658e78664abfda8249a89c88d51b9","src/headers_checks.rs":"42f5bb95c6af9d7e747b3b4e39a2b10c4a323abd7da30cd4db4ebbc47696e060","src/lib.rs":"1fd024d8ec7fed5c4766f8a817531b1a4363bd2eaa60f9a41e4c2fed84682308","src/priority.rs":"946307329f31819d969093406ae5448f7923343ccc112221ea6eedf86cf447dc","src/push_controller.rs":"a03aa8b1e2db588f4342337252e7b7d10f43447498ddbc95733b5304a8e717ab","src/push_id.rs":"cd4cea3102b59918668b66725bbd19b66dc389e35d986132c5ceb72bbc9f3222","src/qlog.rs":"85187b6eee73d0ce085bc42dfc30999f4a51f92daa02a1a1ac1228a490131082","src/qpack_decoder_receiver.rs":"eb06c4be59da567fef70c20daa2c0f165c768131165479a210e69659f168b88f","src/qpack_encoder_receiver.rs":"831f3da9ec17966286786ba3f2c723395a132e65d6a33b4ec341fe7640c1a53d","src/recv_message.rs":"279c1de34d13bc43cfd5c622956d9a1a7e24153918b029c45c0358f384fef8fd","src/request_target.rs":"9720b9f87d66a7c2301bba7de5a5a9300f547613a63153a4d35c7a7506a59b31","src/send_message.rs":"16e688bcffe7aefa43bb5876cdad1f79b9227acad8695afc64f47c1565933e69","src/server.rs":"86c0a012b5dcb4d7c9de69360bf004dd30d75c7827b4cd60c282ca89c7bb2ed3","src/server_connection_events.rs":"1396baab265a814045ccfe63d637a4fdc32a667b5eb2925fa4951f5c3078fb20","src/server_events.rs":"26f3d3585633296a62c3e1e8594e491f45e4c6d17c3cd75847c3cdec5778c2e1","src/settings.rs":"d0f8c546e70161422a029a40564b9e9b953fe671c60835196b16f3364779eaf9","src/stream_type_reader.rs":"5ba77600c5e8c4abdd9443aec20311cf8a812b97ab18a90408aa4e689f42bded","tests/httpconn.rs":"5e2318ac776ce8b4c0d3c44b42fc32e6609b2ef31853767312462eae9a7c659d","tests/priority.rs":"f3869e5fbf63483f04b589d3447e02a4f167b2f3c406028cb30a87ad9a22da53","tests/send_message.rs":"21de05a3c6d516d28df6d77d7e4fb1b05985fc2debde1e8c7fb0607164c74b75","tests/webtransport.rs":"4ae2531c8384120b541198757106954b1dac9f2dcb39ed2231a67a59c1fb94f8"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-http3/Cargo.toml b/third_party/rust/neqo-http3/Cargo.toml index 1ffe903fd361..4abaf979de02 100644 --- a/third_party/rust/neqo-http3/Cargo.toml +++ b/third_party/rust/neqo-http3/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "neqo-http3" -version = "0.11.0" +version = "0.12.2" authors = ["The Neqo Authors "] build = false autolib = false @@ -39,6 +39,9 @@ categories = [ license = "MIT OR Apache-2.0" repository = "https://github.com/mozilla/neqo/" +[package.metadata.cargo-machete] +ignored = ["log"] + [lib] name = "neqo_http3" path = "src/lib.rs" @@ -93,17 +96,47 @@ version = "2.5.3" features = ["std"] default-features = false +[dev-dependencies.neqo-http3] +path = "." +features = ["draft-29"] + +[dev-dependencies.neqo-transport] +path = "./../neqo-transport" +features = ["draft-29"] + [dev-dependencies.test-fixture] path = "../test-fixture" [features] +bench = [ + "neqo-common/bench", + "neqo-crypto/bench", + "neqo-qpack/bench", + "neqo-transport/bench", +] disable-encryption = [ "neqo-transport/disable-encryption", "neqo-crypto/disable-encryption", ] +draft-29 = [] [lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" [lints.clippy.cargo] level = "warn" @@ -116,3 +149,19 @@ priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/neqo-http3/src/buffered_send_stream.rs b/third_party/rust/neqo-http3/src/buffered_send_stream.rs index c4a0a3087bb4..292a1495fea1 100644 --- a/third_party/rust/neqo-http3/src/buffered_send_stream.rs +++ b/third_party/rust/neqo-http3/src/buffered_send_stream.rs @@ -49,7 +49,7 @@ impl BufferedStream { /// # Panics /// - /// This functon cannot be called before the `BufferedStream` is initialized. + /// This function cannot be called before the `BufferedStream` is initialized. pub fn buffer(&mut self, to_buf: &[u8]) { if let Self::Initialized { buf, .. } = self { buf.extend_from_slice(to_buf); @@ -62,14 +62,14 @@ impl BufferedStream { /// /// Returns `neqo_transport` errors. pub fn send_buffer(&mut self, conn: &mut Connection) -> Res { - let label = ::neqo_common::log_subject!(::log::Level::Debug, self); + let label = format!("{self}"); let Self::Initialized { stream_id, buf } = self else { return Ok(0); }; if buf.is_empty() { return Ok(0); } - qtrace!([label], "sending data."); + qtrace!("[{label}] sending data"); let sent = conn.stream_send(*stream_id, &buf[..])?; if sent == 0 { return Ok(0); diff --git a/third_party/rust/neqo-http3/src/client_events.rs b/third_party/rust/neqo-http3/src/client_events.rs index 61aba8f9f121..6efabcb4a346 100644 --- a/third_party/rust/neqo-http3/src/client_events.rs +++ b/third_party/rust/neqo-http3/src/client_events.rs @@ -16,7 +16,7 @@ use crate::{ connection::Http3State, features::extended_connect::{ExtendedConnectEvents, ExtendedConnectType, SessionCloseReason}, settings::HSettingType, - CloseType, Http3StreamInfo, HttpRecvStreamEvents, RecvStreamEvents, SendStreamEvents, + CloseType, Http3StreamInfo, HttpRecvStreamEvents, PushId, RecvStreamEvents, SendStreamEvents, }; #[derive(Debug, PartialEq, Eq, Clone)] @@ -68,24 +68,24 @@ pub enum Http3ClientEvent { }, /// A new push promise. PushPromise { - push_id: u64, + push_id: PushId, request_stream_id: StreamId, headers: Vec
, }, /// A push response headers are ready. PushHeaderReady { - push_id: u64, + push_id: PushId, headers: Vec
, interim: bool, fin: bool, }, /// New bytes are available on a push stream for reading. - PushDataReadable { push_id: u64 }, + PushDataReadable { push_id: PushId }, /// A push has been canceled. - PushCanceled { push_id: u64 }, + PushCanceled { push_id: PushId }, /// A push stream was been reset due to a `HttpGeneralProtocol` error. /// Most common case are malformed response headers. - PushReset { push_id: u64, error: AppError }, + PushReset { push_id: PushId, error: AppError }, /// New stream can be created RequestsCreatable, /// Cert authentication needed @@ -196,7 +196,7 @@ impl ExtendedConnectEvents for Http3ClientEvents { headers, })); } else { - unreachable!("There is only ExtendedConnectType::WebTransport."); + unreachable!("There is only ExtendedConnectType::WebTransport"); } } @@ -216,7 +216,7 @@ impl ExtendedConnectEvents for Http3ClientEvents { }, )); } else { - unreachable!("There are no other types."); + unreachable!("There are no other types"); } } @@ -240,7 +240,7 @@ impl ExtendedConnectEvents for Http3ClientEvents { } impl Http3ClientEvents { - pub fn push_promise(&self, push_id: u64, request_stream_id: StreamId, headers: Vec
) { + pub fn push_promise(&self, push_id: PushId, request_stream_id: StreamId, headers: Vec
) { self.insert(Http3ClientEvent::PushPromise { push_id, request_stream_id, @@ -248,12 +248,12 @@ impl Http3ClientEvents { }); } - pub fn push_canceled(&self, push_id: u64) { + pub fn push_canceled(&self, push_id: PushId) { self.remove_events_for_push_id(push_id); self.insert(Http3ClientEvent::PushCanceled { push_id }); } - pub fn push_reset(&self, push_id: u64, error: AppError) { + pub fn push_reset(&self, push_id: PushId, error: AppError) { self.remove_events_for_push_id(push_id); self.insert(Http3ClientEvent::PushReset { push_id, error }); } @@ -336,7 +336,7 @@ impl Http3ClientEvents { }); } - pub fn has_push(&self, push_id: u64) -> bool { + pub fn has_push(&self, push_id: PushId) -> bool { for iter in &*self.events.borrow() { if matches!(iter, Http3ClientEvent::PushPromise{push_id:x, ..} if *x == push_id) { return true; @@ -345,7 +345,7 @@ impl Http3ClientEvents { false } - pub fn remove_events_for_push_id(&self, push_id: u64) { + pub fn remove_events_for_push_id(&self, push_id: PushId) { self.remove(|evt| { matches!(evt, Http3ClientEvent::PushPromise{ push_id: x, .. } diff --git a/third_party/rust/neqo-http3/src/connection.rs b/third_party/rust/neqo-http3/src/connection.rs index 3a6698aa204e..5d977fc3887c 100644 --- a/third_party/rust/neqo-http3/src/connection.rs +++ b/third_party/rust/neqo-http3/src/connection.rs @@ -35,7 +35,7 @@ use crate::{ qpack_decoder_receiver::DecoderRecvStream, qpack_encoder_receiver::EncoderRecvStream, recv_message::{RecvMessage, RecvMessageInfo}, - request_target::{AsRequestTarget, RequestTarget}, + request_target::{AsRequestTarget, RequestTarget as _}, send_message::SendMessage, settings::{HSettingType, HSettings, HttpZeroRttChecker}, stream_type_reader::NewStreamHeadReader, @@ -159,7 +159,7 @@ The API consists of: Each `Http3Connection` holds a list of stream handlers. Each send and receive-handler is registered in `send_streams` and `recv_streams`. Unidirectional streams are registered only on one of the lists and bidirectional streams are registered in both lists and the 2 handlers are independent, e.g. one -can be closed and removed ane second may still be active. +can be closed and removed and second may still be active. The only streams that are not registered are the local control stream, local QPACK decoder stream, and local QPACK encoder stream. These streams are send-streams and sending data on this stream is @@ -195,7 +195,7 @@ are local or remote: type has been decoded. After this point the stream: - will be regegistered with the appropriate handler, - will be canceled if is an unknown stream type or - - the connection will fail if it is unallowed stream type (receiveing HTTP request on the + - the connection will fail if it is unallowed stream type (receiving HTTP request on the client-side). The output is handled in `handle_new_stream`, for control, qpack streams and partially @@ -277,12 +277,12 @@ For example for `Http` stream the listener will produce `HeaderReady` and `Da A `WebTransport` session is connected to a control stream that is in essence an HTTP transaction. Therefore, `WebTransportSession` will internally use a `SendMessage` and `RecvMessage` handler to -handle parsing and sending of HTTP part of the control stream. When HTTP headers are exchenged, +handle parsing and sending of HTTP part of the control stream. When HTTP headers are exchanged, `WebTransportSession` will take over handling of stream data. `WebTransportSession` sets `WebTransportSessionListener` as the `RecvMessage` event listener. `WebTransportSendStream` and `WebTransportRecvStream` are associated with a `WebTransportSession` -and they will be canceled if the session is closed. To be avle to do this `WebTransportSession` +and they will be canceled if the session is closed. To be able to do this `WebTransportSession` holds a list of its active streams and clean up is done in `remove_extended_connect`. ### `WebTransportSendStream` and `WebTransportRecvStream` @@ -352,7 +352,7 @@ impl Http3Connection { /// This function creates and initializes, i.e. send stream type, the control and qpack /// streams. fn initialize_http3_connection(&mut self, conn: &mut Connection) -> Res<()> { - qdebug!([self], "Initialize the http3 connection."); + qdebug!("[{self}] Initialize the http3 connection"); self.control_stream_local.create(conn)?; self.send_settings(); @@ -361,7 +361,7 @@ impl Http3Connection { } fn send_settings(&mut self) { - qdebug!([self], "Send settings."); + qdebug!("[{self}] Send settings"); self.control_stream_local.queue_frame(&HFrame::Settings { settings: HSettings::from(&self.local_params), }); @@ -374,7 +374,7 @@ impl Http3Connection { } fn create_qpack_streams(&self, conn: &mut Connection) -> Res<()> { - qdebug!([self], "create_qpack_streams."); + qdebug!("[{self}] create_qpack_streams"); self.qpack_encoder .borrow_mut() .add_send_stream(conn.stream_create(StreamType::UniDi)?); @@ -458,7 +458,7 @@ impl Http3Connection { /// This is called when a `ConnectionEvent::NewStream` event is received. This register the /// stream with a `NewStreamHeadReader` handler. pub fn add_new_stream(&mut self, stream_id: StreamId) { - qtrace!([self], "A new stream: {}.", stream_id); + qtrace!("[{self}] A new stream: {stream_id}"); self.recv_streams.insert( stream_id, Box::new(NewStreamHeadReader::new(stream_id, self.role)), @@ -468,7 +468,7 @@ impl Http3Connection { /// The function calls `receive` for a stream. It also deals with the outcome of a read by /// calling `handle_stream_manipulation_output`. fn stream_receive(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res { - qtrace!([self], "Readable stream {}.", stream_id); + qtrace!("[{self}] Readable stream {stream_id}"); if let Some(recv_stream) = self.recv_streams.get_mut(&stream_id) { let res = recv_stream.receive(conn); @@ -485,7 +485,7 @@ impl Http3Connection { conn: &mut Connection, ) -> Res<()> { for stream_id in unblocked_streams { - qdebug!([self], "Stream {} is unblocked", stream_id); + qdebug!("[{self}] Stream {stream_id} is unblocked"); if let Some(r) = self.recv_streams.get_mut(&stream_id) { let res = r .http_stream() @@ -501,7 +501,7 @@ impl Http3Connection { /// This function handles reading from all streams, i.e. control, qpack, request/response /// stream and unidi stream that are still do not have a type. /// The function cannot handle: - /// 1) a `Push(_)`, `Htttp` or `WebTransportStream(_)` stream + /// 1) a `Push(_)`, `Http` or `WebTransportStream(_)` stream /// 2) frames `MaxPushId`, `PriorityUpdateRequest`, `PriorityUpdateRequestPush` or `Goaway` must /// be handled by `Http3Client`/`Server`. /// @@ -551,12 +551,7 @@ impl Http3Connection { app_error: AppError, conn: &mut Connection, ) -> Res<()> { - qinfo!( - [self], - "Handle a stream reset stream_id={} app_err={}", - stream_id, - app_error - ); + qinfo!("[{self}] Handle a stream reset stream_id={stream_id} app_err={app_error}"); self.close_recv(stream_id, CloseType::ResetRemote(app_error), conn) } @@ -567,12 +562,7 @@ impl Http3Connection { app_error: AppError, conn: &mut Connection, ) -> Res<()> { - qinfo!( - [self], - "Handle stream_stop_sending stream_id={} app_err={}", - stream_id, - app_error - ); + qinfo!("[{self}] Handle stream_stop_sending stream_id={stream_id} app_err={app_error}"); if self.send_stream_is_critical(stream_id) { return Err(Error::HttpClosedCriticalStream); @@ -585,7 +575,7 @@ impl Http3Connection { /// This is called when `neqo_transport::Connection` state has been change to take proper /// actions in the HTTP3 layer. pub fn handle_state_change(&mut self, conn: &mut Connection, state: &State) -> Res { - qdebug!([self], "Handle state change {:?}", state); + qdebug!("[{self}] Handle state change {state:?}"); match state { State::Handshaking => { if self.role == Role::Server @@ -649,7 +639,7 @@ impl Http3Connection { self.recv_streams.clear(); Ok(()) } else { - debug_assert!(false, "Zero rtt rejected in the wrong state."); + debug_assert!(false, "Zero rtt rejected in the wrong state"); Err(Error::HttpInternal(3)) } } @@ -696,15 +686,10 @@ impl Http3Connection { } NewStreamType::Push(push_id) => { - qinfo!( - [self], - "A new push stream {} push_id:{}.", - stream_id, - push_id - ); + qinfo!("[{self}] A new push stream {stream_id} push_id:{push_id}"); } NewStreamType::Decoder => { - qdebug!([self], "A new remote qpack encoder stream {}", stream_id); + qdebug!("[{self}] A new remote qpack encoder stream {stream_id}"); self.check_stream_exists(Http3StreamType::Decoder)?; self.recv_streams.insert( stream_id, @@ -715,7 +700,7 @@ impl Http3Connection { ); } NewStreamType::Encoder => { - qdebug!([self], "A new remote qpack decoder stream {}", stream_id); + qdebug!("[{self}] A new remote qpack decoder stream {stream_id}"); self.check_stream_exists(Http3StreamType::Encoder)?; self.recv_streams.insert( stream_id, @@ -726,7 +711,7 @@ impl Http3Connection { ); } NewStreamType::Http(_) => { - qinfo!([self], "A new http stream {}.", stream_id); + qinfo!("[{self}] A new http stream {stream_id}"); } NewStreamType::WebTransportStream(session_id) => { let session_exists = self @@ -737,14 +722,13 @@ impl Http3Connection { conn.stream_stop_sending(stream_id, Error::HttpStreamCreation.code())?; return Ok(ReceiveOutput::NoOutput); } - // set incoming WebTransport streams to be fair (share bandwidth) - conn.stream_fairness(stream_id, true).ok(); - qinfo!( - [self], - "A new WebTransport stream {} for session {}.", - stream_id, - session_id - ); + // Set incoming WebTransport streams to be fair (share bandwidth). + // We may call this with an invalid stream ID, so ignore that error. + match conn.stream_fairness(stream_id, true) { + Ok(()) | Err(neqo_transport::Error::InvalidStreamId) => (), + Err(e) => return Err(Error::from(e)), + }; + qinfo!("[{self}] A new WebTransport stream {stream_id} for session {session_id}"); } NewStreamType::Unknown => { conn.stream_stop_sending(stream_id, Error::HttpStreamCreation.code())?; @@ -764,7 +748,7 @@ impl Http3Connection { /// This is called when an application closes the connection. pub fn close(&mut self, error: AppError) { - qdebug!([self], "Close connection error {:?}.", error); + qdebug!("[{self}] Close connection error {error:?}"); self.state = Http3State::Closing(CloseReason::Application(error)); if (!self.send_streams.is_empty() || !self.recv_streams.is_empty()) && (error == 0) { qwarn!("close(0) called when streams still active"); @@ -805,7 +789,7 @@ impl Http3Connection { Ok((_, false)) => {} Err(e) => { if e.stream_reset_error() && !self.recv_stream_is_critical(stream_id) { - mem::drop(conn.stream_stop_sending(stream_id, e.code())); + drop(conn.stream_stop_sending(stream_id, e.code())); self.close_recv(stream_id, CloseType::LocalError(e.code()), conn)?; return Ok((U::default(), false)); } @@ -850,8 +834,7 @@ impl Http3Connection { T: AsRequestTarget<'t> + ?Sized + Debug, { qinfo!( - [self], - "Fetch method={} target: {:?}", + "[{self}] Fetch method={} target: {:?}", request.method, request.target, ); @@ -902,7 +885,7 @@ impl Http3Connection { MessageType::Request, stream_type, stream_id, - self.qpack_encoder.clone(), + Rc::clone(&self.qpack_encoder), send_events, ); @@ -951,7 +934,7 @@ impl Http3Connection { stream_id: StreamId, buf: &mut [u8], ) -> Res<(usize, bool)> { - qdebug!([self], "read_data from stream {}.", stream_id); + qdebug!("[{self}] read_data from stream {stream_id}"); let res = self .recv_streams .get_mut(&stream_id) @@ -968,12 +951,7 @@ impl Http3Connection { stream_id: StreamId, error: AppError, ) -> Res<()> { - qinfo!( - [self], - "Reset sending side of stream {} error={}.", - stream_id, - error - ); + qinfo!("[{self}] Reset sending side of stream {stream_id} error={error}"); if self.send_stream_is_critical(stream_id) { return Err(Error::InvalidStreamId); @@ -990,12 +968,7 @@ impl Http3Connection { stream_id: StreamId, error: AppError, ) -> Res<()> { - qinfo!( - [self], - "Send stop sending for stream {} error={}.", - stream_id, - error - ); + qinfo!("[{self}] Send stop sending for stream {stream_id} error={error}"); if self.recv_stream_is_critical(stream_id) { return Err(Error::InvalidStreamId); } @@ -1043,7 +1016,7 @@ impl Http3Connection { error: AppError, conn: &mut Connection, ) -> Res<()> { - qinfo!([self], "cancel_fetch {} error={}.", stream_id, error); + qinfo!("[{self}] cancel_fetch {stream_id} error={error}"); let send_stream = self.send_streams.get(&stream_id); let recv_stream = self.recv_streams.get(&stream_id); match (send_stream, recv_stream) { @@ -1056,7 +1029,7 @@ impl Http3Connection { return Err(Error::InvalidStreamId); } // Stream may be already be closed and we may get an error here, but we do not care. - mem::drop(self.stream_reset_send(conn, stream_id, error)); + drop(self.stream_reset_send(conn, stream_id, error)); } (None, Some(s)) => { if !matches!( @@ -1069,7 +1042,7 @@ impl Http3Connection { } // Stream may be already be closed and we may get an error here, but we do not care. - mem::drop(self.stream_stop_sending(conn, stream_id, error)); + drop(self.stream_stop_sending(conn, stream_id, error)); } (Some(s), Some(r)) => { debug_assert_eq!(s.stream_type(), r.stream_type()); @@ -1080,9 +1053,9 @@ impl Http3Connection { return Err(Error::InvalidStreamId); } // Stream may be already be closed and we may get an error here, but we do not care. - mem::drop(self.stream_reset_send(conn, stream_id, error)); + drop(self.stream_reset_send(conn, stream_id, error)); // Stream may be already be closed and we may get an error here, but we do not care. - mem::drop(self.stream_stop_sending(conn, stream_id, error)); + drop(self.stream_stop_sending(conn, stream_id, error)); } } Ok(()) @@ -1090,7 +1063,7 @@ impl Http3Connection { /// This is called when an application wants to close the sending side of a stream. pub fn stream_close_send(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res<()> { - qdebug!([self], "Close the sending side for stream {}.", stream_id); + qdebug!("[{self}] Close the sending side for stream {stream_id}"); debug_assert!(self.state.active()); let send_stream = self .send_streams @@ -1098,7 +1071,7 @@ impl Http3Connection { .ok_or(Error::InvalidStreamId)?; // The following function may return InvalidStreamId from the transport layer if the stream // has been closed already. It is ok to ignore it here. - mem::drop(send_stream.close(conn)); + drop(send_stream.close(conn)); if send_stream.done() { self.remove_send_stream(stream_id, conn); } else if send_stream.has_data_to_send() { @@ -1117,7 +1090,7 @@ impl Http3Connection { where T: AsRequestTarget<'x> + ?Sized + Debug, { - qinfo!([self], "Create WebTransport"); + qinfo!("[{self}] Create WebTransport"); if !self.webtransport_enabled() { return Err(Error::Unavailable); } @@ -1133,8 +1106,8 @@ impl Http3Connection { ))); self.add_streams( id, - Box::new(extended_conn.clone()), - Box::new(extended_conn.clone()), + Box::new(Rc::clone(&extended_conn)), + Box::new(Rc::clone(&extended_conn)), ); let final_headers = Self::create_fetch_headers(&RequestDescription { @@ -1158,10 +1131,7 @@ impl Http3Connection { events: Box, accept_res: &WebTransportSessionAcceptAction, ) -> Res<()> { - qtrace!( - "Respond to WebTransport session with accept={}.", - accept_res - ); + qtrace!("Respond to WebTransport session with accept={accept_res}"); if !self.webtransport_enabled() { return Err(Error::Unavailable); } @@ -1177,6 +1147,7 @@ impl Http3Connection { } let send_stream = self.send_streams.get_mut(&stream_id); + conn.stream_keep_alive(stream_id, true)?; match (send_stream, recv_stream, accept_res) { (None, None, _) => Err(Error::InvalidStreamId), @@ -1191,7 +1162,7 @@ impl Http3Connection { .send_headers(headers, conn) .is_ok() { - mem::drop(self.stream_close_send(conn, stream_id)); + drop(self.stream_close_send(conn, stream_id)); // TODO issue 1294: add a timer to clean up the recv_stream if the peer does not // do that in a short time. self.streams_with_pending_data.insert(stream_id); @@ -1216,7 +1187,7 @@ impl Http3Connection { ))); self.add_streams( stream_id, - Box::new(extended_conn.clone()), + Box::new(Rc::clone(&extended_conn)), Box::new(extended_conn), ); self.streams_with_pending_data.insert(stream_id); @@ -1236,7 +1207,7 @@ impl Http3Connection { error: u32, message: &str, ) -> Res<()> { - qtrace!("Clos WebTransport session {:?}", session_id); + qtrace!("Close WebTransport session {session_id:?}"); let send_stream = self .send_streams .get_mut(&session_id) @@ -1262,11 +1233,7 @@ impl Http3Connection { send_events: Box, recv_events: Box, ) -> Res { - qtrace!( - "Create new WebTransport stream session={} type={:?}", - session_id, - stream_type - ); + qtrace!("Create new WebTransport stream session={session_id} type={stream_type:?}"); let wt = self .recv_streams @@ -1282,8 +1249,7 @@ impl Http3Connection { .stream_create(stream_type) .map_err(|e| Error::map_stream_create_errors(&e))?; // Set outgoing WebTransport streams to be fair (share bandwidth) - // This really can't fail, panics if it does - conn.stream_fairness(stream_id, true).unwrap(); + conn.stream_fairness(stream_id, true)?; self.webtransport_create_stream_internal( wt, @@ -1303,11 +1269,7 @@ impl Http3Connection { send_events: Box, recv_events: Box, ) -> Res<()> { - qtrace!( - "Create new WebTransport stream session={} stream_id={}", - session_id, - stream_id - ); + qtrace!("Create new WebTransport stream session={session_id} stream_id={stream_id}"); let wt = self .recv_streams @@ -1336,7 +1298,6 @@ impl Http3Connection { recv_events: Box, local: bool, ) { - // TODO conn.stream_keep_alive(stream_id, true)?; webtransport_session.borrow_mut().add_stream(stream_id); if stream_id.stream_type() == StreamType::UniDi { if local { @@ -1368,7 +1329,7 @@ impl Http3Connection { stream_id, session_id, send_events, - webtransport_session.clone(), + Rc::clone(&webtransport_session), local, )), Box::new(WebTransportRecvStream::new( @@ -1401,7 +1362,7 @@ impl Http3Connection { /// `PriorityUpdateRequestPush` which handling is specific to the client and server, we must /// give them to the specific client/server handler. fn handle_control_frame(&mut self, f: HFrame) -> Res> { - qdebug!([self], "Handle a control frame {:?}", f); + qdebug!("[{self}] Handle a control frame {f:?}"); if !matches!(f, HFrame::Settings { .. }) && !matches!( self.settings_state, @@ -1432,7 +1393,7 @@ impl Http3Connection { } fn handle_settings(&mut self, new_settings: HSettings) -> Res<()> { - qdebug!([self], "Handle SETTINGS frame."); + qdebug!("[{self}] Handle SETTINGS frame"); match &self.settings_state { Http3RemoteSettingsState::NotReceived => { self.set_qpack_settings(&new_settings)?; @@ -1455,11 +1416,7 @@ impl Http3Connection { } if zero_rtt_value > new_value { qerror!( - [self], - "The new({}) and the old value({}) of setting {:?} do not match", - new_value, - zero_rtt_value, - st + "[{self}] The new({new_value}) and the old value({zero_rtt_value}) of setting {st:?} do not match" ); return Err(Error::HttpSettings); } @@ -1478,7 +1435,7 @@ impl Http3Connection { } } if qpack_changed { - qdebug!([self], "Settings after zero rtt differ."); + qdebug!("[{self}] Settings after zero rtt differ"); self.set_qpack_settings(&(new_settings))?; } self.settings_state = Http3RemoteSettingsState::Received(new_settings); @@ -1577,20 +1534,20 @@ impl Http3Connection { let (recv, send) = wt.borrow_mut().take_sub_streams(); for id in recv { - qtrace!("Remove the extended connect sub receiver stream {}", id); + qtrace!("Remove the extended connect sub receiver stream {id}"); // Use CloseType::ResetRemote so that an event will be sent. CloseType::LocalError would // have the same effect. if let Some(mut s) = self.recv_streams.remove(&id) { - mem::drop(s.reset(CloseType::ResetRemote(Error::HttpRequestCancelled.code()))); + drop(s.reset(CloseType::ResetRemote(Error::HttpRequestCancelled.code()))); } - mem::drop(conn.stream_stop_sending(id, Error::HttpRequestCancelled.code())); + drop(conn.stream_stop_sending(id, Error::HttpRequestCancelled.code())); } for id in send { - qtrace!("Remove the extended connect sub send stream {}", id); + qtrace!("Remove the extended connect sub send stream {id}"); if let Some(mut s) = self.send_streams.remove(&id) { s.handle_stop_sending(CloseType::ResetRemote(Error::HttpRequestCancelled.code())); } - mem::drop(conn.stream_reset_send(id, Error::HttpRequestCancelled.code())); + drop(conn.stream_reset_send(id, Error::HttpRequestCancelled.code())); } } @@ -1600,7 +1557,7 @@ impl Http3Connection { conn: &mut Connection, ) -> Option> { let stream = self.recv_streams.remove(&stream_id); - if let Some(ref s) = stream { + if let Some(s) = &stream { if s.stream_type() == Http3StreamType::ExtendedConnect { self.send_streams.remove(&stream_id).unwrap(); if let Some(wt) = s.webtransport() { @@ -1617,7 +1574,7 @@ impl Http3Connection { conn: &mut Connection, ) -> Option> { let stream = self.send_streams.remove(&stream_id); - if let Some(ref s) = stream { + if let Some(s) = &stream { if s.stream_type() == Http3StreamType::ExtendedConnect { if let Some(wt) = self.recv_streams.remove(&stream_id).unwrap().webtransport() { self.remove_extended_connect(&wt, conn); diff --git a/third_party/rust/neqo-http3/src/connection_client.rs b/third_party/rust/neqo-http3/src/connection_client.rs index 253e303ad1cc..5641dc94017b 100644 --- a/third_party/rust/neqo-http3/src/connection_client.rs +++ b/third_party/rust/neqo-http3/src/connection_client.rs @@ -7,7 +7,7 @@ use std::{ cell::RefCell, fmt::{Debug, Display}, - iter, mem, + iter, net::SocketAddr, rc::Rc, time::Instant, @@ -33,32 +33,24 @@ use crate::{ recv_message::{RecvMessage, RecvMessageInfo}, request_target::AsRequestTarget, settings::HSettings, - Error, Http3Parameters, Http3StreamType, NewStreamType, Priority, PriorityHandler, + Error, Http3Parameters, Http3StreamType, NewStreamType, Priority, PriorityHandler, PushId, ReceiveOutput, Res, }; // This is used for filtering send_streams and recv_Streams with a stream_ids greater than or equal -// a given id. Only the same type (bidirectional or unidirectionsl) streams are filtered. +// a given id. Only the same type (bidirectional or unidirectional) streams are filtered. fn id_gte(base: StreamId) -> impl FnMut((&StreamId, &U)) -> Option + 'static where U: ?Sized, { - move |(id, _)| { - if *id >= base && !(id.is_bidi() ^ base.is_bidi()) { - Some(*id) - } else { - None - } - } + move |(id, _)| (*id >= base && !(id.is_bidi() ^ base.is_bidi())).then_some(*id) } const fn alpn_from_quic_version(version: Version) -> &'static str { match version { Version::Version2 | Version::Version1 => "h3", + #[cfg(feature = "draft-29")] Version::Draft29 => "h3-29", - Version::Draft30 => "h3-30", - Version::Draft31 => "h3-31", - Version::Draft32 => "h3-32", } } @@ -146,7 +138,7 @@ const fn alpn_from_quic_version(version: Version) -> &'static str { /// ); /// } /// Http3ClientEvent::DataReadable { stream_id } => { -/// println!("New data available on stream {}", stream_id); +/// println!("New data available on stream {stream_id}"); /// let mut buf = [0; 100]; /// let (amount, fin) = client.read_data(now(), stream_id, &mut buf).unwrap(); /// println!("Read {:?} bytes from stream {:?} [fin={?}]", @@ -226,7 +218,7 @@ const fn alpn_from_quic_version(version: Version) -> &'static str { /// while let Some(event) = client.next_event() { /// match event { /// Http3ClientEvent::DataReadable{ stream_id } => { -/// println!("Data receivedd form the server on WebTransport stream ID {:?}", +/// println!("Data received form the server on WebTransport stream ID {:?}", /// stream_id, /// ); /// let mut buf = [0; 100]; @@ -262,13 +254,13 @@ const fn alpn_from_quic_version(version: Version) -> &'static str { /// session_id, /// }) => { /// println!("New stream received on session{:?}, stream id={:?} stream type={:?}", -/// sesson_id.stream_id(), +/// session_id.stream_id(), /// stream_id.stream_id(), /// stream_id.stream_type() /// ); /// } /// Http3ClientEvent::DataReadable{ stream_id } => { -/// println!("Data receivedd form the server on WebTransport stream ID {:?}", +/// println!("Data received form the server on WebTransport stream ID {:?}", /// stream_id, /// ); /// let mut buf = [0; 100]; @@ -419,7 +411,7 @@ impl Http3Client { /// The correct way to obtain a resumption token is to wait for the /// `Http3ClientEvent::ResumptionToken` event. To emit the event we are waiting for a - /// resumtion token and a `NEW_TOKEN` frame to arrive. Some servers don't send `NEW_TOKEN` + /// resumption token and a `NEW_TOKEN` frame to arrive. Some servers don't send `NEW_TOKEN` /// frames and in this case, we wait for 3xPTO before emitting an event. This is especially a /// problem for short-lived connections, where the connection is closed before any events are /// released. This function retrieves the token, without waiting for a `NEW_TOKEN` frame to @@ -456,7 +448,7 @@ impl Http3Client { let Some(settings_slice) = dec.decode_vvec() else { return Err(Error::InvalidResumptionToken); }; - qtrace!([self], " settings {}", hex_with_len(settings_slice)); + qtrace!("[{self}] settings {}", hex_with_len(settings_slice)); let mut dec_settings = Decoder::from(settings_slice); let mut settings = HSettings::default(); Error::map_error( @@ -464,7 +456,7 @@ impl Http3Client { Error::InvalidResumptionToken, )?; let tok = dec.decode_remainder(); - qtrace!([self], " Transport token {}", hex(tok)); + qtrace!("[{self}] Transport token {}", hex(tok)); self.conn.enable_resumption(now, tok)?; if self.conn.state().closed() { let state = self.conn.state().clone(); @@ -491,7 +483,7 @@ impl Http3Client { where S: AsRef + Display, { - qinfo!([self], "Close the connection error={} msg={}.", error, msg); + qinfo!("[{self}] Close the connection error={error} msg={msg}"); if !matches!( self.base_handler.state, Http3State::Closing(_) | Http3State::Closed(_) @@ -573,13 +565,13 @@ impl Http3Client { } /// An application may cancel a stream(request). - /// Both sides, the receiviing and sending side, sending and receiving side, will be closed. + /// Both sides, the receiving and sending side, sending and receiving side, will be closed. /// /// # Errors /// /// An error will be return if a stream does not exist. pub fn cancel_fetch(&mut self, stream_id: StreamId, error: AppError) -> Res<()> { - qinfo!([self], "reset_stream {} error={}.", stream_id, error); + qinfo!("[{self}] reset_stream {stream_id} error={error}"); self.base_handler .cancel_fetch(stream_id, error, &mut self.conn) } @@ -590,7 +582,7 @@ impl Http3Client { /// /// An error will be return if stream does not exist. pub fn stream_close_send(&mut self, stream_id: StreamId) -> Res<()> { - qdebug!([self], "Close sending side stream={}.", stream_id); + qdebug!("[{self}] Close sending side stream={stream_id}"); self.base_handler .stream_close_send(&mut self.conn, stream_id) } @@ -599,7 +591,7 @@ impl Http3Client { /// /// An error will be return if a stream does not exist. pub fn stream_reset_send(&mut self, stream_id: StreamId, error: AppError) -> Res<()> { - qinfo!([self], "stream_reset_send {} error={}.", stream_id, error); + qinfo!("[{self}] stream_reset_send {stream_id} error={error}"); self.base_handler .stream_reset_send(&mut self.conn, stream_id, error) } @@ -608,7 +600,7 @@ impl Http3Client { /// /// An error will be return if a stream does not exist. pub fn stream_stop_sending(&mut self, stream_id: StreamId, error: AppError) -> Res<()> { - qinfo!([self], "stream_stop_sending {} error={}.", stream_id, error); + qinfo!("[{self}] stream_stop_sending {stream_id} error={error}"); self.base_handler .stream_stop_sending(&mut self.conn, stream_id, error) } @@ -627,9 +619,7 @@ impl Http3Client { /// supplied. pub fn send_data(&mut self, stream_id: StreamId, buf: &[u8]) -> Res { qinfo!( - [self], - "send_data from stream {} sending {} bytes.", - stream_id, + "[{self}] end_data from stream {stream_id} sending {} bytes", buf.len() ); self.base_handler @@ -652,7 +642,7 @@ impl Http3Client { stream_id: StreamId, buf: &mut [u8], ) -> Res<(usize, bool)> { - qdebug!([self], "read_data from stream {}.", stream_id); + qdebug!("[{self}] read_data from stream {stream_id}"); let res = self.base_handler.read_data(&mut self.conn, stream_id, buf); if let Err(e) = &res { if e.connection_error() { @@ -669,7 +659,7 @@ impl Http3Client { /// # Errors /// /// `InvalidStreamId` if the stream does not exist. - pub fn cancel_push(&mut self, push_id: u64) -> Res<()> { + pub fn cancel_push(&mut self, push_id: PushId) -> Res<()> { self.push_handler .borrow_mut() .cancel(push_id, &mut self.conn, &mut self.base_handler) @@ -685,7 +675,7 @@ impl Http3Client { pub fn push_read_data( &mut self, now: Instant, - push_id: u64, + push_id: PushId, buf: &mut [u8], ) -> Res<(usize, bool)> { let stream_id = self @@ -777,7 +767,7 @@ impl Http3Client { buf: &[u8], id: impl Into, ) -> Res<()> { - qtrace!("webtransport_send_datagram session:{:?}", session_id); + qtrace!("webtransport_send_datagram session:{session_id:?}"); self.base_handler .webtransport_send_datagram(session_id, &mut self.conn, buf, id) } @@ -820,10 +810,6 @@ impl Http3Client { /// # Errors /// /// It may return `InvalidStreamId` if a stream does not exist anymore. - /// - /// # Panics - /// - /// This cannot panic. pub fn webtransport_set_fairness(&mut self, stream_id: StreamId, fairness: bool) -> Res<()> { Http3Connection::stream_set_fairness(&mut self.conn, stream_id, fairness) } @@ -856,7 +842,7 @@ impl Http3Client { /// This function combines `process_input` and `process_output` function. pub fn process(&mut self, dgram: Option>>, now: Instant) -> Output { - qtrace!([self], "Process."); + qtrace!("[{self}] Process"); if let Some(d) = dgram { self.process_input(d, now); } @@ -883,7 +869,7 @@ impl Http3Client { now: Instant, ) { let mut dgrams = dgrams.into_iter().peekable(); - qtrace!([self], "Process multiple datagrams"); + qtrace!("[{self}] Process multiple datagrams"); if dgrams.peek().is_none() { return; } @@ -897,7 +883,7 @@ impl Http3Client { /// the QUC layer and calls `Http3Connection::process_sending` to ensure that HTTP/3 layer /// data, e.g. control frames, are sent. fn process_http3(&mut self, now: Instant) { - qtrace!([self], "Process http3 internal."); + qtrace!("[{self}] Process http3 internal"); match self.base_handler.state() { Http3State::ZeroRtt | Http3State::Connected | Http3State::GoingAway(..) => { let res = self.check_connection_events(); @@ -927,7 +913,7 @@ impl Http3Client { /// - a [`Output::Datagram(Datagram)`][1]: data that should be sent as a UDP payload, /// - a [`Output::Callback(Duration)`][1]: the duration of a timer. `process_output` should be /// called at least after the time expires, - /// - [`Output::None`][1]: this is returned when `Nttp3Client` is done and can be destroyed. + /// - [`Output::None`][1]: this is returned when `Http3Client` is done and can be destroyed. /// /// The application should call this function repeatedly until a timer value or None is /// returned. After that, the application should call the function again if a new UDP packet is @@ -946,7 +932,7 @@ impl Http3Client { /// [2]: ../neqo_transport/struct.ConnectionEvents.html /// [3]: ../neqo_transport/struct.Connection.html#method.process_output pub fn process_output(&mut self, now: Instant) -> Output { - qtrace!([self], "Process output."); + qtrace!("[{self}] Process output"); // Maybe send() stuff on http3-managed streams self.process_http3(now); @@ -964,7 +950,7 @@ impl Http3Client { fn check_result(&mut self, now: Instant, res: &Res) -> bool { match &res { Err(Error::HttpGoaway) => { - qinfo!([self], "Connection error: goaway stream_id increased."); + qinfo!("[{self}] Connection error: goaway stream_id increased"); self.close( now, Error::HttpGeneralProtocol.code(), @@ -973,7 +959,7 @@ impl Http3Client { true } Err(e) => { - qinfo!([self], "Connection error: {}.", e); + qinfo!("[{self}] Connection error: {e}"); self.close(now, e.code(), format!("{e}")); true } @@ -996,9 +982,9 @@ impl Http3Client { /// [2]: ../neqo_transport/enum.ConnectionEvent.html /// [3]: ../neqo_transport/enum.ConnectionEvent.html#variant.RecvStreamReadable fn check_connection_events(&mut self) -> Res<()> { - qtrace!([self], "Check connection events."); + qtrace!("[{self}] Check connection events"); while let Some(e) = self.conn.next_event() { - qdebug!([self], "check_connection_events - event {:?}.", e); + qdebug!("[{self}] check_connection_events - event {e:?}"); match e { ConnectionEvent::NewStream { stream_id } => { // During this event we only add a new stream to the Http3Connection stream @@ -1122,7 +1108,7 @@ impl Http3Client { HFrame::Goaway { stream_id } => self.handle_goaway(stream_id), _ => { unreachable!( - "we should only put MaxPushId, Goaway and PriorityUpdates into control_frames." + "we should only put MaxPushId, Goaway and PriorityUpdates into control_frames" ); } }?; @@ -1133,7 +1119,7 @@ impl Http3Client { } } - fn handle_new_push_stream(&mut self, stream_id: StreamId, push_id: u64) -> Res<()> { + fn handle_new_push_stream(&mut self, stream_id: StreamId, push_id: PushId) -> Res<()> { if !self.push_handler.borrow().can_receive_push() { return Err(Error::HttpId); } @@ -1149,7 +1135,7 @@ impl Http3Client { { // We are not interested in the result of stream_stop_sending, we are not interested // in this stream. - mem::drop( + drop( self.conn .stream_stop_sending(stream_id, Error::HttpRequestCancelled.code()), ); @@ -1168,7 +1154,7 @@ impl Http3Client { Rc::clone(&self.base_handler.qpack_decoder), Box::new(RecvPushEvents::new(push_id, Rc::clone(&self.push_handler))), None, - // TODO: think about the right prority for the push streams. + // TODO: think about the right priority for the push streams. PriorityHandler::new(true, Priority::default()), )), ); @@ -1180,7 +1166,7 @@ impl Http3Client { } fn handle_goaway(&mut self, goaway_stream_id: StreamId) -> Res<()> { - qinfo!([self], "handle_goaway {}", goaway_stream_id); + qinfo!("[{self}] handle_goaway {goaway_stream_id}"); if goaway_stream_id.is_uni() || goaway_stream_id.is_server_initiated() { return Err(Error::HttpId); @@ -1197,7 +1183,7 @@ impl Http3Client { *stream_id = goaway_stream_id; } Http3State::Closing(..) | Http3State::Closed(..) => {} - _ => unreachable!("Should not receive Goaway frame in this state."), + _ => unreachable!("Should not receive Goaway frame in this state"), } // Issue reset events for streams >= goaway stream id @@ -1209,7 +1195,7 @@ impl Http3Client { .collect(); for id in send_ids { // We do not care about streams that are going to be closed. - mem::drop(self.base_handler.handle_stream_stop_sending( + drop(self.base_handler.handle_stream_stop_sending( id, Error::HttpRequestRejected.code(), &mut self.conn, @@ -1224,7 +1210,7 @@ impl Http3Client { .collect(); for id in recv_ids { // We do not care about streams that are going to be closed. - mem::drop(self.base_handler.handle_stream_reset( + drop(self.base_handler.handle_stream_reset( id, Error::HttpRequestRejected.code(), &mut self.conn, @@ -1286,9 +1272,9 @@ impl EventProvider for Http3Client { #[cfg(test)] mod tests { - use std::{mem, time::Duration}; + use std::time::Duration; - use neqo_common::{event::Provider, qtrace, Datagram, Decoder, Encoder}; + use neqo_common::{event::Provider as _, qtrace, Datagram, Decoder, Encoder}; use neqo_crypto::{AllowZeroRtt, AntiReplay, ResumptionToken}; use neqo_qpack::{encoder::QPackEncoder, QpackSettings}; use neqo_transport::{ @@ -1309,7 +1295,7 @@ mod tests { frames::{HFrame, H3_FRAME_TYPE_SETTINGS, H3_RESERVED_FRAME_TYPES}, qpack_encoder_receiver::EncoderRecvStream, settings::{HSetting, HSettingType, H3_RESERVED_SETTINGS}, - Http3Server, Priority, RecvStream, + Http3Server, Priority, PushId, RecvStream as _, }; fn assert_closed(client: &Http3Client, expected: &Error) { @@ -1472,7 +1458,7 @@ mod tests { pub fn create_control_stream(&mut self) { // Create control stream let control = self.conn.stream_create(StreamType::UniDi).unwrap(); - qtrace!(["TestServer"], "control stream: {}", control); + qtrace!("[TestServer] control stream: {control}"); self.control_stream_id = Some(control); // Send stream type on the control stream. assert_eq!( @@ -1655,7 +1641,7 @@ mod tests { out } - // Perform only Quic transport handshake. + // Perform only QUIC transport handshake. fn connect_only_transport_with(client: &mut Http3Client, server: &mut TestServer) { let out = handshake_only(client, server); @@ -1668,7 +1654,7 @@ mod tests { assert!(server.conn.state().connected()); } - // Perform only Quic transport handshake. + // Perform only QUIC transport handshake. fn connect_only_transport() -> (Http3Client, TestServer) { let mut client = default_http3_client(); let mut server = TestServer::new(); @@ -1683,7 +1669,7 @@ mod tests { server.check_client_control_qpack_streams_no_resumption(); } - // Perform Quic transport handshake and exchange Http3 settings. + // Perform QUIC transport handshake and exchange Http3 settings. fn connect_with(client: &mut Http3Client, server: &mut TestServer) { connect_only_transport_with(client, server); @@ -1696,19 +1682,19 @@ mod tests { let out = server.conn.process(None::, now()); client.process_input(out.dgram().unwrap(), now()); - // assert no error occured. + // assert no error occurred. assert_eq!(client.state(), Http3State::Connected); } - // Perform Quic transport handshake and exchange Http3 settings. + // Perform QUIC transport handshake and exchange Http3 settings. fn connect_with_connection_parameters( server_conn_params: ConnectionParameters, ) -> (Http3Client, TestServer) { // connecting with default max_table_size let mut client = default_http3_client_param(100); let server = Connection::new_server( - test_fixture::DEFAULT_KEYS, - test_fixture::DEFAULT_ALPN_H3, + DEFAULT_KEYS, + DEFAULT_ALPN_H3, Rc::new(RefCell::new(CountingConnectionIdGenerator::default())), server_conn_params, ) @@ -1718,7 +1704,7 @@ mod tests { (client, server) } - // Perform Quic transport handshake and exchange Http3 settings. + // Perform QUIC transport handshake and exchange Http3 settings. fn connect() -> (Http3Client, TestServer) { let mut client = default_http3_client(); let mut server = TestServer::new(); @@ -1897,7 +1883,7 @@ mod tests { } let out = server.conn.process(None::, now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); } const PUSH_PROMISE_DATA: &[u8] = &[ @@ -1916,7 +1902,7 @@ mod tests { } // Send a push promise with push_id and request_stream_id. - fn send_push_promise(conn: &mut Connection, stream_id: StreamId, push_id: u64) { + fn send_push_promise(conn: &mut Connection, stream_id: StreamId, push_id: PushId) { let frame = HFrame::PushPromise { push_id, header_block: PUSH_PROMISE_DATA.to_vec(), @@ -1929,14 +1915,14 @@ mod tests { fn send_push_data_and_exchange_packets( client: &mut Http3Client, server: &mut TestServer, - push_id: u8, + push_id: PushId, close_push_stream: bool, ) -> StreamId { let push_stream_id = send_push_data(&mut server.conn, push_id, close_push_stream); let out = server.conn.process_output(now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); push_stream_id } @@ -1945,19 +1931,19 @@ mod tests { client: &mut Http3Client, server: &mut TestServer, stream_id: StreamId, - push_id: u64, + push_id: PushId, ) { send_push_promise(&mut server.conn, stream_id, push_id); let out = server.conn.process_output(now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); } fn send_cancel_push_and_exchange_packets( client: &mut Http3Client, server: &mut TestServer, - push_id: u64, + push_id: PushId, ) { let frame = HFrame::CancelPush { push_id }; let mut d = Encoder::default(); @@ -1969,7 +1955,7 @@ mod tests { let out = server.conn.process_output(now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); } const PUSH_DATA: &[u8] = &[ @@ -1999,13 +1985,15 @@ mod tests { fn send_data_on_push( conn: &mut Connection, push_stream_id: StreamId, - push_id: u8, + push_id: PushId, data: impl AsRef<[u8]>, close_push_stream: bool, ) { // send data _ = conn.stream_send(push_stream_id, PUSH_STREAM_TYPE).unwrap(); - _ = conn.stream_send(push_stream_id, &[push_id]).unwrap(); + _ = conn + .stream_send(push_stream_id, &[u8::try_from(u64::from(push_id)).unwrap()]) + .unwrap(); _ = conn.stream_send(push_stream_id, data.as_ref()).unwrap(); if close_push_stream { conn.stream_close_send(push_stream_id).unwrap(); @@ -2017,7 +2005,7 @@ mod tests { // 2) push_id // 3) PUSH_DATA that contains encoded headers and a data frame. // This function can only handle small push_id numbers that fit in a varint of length 1 byte. - fn send_push_data(conn: &mut Connection, push_id: u8, close_push_stream: bool) -> StreamId { + fn send_push_data(conn: &mut Connection, push_id: PushId, close_push_stream: bool) -> StreamId { send_push_with_data(conn, push_id, PUSH_DATA, close_push_stream) } @@ -2028,7 +2016,7 @@ mod tests { // This function can only handle small push_id numbers that fit in a varint of length 1 byte. fn send_push_with_data( conn: &mut Connection, - push_id: u8, + push_id: PushId, data: &[u8], close_push_stream: bool, ) -> StreamId { @@ -2040,7 +2028,7 @@ mod tests { } struct PushPromiseInfo { - pub push_id: u64, + pub push_id: PushId, pub ref_stream_id: StreamId, } @@ -2053,7 +2041,7 @@ mod tests { fn read_response_and_push_events( client: &mut Http3Client, push_promises: &[PushPromiseInfo], - push_streams: &[u64], + push_streams: &[PushId], response_stream_id: StreamId, ) { let mut num_push_promises = 0; @@ -2123,7 +2111,7 @@ mod tests { // Client: Test receiving a new control stream and a SETTINGS frame. #[test] fn client_connect_and_exchange_qpack_and_control_streams() { - mem::drop(connect()); + drop(connect()); } // Client: Test that the connection will be closed if control stream @@ -2272,19 +2260,19 @@ mod tests { assert_closed(&client, &Error::HttpFrameUnexpected); } - // send DATA frame on a cortrol stream + // send DATA frame on a control stream #[test] fn data_frame_on_control_stream() { test_wrong_frame_on_control_stream(&[0x0, 0x2, 0x1, 0x2]); } - // send HEADERS frame on a cortrol stream + // send HEADERS frame on a control stream #[test] fn headers_frame_on_control_stream() { test_wrong_frame_on_control_stream(&[0x1, 0x2, 0x1, 0x2]); } - // send PUSH_PROMISE frame on a cortrol stream + // send PUSH_PROMISE frame on a control stream #[test] fn push_promise_frame_on_control_stream() { test_wrong_frame_on_control_stream(&[0x5, 0x2, 0x1, 0x2]); @@ -2304,7 +2292,7 @@ mod tests { fn test_wrong_frame_on_push_stream(v: &[u8]) { let (mut client, mut server, request_stream_id) = connect_and_send_request(false); - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); // Create a push stream let push_stream_id = server.conn.stream_create(StreamType::UniDi).unwrap(); @@ -2317,7 +2305,7 @@ mod tests { let out = server.conn.process_output(now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); assert_closed(&client, &Error::HttpFrameUnexpected); } @@ -2377,7 +2365,7 @@ mod tests { .unwrap(); let out = server.conn.process_output(now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // check for stop-sending with Error::HttpStreamCreation. let mut stop_sending_event_found = false; @@ -2405,7 +2393,7 @@ mod tests { // Generate packet with the above bad h3 input let out = server.conn.process_output(now()); // Process bad input and close the connection. - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); assert_closed(&client, &Error::HttpFrameUnexpected); } @@ -2571,7 +2559,7 @@ mod tests { } } - // after this stream will be removed from hcoon. We will check this by trying to read + // after this stream will be removed from conn. We will check this by trying to read // from the stream and that should fail. let mut buf = [0_u8; 100]; let res = client.read_data(now(), request_stream_id, &mut buf); @@ -2682,7 +2670,7 @@ mod tests { client.stream_close_send(request_stream_id).unwrap(); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // find the new request/response stream and send response on it. while let Some(e) = server.conn.next_event() { @@ -2795,7 +2783,7 @@ mod tests { } // Send 2 data frames so that the second one cannot fit into the send_buf and it is only - // partialy sent. We check that the sent data is correct. + // partially sent. We check that the sent data is correct. fn fetch_with_two_data_frames( first_frame: &[u8], expected_first_data_frame_header: &[u8], @@ -3114,7 +3102,7 @@ mod tests { stop_sending = true; } Http3ClientEvent::Reset { .. } => { - panic!("We should not get StopSending."); + panic!("We should not get StopSending"); } Http3ClientEvent::HeaderReady { .. } | Http3ClientEvent::DataReadable { .. } => { panic!("We should not get any headers or data"); @@ -3248,7 +3236,7 @@ mod tests { stop_sending = true; } Http3ClientEvent::Reset { .. } => { - panic!("We should not get StopSending."); + panic!("We should not get StopSending"); } Http3ClientEvent::HeaderReady { .. } | Http3ClientEvent::DataReadable { .. } => { header_ready = true; @@ -3260,7 +3248,7 @@ mod tests { assert!(stop_sending); assert!(header_ready); - // after this, we can sill read data from a sttream. + // after this, we can sill read data from a stream. let mut buf = [0_u8; 100]; let (amount, fin) = client .read_data(now(), request_stream_id, &mut buf) @@ -3295,7 +3283,7 @@ mod tests { while let Some(e) = client.next_event() { match e { Http3ClientEvent::StopSending { .. } => { - panic!("We should not get StopSending."); + panic!("We should not get StopSending"); } Http3ClientEvent::Reset { stream_id, @@ -3378,7 +3366,7 @@ mod tests { assert_eq!(request_stream_id_3, 8); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); _ = server .conn @@ -3462,7 +3450,7 @@ mod tests { assert_eq!(request_stream_id_3, 8); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // First send a Goaway frame with an higher number _ = server @@ -3598,7 +3586,7 @@ mod tests { let out = server.conn.process_output(now()); client.process(out.dgram(), now()); - // Recv HeaderReady wo headers with fin. + // Recv HeaderReady without headers with fin. let e = client.events().next().unwrap(); assert_eq!( e, @@ -3617,7 +3605,7 @@ mod tests { ); } - // Close stream imemediately after headers. + // Close stream immediately after headers. #[test] fn stream_fin_after_headers() { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); @@ -3660,7 +3648,7 @@ mod tests { #[test] fn stream_fin_after_headers_are_read_wo_data_frame() { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - // Send some good data wo fin + // Send some good data without fin server_send_response_and_exchange_packet( &mut client, &mut server, @@ -3669,7 +3657,7 @@ mod tests { false, ); - // Recv headers wo fin + // Recv headers without fin while let Some(e) = client.next_event() { match e { Http3ClientEvent::HeaderReady { @@ -3696,7 +3684,7 @@ mod tests { let out = server.conn.process_output(now()); client.process(out.dgram(), now()); - // Recv DataReadable wo data with fin + // Recv DataReadable without data with fin while let Some(e) = client.next_event() { match e { Http3ClientEvent::HeaderReady { .. } => { @@ -3775,11 +3763,11 @@ mod tests { } // Send headers and an empty data frame. Read headers and then close the stream. - // We should get a HeaderReady without fin and a DataReadable wo data and with fin. + // We should get a HeaderReady without fin and a DataReadable without data and with fin. #[test] fn stream_fin_after_headers_an_empty_data_frame_are_read() { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - // Send some good data wo fin + // Send some good data without fin // Send headers. _ = server .conn @@ -3794,7 +3782,7 @@ mod tests { let out = server.conn.process_output(now()); client.process(out.dgram(), now()); - // Recv headers wo fin + // Recv headers without fin while let Some(e) = client.next_event() { match e { Http3ClientEvent::HeaderReady { @@ -3850,7 +3838,7 @@ mod tests { #[test] fn stream_fin_after_a_data_frame() { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - // Send some good data wo fin + // Send some good data without fin server_send_response_and_exchange_packet( &mut client, &mut server, @@ -3859,7 +3847,7 @@ mod tests { false, ); - // Recv some good data wo fin + // Recv some good data without fin while let Some(e) = client.next_event() { match e { Http3ClientEvent::HeaderReady { @@ -3891,7 +3879,7 @@ mod tests { let out = server.conn.process_output(now()); client.process(out.dgram(), now()); - // fin wo data should generate DataReadable + // fin without data should generate DataReadable let e = client.events().next().unwrap(); if let Http3ClientEvent::DataReadable { stream_id } = e { assert_eq!(stream_id, request_stream_id); @@ -4035,11 +4023,11 @@ mod tests { assert!(!client.events().any(header_ready_event)); // Let client receive the encoder instructions. - mem::drop(client.process(encoder_inst_pkt.dgram(), now())); + drop(client.process(encoder_inst_pkt.dgram(), now())); let out = server.conn.process_output(now()); - mem::drop(client.process(out.dgram(), now())); - mem::drop(client.process_output(now())); + drop(client.process(out.dgram(), now())); + drop(client.process_output(now())); let mut recv_header = false; let mut recv_data = false; @@ -4156,7 +4144,7 @@ mod tests { assert_eq!(client.state(), Http3State::Initializing); client .enable_resumption(now(), &token) - .expect("Set resumption token."); + .expect("Set resumption token"); assert_eq!(client.state(), Http3State::ZeroRtt); let zerortt_event = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::ZeroRtt)); @@ -4189,7 +4177,7 @@ mod tests { let out = client.process(out.dgram(), now()); assert_eq!(client.state(), Http3State::Connected); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); assert!(server.conn.state().connected()); assert!(client.tls_info().unwrap().resumed()); @@ -4260,8 +4248,8 @@ mod tests { let mut client = default_http3_client(); let mut server = Connection::new_server( - test_fixture::DEFAULT_KEYS, - test_fixture::DEFAULT_ALPN_H3, + DEFAULT_KEYS, + DEFAULT_ALPN_H3, Rc::new(RefCell::new(CountingConnectionIdGenerator::default())), ConnectionParameters::default(), ) @@ -4277,7 +4265,7 @@ mod tests { assert_eq!(client.state(), Http3State::Initializing); client .enable_resumption(now(), &token) - .expect("Set resumption token."); + .expect("Set resumption token"); let zerortt_event = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::ZeroRtt)); assert!(client.events().any(zerortt_event)); @@ -4313,14 +4301,14 @@ mod tests { assert_eq!(res.unwrap_err(), Error::InvalidStreamId); // Client will send Setting frame and open new qpack streams. - mem::drop(server.process(client_out.dgram(), now())); + drop(server.process(client_out.dgram(), now())); TestServer::new_with_conn(server).check_client_control_qpack_streams_no_resumption(); // Check that we can send a request and that the stream_id starts again from 0. assert_eq!(make_request(&mut client, false, &[]), 0); } - // Connect to a server, get token and reconnect using 0-rtt. Seerver sends new Settings. + // Connect to a server, get token and reconnect using 0-rtt. Server sends new Settings. fn zero_rtt_change_settings( original_settings: &[HSetting], resumption_settings: &[HSetting], @@ -4338,7 +4326,7 @@ mod tests { assert_eq!(client.state(), Http3State::Initializing); client .enable_resumption(now(), &token) - .expect("Set resumption token."); + .expect("Set resumption token"); assert_eq!(client.state(), Http3State::ZeroRtt); let out = client.process_output(now()); @@ -4359,7 +4347,7 @@ mod tests { let out = client.process(out.dgram(), now()); assert_eq!(client.state(), Http3State::Connected); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); assert!(server.conn.state().connected()); assert!(client.tls_info().unwrap().resumed()); @@ -4903,7 +4891,7 @@ mod tests { ); assert!(!client.events().any(data_readable_event)); - // Now read only until the end of the first frame. The firs framee has 3 bytes. + // Now read only until the end of the first frame. The firs frame has 3 bytes. let mut buf2 = [0_u8; 2]; assert_eq!( (2, false), @@ -4983,7 +4971,7 @@ mod tests { let request_stream_id = make_request(&mut client, true, &[]); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); setup_server_side_encoder(&mut client, &mut server); @@ -5018,13 +5006,13 @@ mod tests { server.conn.stream_close_send(request_stream_id).unwrap(); let out = server.conn.process_output(now()); - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); let header_ready_event = |e| matches!(e, Http3ClientEvent::HeaderReady { .. }); assert!(!client.events().any(header_ready_event)); // Let client receive the encoder instructions. - mem::drop(client.process(qpack_pkt1.dgram(), now())); + drop(client.process(qpack_pkt1.dgram(), now())); assert!(client.events().any(header_ready_event)); } @@ -5036,10 +5024,10 @@ mod tests { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); // Send a push promise. - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); // create a push stream. - _ = send_push_data(&mut server.conn, 0, true); + _ = send_push_data(&mut server.conn, PushId::new(0), true); server_send_response_and_exchange_packet( &mut client, @@ -5052,10 +5040,10 @@ mod tests { read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 0, + push_id: PushId::new(0), ref_stream_id: request_stream_id, }], - &[0], + &[PushId::new(0)], request_stream_id, ); @@ -5063,7 +5051,10 @@ mod tests { // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); } /// We can't keep the connection alive on the basis of a push promise, @@ -5076,7 +5067,7 @@ mod tests { let idle_timeout = ConnectionParameters::default().get_idle_timeout(); // Promise a push and deliver, but don't close the stream. - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); server_send_response_and_exchange_packet( &mut client, &mut server, @@ -5087,7 +5078,7 @@ mod tests { read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 0, + push_id: PushId::new(0), ref_stream_id: request_stream_id, }], &[], // No push streams yet. @@ -5099,12 +5090,14 @@ mod tests { assert_eq!(client.process_output(now()).callback(), idle_timeout); // Reading push data will stop the client from being idle. - _ = send_push_data(&mut server.conn, 0, false); + _ = send_push_data(&mut server.conn, PushId::new(0), false); let out = server.conn.process_output(now()); client.process_input(out.dgram().unwrap(), now()); let mut buf = [0; 16]; - let (read, fin) = client.push_read_data(now(), 0, &mut buf).unwrap(); + let (read, fin) = client + .push_read_data(now(), PushId::new(0), &mut buf) + .unwrap(); assert!(read < buf.len()); assert!(!fin); @@ -5118,14 +5111,14 @@ mod tests { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); // Send a push promise. - send_push_promise(&mut server.conn, request_stream_id, 0); - send_push_promise(&mut server.conn, request_stream_id, 1); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(1)); // create a push stream. - _ = send_push_data(&mut server.conn, 0, true); + _ = send_push_data(&mut server.conn, PushId::new(0), true); // create a second push stream. - _ = send_push_data(&mut server.conn, 1, true); + _ = send_push_data(&mut server.conn, PushId::new(1), true); server_send_response_and_exchange_packet( &mut client, @@ -5139,15 +5132,15 @@ mod tests { &mut client, &[ PushPromiseInfo { - push_id: 0, + push_id: PushId::new(0), ref_stream_id: request_stream_id, }, PushPromiseInfo { - push_id: 1, + push_id: PushId::new(1), ref_stream_id: request_stream_id, }, ], - &[0, 1], + &[PushId::new(0), PushId::new(1)], request_stream_id, ); @@ -5155,8 +5148,14 @@ mod tests { // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); - assert_eq!(client.cancel_push(1), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); + assert_eq!( + client.cancel_push(PushId::new(1)), + Err(Error::InvalidStreamId) + ); } #[test] @@ -5171,10 +5170,10 @@ mod tests { .unwrap(); // Send a push promise. - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); // create a push stream. - _ = send_push_data(&mut server.conn, 0, true); + _ = send_push_data(&mut server.conn, PushId::new(0), true); // Send response data server_send_response_and_exchange_packet( @@ -5188,10 +5187,10 @@ mod tests { read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 0, + push_id: PushId::new(0), ref_stream_id: request_stream_id, }], - &[0], + &[PushId::new(0)], request_stream_id, ); @@ -5210,17 +5209,17 @@ mod tests { .unwrap(); // Send a push promise. - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); // create a push stream. - send_push_data_and_exchange_packets(&mut client, &mut server, 0, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), true); read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 0, + push_id: PushId::new(0), ref_stream_id: request_stream_id, }], - &[0], + &[PushId::new(0)], request_stream_id, ); @@ -5265,13 +5264,18 @@ mod tests { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); // create a push stream. - send_push_data_and_exchange_packets(&mut client, &mut server, 0, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), true); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Now send push_promise - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 0); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); server_send_response_and_exchange_packet( &mut client, @@ -5284,10 +5288,10 @@ mod tests { read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 0, + push_id: PushId::new(0), ref_stream_id: request_stream_id, }], - &[0], + &[PushId::new(0)], request_stream_id, ); @@ -5302,11 +5306,21 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 5); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(5), + ); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 3); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(3), + ); // Start a push stream with push_id 3. - send_push_data_and_exchange_packets(&mut client, &mut server, 3, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(3), true); assert_eq!(client.state(), Http3State::Connected); @@ -5314,15 +5328,15 @@ mod tests { &mut client, &[ PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id, }, PushPromiseInfo { - push_id: 3, + push_id: PushId::new(3), ref_stream_id: request_stream_id, }, ], - &[3], + &[PushId::new(3)], request_stream_id, ); assert_eq!(client.state(), Http3State::Connected); @@ -5336,24 +5350,34 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 5); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(5), + ); - send_push_data_and_exchange_packets(&mut client, &mut server, 3, true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 3); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(3), true); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(3), + ); read_response_and_push_events( &mut client, &[ PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id, }, PushPromiseInfo { - push_id: 3, + push_id: PushId::new(3), ref_stream_id: request_stream_id, }, ], - &[3], + &[PushId::new(3)], request_stream_id, ); assert_eq!(client.state(), Http3State::Connected); @@ -5368,31 +5392,41 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 5); - send_push_data_and_exchange_packets(&mut client, &mut server, 5, true); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(5), + ); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(5), true); assert_eq!(client.state(), Http3State::Connected); // Read push stream with push_id 5 to make it change to closed state. read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id, }], - &[5], + &[PushId::new(5)], request_stream_id, ); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 3); - send_push_data_and_exchange_packets(&mut client, &mut server, 3, true); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(3), + ); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(3), true); read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 3, + push_id: PushId::new(3), ref_stream_id: request_stream_id, }], - &[3], + &[PushId::new(3)], request_stream_id, ); assert_eq!(client.state(), Http3State::Connected); @@ -5404,26 +5438,36 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 5); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(5), + ); // make a second request. let request_stream_id_2 = make_request(&mut client, false, &[]); assert_eq!(request_stream_id_2, 4); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id_2, 5); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id_2, + PushId::new(5), + ); read_response_and_push_events( &mut client, &[ PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id, }, PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id_2, }, ], @@ -5439,31 +5483,41 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 5); - send_push_data_and_exchange_packets(&mut client, &mut server, 5, true); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(5), + ); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(5), true); // make a second request. let request_stream_id_2 = make_request(&mut client, false, &[]); assert_eq!(request_stream_id_2, 4); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id_2, 5); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id_2, + PushId::new(5), + ); read_response_and_push_events( &mut client, &[ PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id, }, PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id_2, }, ], - &[5], + &[PushId::new(5)], request_stream_id, ); assert_eq!(client.state(), Http3State::Connected); @@ -5476,17 +5530,22 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 5); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(5), + ); // Start a push stream with push_id 5. - send_push_data_and_exchange_packets(&mut client, &mut server, 5, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(5), true); read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 5, + push_id: PushId::new(5), ref_stream_id: request_stream_id, }], - &[5], + &[PushId::new(5)], request_stream_id, ); @@ -5495,9 +5554,14 @@ mod tests { assert_eq!(request_stream_id_2, 4); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id_2, 5); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id_2, + PushId::new(5), + ); // Check that we do not have a Http3ClientEvent::PushPromise. let push_event = |e| matches!(e, Http3ClientEvent::PushPromise { .. }); @@ -5511,7 +5575,12 @@ mod tests { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); // Send a push promise. max_push_id is set to 5, to trigger an error we send push_id=6. - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 6); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(6), + ); assert_closed(&client, &Error::HttpId); } @@ -5523,7 +5592,7 @@ mod tests { let (mut client, mut server) = connect(); // Send a push stream. max_push_id is set to 5, to trigger an error we send push_id=6. - send_push_data_and_exchange_packets(&mut client, &mut server, 6, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(6), true); assert_closed(&client, &Error::HttpId); } @@ -5535,7 +5604,7 @@ mod tests { let (mut client, mut server, _request_stream_id) = connect_and_send_request(true); // Send CANCEL_PUSH for push_id 6. - send_cancel_push_and_exchange_packets(&mut client, &mut server, 6); + send_cancel_push_and_exchange_packets(&mut client, &mut server, PushId::new(6)); assert_closed(&client, &Error::HttpId); } @@ -5546,7 +5615,7 @@ mod tests { // Connect and send a request let (mut client, _, _) = connect_and_send_request(true); - assert_eq!(client.cancel_push(6), Err(Error::HttpId)); + assert_eq!(client.cancel_push(PushId::new(6)), Err(Error::HttpId)); assert_eq!(client.state(), Http3State::Connected); } @@ -5558,37 +5627,37 @@ mod tests { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); // Send 3 push promises. - send_push_promise(&mut server.conn, request_stream_id, 0); - send_push_promise(&mut server.conn, request_stream_id, 1); - send_push_promise(&mut server.conn, request_stream_id, 2); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(1)); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(2)); // create 3 push streams. - send_push_data(&mut server.conn, 0, true); - send_push_data(&mut server.conn, 1, true); - send_push_data_and_exchange_packets(&mut client, &mut server, 2, true); + send_push_data(&mut server.conn, PushId::new(0), true); + send_push_data(&mut server.conn, PushId::new(1), true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(2), true); read_response_and_push_events( &mut client, &[ PushPromiseInfo { - push_id: 0, + push_id: PushId::new(0), ref_stream_id: request_stream_id, }, PushPromiseInfo { - push_id: 1, + push_id: PushId::new(1), ref_stream_id: request_stream_id, }, PushPromiseInfo { - push_id: 2, + push_id: PushId::new(2), ref_stream_id: request_stream_id, }, ], - &[0, 1, 2], + &[PushId::new(0), PushId::new(1), PushId::new(2)], request_stream_id, ); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // Check max_push_id frame has been received let control_stream_readable = @@ -5602,22 +5671,22 @@ mod tests { assert_eq!(&buf[..3], MAX_PUSH_ID_FRAME); // Check that we can send push_id=8 now - send_push_promise(&mut server.conn, request_stream_id, 8); - send_push_data(&mut server.conn, 8, true); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(8)); + send_push_data(&mut server.conn, PushId::new(8), true); let out = server.conn.process_output(now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); assert_eq!(client.state(), Http3State::Connected); read_response_and_push_events( &mut client, &[PushPromiseInfo { - push_id: 8, + push_id: PushId::new(8), ref_stream_id: request_stream_id, }], - &[8], + &[PushId::new(8)], request_stream_id, ); @@ -5631,10 +5700,10 @@ mod tests { let (mut client, mut server, _request_stream_id) = connect_and_send_request(true); // Start a push stream with push_id 0. - send_push_data_and_exchange_packets(&mut client, &mut server, 0, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), true); // Send it again - send_push_data_and_exchange_packets(&mut client, &mut server, 0, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), true); assert_closed(&client, &Error::HttpId); } @@ -5645,11 +5714,11 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise(&mut server.conn, request_stream_id, 0); - send_push_data_and_exchange_packets(&mut client, &mut server, 0, true); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), true); // Now the push_stream is in the PushState::Active state - send_push_data_and_exchange_packets(&mut client, &mut server, 0, true); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), true); assert_closed(&client, &Error::HttpId); } @@ -5675,19 +5744,22 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_cancel_push_and_exchange_packets(&mut client, &mut server, 0); + send_cancel_push_and_exchange_packets(&mut client, &mut server, PushId::new(0)); - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); // Start a push stream with push_id 0. let push_stream_id = - send_push_data_and_exchange_packets(&mut client, &mut server, 0, false); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), false); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); // Check that the push has been canceled by the client. assert_stop_sending_event( @@ -5706,18 +5778,21 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); let push_stream_id = - send_push_data_and_exchange_packets(&mut client, &mut server, 0, false); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), false); - send_cancel_push_and_exchange_packets(&mut client, &mut server, 0); + send_cancel_push_and_exchange_packets(&mut client, &mut server, PushId::new(0)); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); // Check that the push has been canceled by the client. assert_stop_sending_event( @@ -5737,16 +5812,19 @@ mod tests { // Start a push stream with push_id 0. let push_stream_id = - send_push_data_and_exchange_packets(&mut client, &mut server, 0, false); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), false); - send_cancel_push_and_exchange_packets(&mut client, &mut server, 0); + send_cancel_push_and_exchange_packets(&mut client, &mut server, PushId::new(0)); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); // Check that the push has been canceled by the client. assert_stop_sending_event( @@ -5765,10 +5843,10 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise(&mut server.conn, request_stream_id, 0); + send_push_promise(&mut server.conn, request_stream_id, PushId::new(0)); // Start a push stream with push_id 0. let push_stream_id = - send_push_data_and_exchange_packets(&mut client, &mut server, 0, false); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), false); server .conn @@ -5782,7 +5860,10 @@ mod tests { // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); assert_eq!(client.state(), Http3State::Connected); } @@ -5795,7 +5876,7 @@ mod tests { // Start a push stream with push_id 0. let push_stream_id = - send_push_data_and_exchange_packets(&mut client, &mut server, 0, false); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), false); server .conn @@ -5804,14 +5885,22 @@ mod tests { let out = server.conn.process_output(now()); client.process(out.dgram(), now()); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 0); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); assert_eq!(client.state(), Http3State::Connected); } @@ -5822,16 +5911,24 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 0); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); - assert!(client.cancel_push(0).is_ok()); + assert!(client.cancel_push(PushId::new(0)).is_ok()); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); assert_eq!(client.state(), Http3State::Connected); } @@ -5843,20 +5940,28 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 0); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); let push_stream_id = - send_push_data_and_exchange_packets(&mut client, &mut server, 0, false); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), false); - assert!(client.cancel_push(0).is_ok()); + assert!(client.cancel_push(PushId::new(0)).is_ok()); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); // Check that the push has been canceled by the client. assert_stop_sending_event( @@ -5874,22 +5979,35 @@ mod tests { // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 0); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); let push_stream_id = - send_push_data_and_exchange_packets(&mut client, &mut server, 0, false); + send_push_data_and_exchange_packets(&mut client, &mut server, PushId::new(0), false); - assert!(client.cancel_push(0).is_ok()); + assert!(client.cancel_push(PushId::new(0)).is_ok()); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); - send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id, 0); + send_push_promise_and_exchange_packets( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); // Assert that we do not have any push event. assert!(!check_push_events(&mut client)); // Check that the push has been closed, e.g. calling cancel_push should return // InvalidStreamId. - assert_eq!(client.cancel_push(0), Err(Error::InvalidStreamId)); + assert_eq!( + client.cancel_push(PushId::new(0)), + Err(Error::InvalidStreamId) + ); // Check that the push has been canceled by the client. assert_stop_sending_event( @@ -5922,7 +6040,7 @@ mod tests { .send_encoder_updates(&mut server.conn) .unwrap(); let out = server.conn.process_output(now()); - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); } fn setup_server_side_encoder(client: &mut Http3Client, server: &mut TestServer) { @@ -5933,7 +6051,7 @@ mod tests { client: &mut Http3Client, server: &mut TestServer, stream_id: StreamId, - push_id: u64, + push_id: PushId, ) -> Option { send_push_promise_using_encoder_with_custom_headers( client, @@ -5948,7 +6066,7 @@ mod tests { client: &mut Http3Client, server: &mut TestServer, stream_id: StreamId, - push_id: u64, + push_id: PushId, additional_header: Header, ) -> Option { let mut headers = vec![ @@ -5988,16 +6106,20 @@ mod tests { setup_server_side_encoder(&mut client, &mut server); - let encoder_inst_pkt = - send_push_promise_using_encoder(&mut client, &mut server, request_stream_id, 0); + let encoder_inst_pkt = send_push_promise_using_encoder( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(!check_push_events(&mut client)); // Let client receive the encoder instructions. let _out = client.process(encoder_inst_pkt, now()); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(check_push_events(&mut client)); } @@ -6017,10 +6139,14 @@ mod tests { false, ); - let encoder_inst_pkt = - send_push_promise_using_encoder(&mut client, &mut server, request_stream_id, 0); + let encoder_inst_pkt = send_push_promise_using_encoder( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(!check_push_events(&mut client)); // Stream data can be still read @@ -6037,7 +6163,7 @@ mod tests { // Let client receive the encoder instructions. let _out = client.process(encoder_inst_pkt, now()); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(check_push_events(&mut client)); // Stream data can be still read @@ -6059,10 +6185,14 @@ mod tests { setup_server_side_encoder(&mut client, &mut server); - let encoder_inst_pkt = - send_push_promise_using_encoder(&mut client, &mut server, request_stream_id, 0); + let encoder_inst_pkt = send_push_promise_using_encoder( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(!check_push_events(&mut client)); // Send response headers @@ -6079,7 +6209,7 @@ mod tests { // Let client receive the encoder instructions. let _out = client.process(encoder_inst_pkt, now()); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(check_push_events(&mut client)); } @@ -6090,7 +6220,7 @@ mod tests { setup_server_side_encoder(&mut client, &mut server); - // Insert an elemet into a dynamic table. + // Insert an element into a dynamic table. // insert "content-length: 1234 server .encoder @@ -6101,10 +6231,14 @@ mod tests { let _out = client.process(encoder_inst_pkt1, now()); // Send a PushPromise that is blocked until encoder_inst_pkt2 is process by the client. - let encoder_inst_pkt2 = - send_push_promise_using_encoder(&mut client, &mut server, request_stream_id, 0); + let encoder_inst_pkt2 = send_push_promise_using_encoder( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(!check_push_events(&mut client)); let response_headers = vec![ @@ -6161,22 +6295,22 @@ mod tests { &mut client, &mut server, request_stream_id, - 0, + PushId::new(0), Header::new("myn1", "myv1"), ); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(!check_push_events(&mut client)); let encoder_inst_pkt2 = send_push_promise_using_encoder_with_custom_headers( &mut client, &mut server, request_stream_id, - 1, + PushId::new(1), Header::new("myn2", "myv2"), ); - // PushPromise is blocked wathing for encoder instructions. + // PushPromise is blocked watching for encoder instructions. assert!(!check_push_events(&mut client)); let response_headers = vec![ @@ -6225,9 +6359,14 @@ mod tests { setup_server_side_encoder(&mut client, &mut server); - mem::drop( - send_push_promise_using_encoder(&mut client, &mut server, request_stream_id, 0) - .unwrap(), + drop( + send_push_promise_using_encoder( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ) + .unwrap(), ); server_send_response_and_exchange_packet( @@ -6246,7 +6385,7 @@ mod tests { .unwrap(); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // Check that encoder got stream_canceled instruction. let mut inst = [0_u8; 100]; let (amount, fin) = server @@ -6292,7 +6431,7 @@ mod tests { false, ); - // Headers are blocked waiting fro the encoder instructions. + // Headers are blocked waiting for the encoder instructions. let header_ready_event = |e| matches!(e, Http3ClientEvent::HeaderReady { .. }); assert!(!client.events().any(header_ready_event)); @@ -6310,7 +6449,7 @@ mod tests { ); // Now read headers. - mem::drop(client.process(encoder_insts.dgram(), now())); + drop(client.process(encoder_insts.dgram(), now())); } #[test] @@ -6318,11 +6457,11 @@ mod tests { let (mut client, mut server, request_stream_id) = connect_and_send_request(true); setup_server_side_encoder(&mut client, &mut server); // Cancel request. - mem::drop(client.cancel_fetch(request_stream_id, Error::HttpRequestCancelled.code())); + drop(client.cancel_fetch(request_stream_id, Error::HttpRequestCancelled.code())); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); - mem::drop(server.encoder_receiver.receive(&mut server.conn)); + drop(server.conn.process(out.dgram(), now())); + drop(server.encoder_receiver.receive(&mut server.conn)); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 1); } @@ -6370,8 +6509,8 @@ mod tests { assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0); let out = server.conn.process_output(now()); let out = client.process(out.dgram(), now()); - mem::drop(server.conn.process(out.dgram(), now())); - mem::drop(server.encoder_receiver.receive(&mut server.conn)); + drop(server.conn.process(out.dgram(), now())); + drop(server.encoder_receiver.receive(&mut server.conn)); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 1); } @@ -6381,7 +6520,7 @@ mod tests { setup_server_side_encoder(&mut client, &mut server); - mem::drop( + drop( send_headers_using_encoder( &mut client, &mut server, @@ -6406,8 +6545,8 @@ mod tests { assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); - mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); + drop(server.conn.process(out.dgram(), now())); + drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 1); } @@ -6430,7 +6569,7 @@ mod tests { ); // Exchange encoder instructions - mem::drop(client.process(encoder_instruct, now())); + drop(client.process(encoder_instruct, now())); let header_ready_event = |e| matches!(e, Http3ClientEvent::HeaderReady { .. }); assert!(client.events().any(header_ready_event)); @@ -6443,8 +6582,8 @@ mod tests { assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); - mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); + drop(server.conn.process(out.dgram(), now())); + drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0); } @@ -6469,12 +6608,17 @@ mod tests { // Send the encoder instructions. let out = server.conn.process_output(now()); - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); // Send PushPromise that will be blocked waiting for decoder instructions. - mem::drop( - send_push_promise_using_encoder(&mut client, &mut server, request_stream_id, 0) - .unwrap(), + drop( + send_push_promise_using_encoder( + &mut client, + &mut server, + request_stream_id, + PushId::new(0), + ) + .unwrap(), ); // Send response @@ -6499,8 +6643,8 @@ mod tests { .unwrap(); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); - mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); + drop(server.conn.process(out.dgram(), now())); + drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 1); } @@ -6513,8 +6657,8 @@ mod tests { .unwrap(); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); - mem::drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); + drop(server.conn.process(out.dgram(), now())); + drop(server.encoder_receiver.receive(&mut server.conn).unwrap()); assert_eq!(server.encoder.borrow_mut().stats().stream_cancelled_recv, 0); } @@ -6566,7 +6710,7 @@ mod tests { assert!(!client.events().any(header_ready_event)); // Now make the encoder instructions available. - mem::drop(client.process(encoder_insts.dgram(), now())); + drop(client.process(encoder_insts.dgram(), now())); // Header blocks for both streams should be ready. let mut count_responses = 0; @@ -6711,7 +6855,7 @@ mod tests { ); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // Check that server has received a reset. let stop_sending_event = |e| { @@ -6733,7 +6877,7 @@ mod tests { // Client: receive a push stream #[test] fn push_single_with_1xx() { - const FIRST_PUSH_ID: u64 = 0; + const FIRST_PUSH_ID: PushId = PushId::new(0); // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); @@ -6754,13 +6898,7 @@ mod tests { server.encode_headers(push_stream_id, headers200, &mut d); // create a push stream. - send_data_on_push( - &mut server.conn, - push_stream_id, - u8::try_from(FIRST_PUSH_ID).unwrap(), - &d, - true, - ); + send_data_on_push(&mut server.conn, push_stream_id, FIRST_PUSH_ID, &d, true); server_send_response_and_exchange_packet( &mut client, @@ -6801,7 +6939,7 @@ mod tests { // Client: receive a push stream #[test] fn push_single_wo_status() { - const FIRST_PUSH_ID: u64 = 0; + const FIRST_PUSH_ID: PushId = PushId::new(0); // Connect and send a request let (mut client, mut server, request_stream_id) = connect_and_send_request(true); @@ -6817,13 +6955,7 @@ mod tests { ]; server.encode_headers(request_stream_id, &headers, &mut d); - send_data_on_push( - &mut server.conn, - push_stream_id, - u8::try_from(FIRST_PUSH_ID).unwrap(), - &d, - false, - ); + send_data_on_push(&mut server.conn, push_stream_id, FIRST_PUSH_ID, &d, false); server_send_response_and_exchange_packet( &mut client, @@ -6833,7 +6965,7 @@ mod tests { true, ); - // Stream has been reset because of thei malformed headers. + // Stream has been reset because of their malformed headers. let push_reset_event = |e| { matches!(e, Http3ClientEvent::PushReset { push_id, @@ -6844,7 +6976,7 @@ mod tests { assert!(client.events().any(push_reset_event)); let out = client.process_output(now()); - mem::drop(server.conn.process(out.dgram(), now())); + drop(server.conn.process(out.dgram(), now())); // Check that server has received a reset. let stop_sending_event = |e| { @@ -7026,7 +7158,7 @@ mod tests { // exchange qpack settings, server will send a token as well. datagram = client.process(datagram, now()).dgram(); datagram = server.process(datagram, now()).dgram(); - mem::drop(client.process(datagram, now()).dgram()); + drop(client.process(datagram, now()).dgram()); client .events() @@ -7066,7 +7198,7 @@ mod tests { assert_eq!(client.state(), Http3State::Initializing); client .enable_resumption(now(), &token) - .expect("Set resumption token."); + .expect("Set resumption token"); assert_eq!(client.state(), Http3State::ZeroRtt); let zerortt_event = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::ZeroRtt)); @@ -7088,7 +7220,7 @@ mod tests { let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); let out = server.process(out.dgram(), now()); - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); // The header ack for the first request has been received. assert_eq!(client.qpack_encoder_stats().header_acks_recv, 1); diff --git a/third_party/rust/neqo-http3/src/connection_server.rs b/third_party/rust/neqo-http3/src/connection_server.rs index f06cf272ba2f..d7741755ab10 100644 --- a/third_party/rust/neqo-http3/src/connection_server.rs +++ b/third_party/rust/neqo-http3/src/connection_server.rs @@ -6,7 +6,7 @@ use std::{rc::Rc, time::Instant}; -use neqo_common::{event::Provider, qdebug, qinfo, qtrace, Header, MessageType, Role}; +use neqo_common::{event::Provider as _, qdebug, qinfo, qtrace, Header, MessageType, Role}; use neqo_transport::{ AppError, Connection, ConnectionEvent, DatagramTracking, StreamId, StreamType, }; @@ -102,7 +102,7 @@ impl Http3ServerHandler { /// /// An error will be returned if stream does not exist. pub fn stream_close_send(&mut self, stream_id: StreamId, conn: &mut Connection) -> Res<()> { - qdebug!([self], "Close sending side stream={}.", stream_id); + qdebug!("[{self}] Close sending side stream={stream_id}"); self.base_handler.stream_close_send(conn, stream_id)?; self.needs_processing = true; Ok(()) @@ -120,7 +120,7 @@ impl Http3ServerHandler { error: AppError, conn: &mut Connection, ) -> Res<()> { - qinfo!([self], "cancel_fetch {} error={}.", stream_id, error); + qinfo!("[{self}] cancel_fetch {stream_id} error={error}"); self.needs_processing = true; self.base_handler.cancel_fetch(stream_id, error, conn) } @@ -131,7 +131,7 @@ impl Http3ServerHandler { error: AppError, conn: &mut Connection, ) -> Res<()> { - qinfo!([self], "stream_stop_sending {} error={}.", stream_id, error); + qinfo!("[{self}] stream_stop_sending {stream_id} error={error}"); self.needs_processing = true; self.base_handler .stream_stop_sending(conn, stream_id, error) @@ -143,7 +143,7 @@ impl Http3ServerHandler { error: AppError, conn: &mut Connection, ) -> Res<()> { - qinfo!([self], "stream_reset_send {} error={}.", stream_id, error); + qinfo!("[{self}] stream_reset_send {stream_id} error={error}"); self.needs_processing = true; self.base_handler.stream_reset_send(conn, stream_id, error) } @@ -215,7 +215,7 @@ impl Http3ServerHandler { /// Process HTTTP3 layer. pub fn process_http3(&mut self, conn: &mut Connection, now: Instant) { - qtrace!([self], "Process http3 internal."); + qtrace!("[{self}] Process http3 internal"); if matches!(self.base_handler.state(), Http3State::Closed(..)) { return; } @@ -254,7 +254,7 @@ impl Http3ServerHandler { } fn close(&mut self, conn: &mut Connection, now: Instant, err: &Error) { - qinfo!([self], "Connection error: {}.", err); + qinfo!("[{self}] Connection error: {err}"); conn.close(now, err.code(), format!("{err}")); self.base_handler.close(err.code()); self.events @@ -263,9 +263,9 @@ impl Http3ServerHandler { // If this return an error the connection must be closed. fn check_connection_events(&mut self, conn: &mut Connection, now: Instant) -> Res<()> { - qtrace!([self], "Check connection events."); + qtrace!("[{self}] Check connection events"); while let Some(e) = conn.next_event() { - qdebug!([self], "check_connection_events - event {e:?}."); + qdebug!("[{self}] check_connection_events - event {e:?}"); match e { ConnectionEvent::NewStream { stream_id } => { self.base_handler.add_new_stream(stream_id); @@ -325,7 +325,7 @@ impl Http3ServerHandler { MessageType::Response, Http3StreamType::Http, stream_id, - self.base_handler.qpack_encoder.clone(), + Rc::clone(&self.base_handler.qpack_encoder), Box::new(self.events.clone()), )), Box::new(RecvMessage::new( @@ -387,7 +387,7 @@ impl Http3ServerHandler { Ok(()) } _ => unreachable!( - "we should only put MaxPushId, Goaway and PriorityUpdates into control_frames." + "we should only put MaxPushId, Goaway and PriorityUpdates into control_frames" ), }?; } @@ -411,7 +411,7 @@ impl Http3ServerHandler { stream_id: StreamId, buf: &mut [u8], ) -> Res<(usize, bool)> { - qdebug!([self], "read_data from stream {}.", stream_id); + qdebug!("[{self}] read_data from stream {stream_id}"); let res = self.base_handler.read_data(conn, stream_id, buf); if let Err(e) = &res { if e.connection_error() { diff --git a/third_party/rust/neqo-http3/src/control_stream_local.rs b/third_party/rust/neqo-http3/src/control_stream_local.rs index 92d12ef97fb6..db30df1950e0 100644 --- a/third_party/rust/neqo-http3/src/control_stream_local.rs +++ b/third_party/rust/neqo-http3/src/control_stream_local.rs @@ -92,7 +92,7 @@ impl ControlStreamLocal { /// Create a control stream. pub fn create(&mut self, conn: &mut Connection) -> Res<()> { - qtrace!([self], "Create a control stream."); + qtrace!("[{self}] Create a control stream"); self.stream.init(conn.stream_create(StreamType::UniDi)?); self.stream .buffer(&[u8::try_from(HTTP3_UNI_STREAM_TYPE_CONTROL).unwrap()]); diff --git a/third_party/rust/neqo-http3/src/control_stream_remote.rs b/third_party/rust/neqo-http3/src/control_stream_remote.rs index ef2bf96d5b70..644e3b55d876 100644 --- a/third_party/rust/neqo-http3/src/control_stream_remote.rs +++ b/third_party/rust/neqo-http3/src/control_stream_remote.rs @@ -36,7 +36,7 @@ impl ControlStreamRemote { /// Check if a stream is the control stream and read received data. pub fn receive_single(&mut self, conn: &mut Connection) -> Res> { - qdebug!([self], "Receiving data."); + qdebug!("[{self}] Receiving data"); match self .frame_reader .receive(&mut StreamReaderConnectionWrapper::new( @@ -45,7 +45,7 @@ impl ControlStreamRemote { ))? { (_, true) => Err(Error::HttpClosedCriticalStream), (s, false) => { - qdebug!([self], "received {:?}", s); + qdebug!("[{self}] received {s:?}"); Ok(s) } } diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs index 4b23277cbc15..15b6c343cb0d 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/mod.rs @@ -10,7 +10,7 @@ mod sessions; mod streams; use std::{cell::RefCell, rc::Rc, time::Duration}; -use neqo_common::event::Provider; +use neqo_common::{event::Provider as _, header::HeadersExt as _}; use neqo_crypto::AuthenticationStatus; use neqo_transport::{ConnectionParameters, Pmtud, StreamId, StreamType}; use test_fixture::{ @@ -60,6 +60,13 @@ pub fn default_http3_server(server_params: Http3Parameters) -> Http3Server { .expect("create a server") } +pub fn assert_wt(headers: &[Header]) { + assert!( + headers.contains_header(":method", "CONNECT") + && headers.contains_header(":protocol", "webtransport") + ); +} + fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) { let mut out = None; loop { @@ -71,7 +78,7 @@ fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) { } } -// Perform only Quic transport handshake. +// Perform only QUIC transport handshake. fn connect_with(client: &mut Http3Client, server: &mut Http3Server) { assert_eq!(client.state(), Http3State::Initializing); let out = client.process_output(now()); @@ -92,13 +99,13 @@ fn connect_with(client: &mut Http3Client, server: &mut Http3Server) { assert_eq!(client.state(), Http3State::Connected); - // Exchange H3 setttings + // Exchange H3 settings let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); let out = server.process(out.dgram(), now()); - std::mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); } fn connect( @@ -148,14 +155,7 @@ impl WtTest { session, headers, }) => { - assert!( - headers - .iter() - .any(|h| h.name() == ":method" && h.value() == "CONNECT") - && headers - .iter() - .any(|h| h.name() == ":protocol" && h.value() == "webtransport") - ); + assert_wt(&headers); session.response(accept).unwrap(); wt_server_session = Some(session); } @@ -183,7 +183,7 @@ impl WtTest { }) if ( stream_id == wt_session_id && status == 200 && - headers.contains(&Header::new(":status", "200")) + headers.contains_header(":status", "200") ) ) }; diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs index 82ec1328a725..d396347421fb 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/negotiation.rs @@ -6,7 +6,7 @@ use std::time::Duration; -use neqo_common::{event::Provider, Encoder}; +use neqo_common::{event::Provider as _, Encoder}; use neqo_crypto::AuthenticationStatus; use neqo_transport::{CloseReason, Connection, StreamType}; use test_fixture::{default_server_h3, now}; @@ -88,7 +88,7 @@ fn zero_rtt( // exchange token let out = server.process_output(now()); // We do not have a token so we need to wait for a resumption token timer to trigger. - std::mem::drop(client.process(out.dgram(), now() + Duration::from_millis(250))); + drop(client.process(out.dgram(), now() + Duration::from_millis(250))); assert_eq!(client.state(), Http3State::Connected); let token = client .events() @@ -105,7 +105,7 @@ fn zero_rtt( let mut server = default_http3_server(Http3Parameters::default().webtransport(server_resumed)); client .enable_resumption(now(), &token) - .expect("Set resumption token."); + .expect("Set resumption token"); assert_eq!(client.state(), Http3State::ZeroRtt); exchange_packets(&mut client, &mut server); diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/sessions.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/sessions.rs index 821d8ac5e342..4c327af457e4 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/sessions.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/sessions.rs @@ -4,16 +4,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; - -use neqo_common::{event::Provider, Encoder}; +use neqo_common::{event::Provider as _, header::HeadersExt as _, Encoder}; use neqo_transport::StreamType; use test_fixture::now; use crate::{ features::extended_connect::{ tests::webtransport::{ - default_http3_client, default_http3_server, wt_default_parameters, WtTest, + assert_wt, default_http3_client, default_http3_server, wt_default_parameters, WtTest, }, SessionCloseReason, }, @@ -26,7 +24,7 @@ use crate::{ #[test] fn wt_session() { let mut wt = WtTest::new(); - mem::drop(wt.create_wt_session()); + drop(wt.create_wt_session()); } #[test] @@ -134,14 +132,7 @@ fn wt_session_response_with_1xx() { headers, }) = event { - assert!( - headers - .iter() - .any(|h| h.name() == ":method" && h.value() == "CONNECT") - && headers - .iter() - .any(|h| h.name() == ":protocol" && h.value() == "webtransport") - ); + assert_wt(&headers); wt_server_session = Some(session); } } @@ -168,7 +159,7 @@ fn wt_session_response_with_1xx() { }) if ( stream_id == wt_session_id && status == 200 && - headers.contains(&Header::new(":status", "200")) + headers.contains_header(":status", "200") ) ) }; @@ -209,14 +200,7 @@ fn wt_session_respone_200_with_fin() { headers, }) = event { - assert!( - headers - .iter() - .any(|h| h.name() == ":method" && h.value() == "CONNECT") - && headers - .iter() - .any(|h| h.name() == ":protocol" && h.value() == "webtransport") - ); + assert_wt(&headers); wt_server_session = Some(session); } } diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/streams.rs b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/streams.rs index 07a761206fa5..73db34ca7e63 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/streams.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/tests/webtransport/streams.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; - use neqo_transport::StreamType; use crate::{ @@ -94,7 +92,7 @@ fn wt_server_stream_bidi() { wt.send_data_server(&wt_server_stream, BUF_SERVER); wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, false); wt.send_data_client(wt_server_stream.stream_id(), BUF_CLIENT); - mem::drop(wt.receive_data_server(wt_server_stream.stream_id(), false, BUF_CLIENT, false)); + drop(wt.receive_data_server(wt_server_stream.stream_id(), false, BUF_CLIENT, false)); let stats = wt.send_stream_stats(wt_server_stream.stream_id()).unwrap(); assert_eq!(stats.bytes_written(), BUF_CLIENT.len() as u64); assert_eq!(stats.bytes_sent(), BUF_CLIENT.len() as u64); @@ -161,7 +159,7 @@ fn wt_server_stream_bidi_close() { wt.receive_data_client(wt_server_stream.stream_id(), true, BUF_SERVER, true); wt.send_data_client(wt_server_stream.stream_id(), BUF_CLIENT); wt.close_stream_sending_client(wt_server_stream.stream_id()); - mem::drop(wt.receive_data_server(wt_server_stream.stream_id(), false, BUF_CLIENT, true)); + drop(wt.receive_data_server(wt_server_stream.stream_id(), false, BUF_CLIENT, true)); } #[test] @@ -172,7 +170,7 @@ fn wt_client_stream_uni_reset() { let wt_session = wt.create_wt_session(); let wt_stream = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi); wt.send_data_client(wt_stream, BUF_CLIENT); - mem::drop(wt.receive_data_server(wt_stream, true, BUF_CLIENT, false)); + drop(wt.receive_data_server(wt_stream, true, BUF_CLIENT, false)); wt.reset_stream_client(wt_stream); wt.receive_reset_server(wt_stream, Error::HttpNoError.code()); } @@ -315,7 +313,7 @@ fn wt_client_session_close_1() { let bidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi); wt.send_data_client(bidi_from_client, BUF); - std::mem::drop(wt.receive_data_server(bidi_from_client, true, BUF, false)); + drop(wt.receive_data_server(bidi_from_client, true, BUF, false)); wt.cancel_session_client(wt_session.stream_id()); @@ -350,7 +348,7 @@ fn wt_client_session_close_2() { let unidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi); wt.send_data_client(unidi_from_client, BUF); - std::mem::drop(wt.receive_data_server(unidi_from_client, true, BUF, false)); + drop(wt.receive_data_server(unidi_from_client, true, BUF, false)); wt.cancel_session_client(wt_session.stream_id()); @@ -385,7 +383,7 @@ fn wt_client_session_close_3() { let unidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi); wt.send_data_client(unidi_from_client, BUF); - std::mem::drop(wt.receive_data_server(unidi_from_client, true, BUF, false)); + drop(wt.receive_data_server(unidi_from_client, true, BUF, false)); wt.close_stream_sending_client(unidi_from_client); wt.cancel_session_client(wt_session.stream_id()); @@ -450,7 +448,7 @@ fn wt_client_session_close_5() { let unidi_from_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi); wt.send_data_client(unidi_from_client, BUF); - mem::drop(wt.receive_data_server(unidi_from_client, true, BUF, false)); + drop(wt.receive_data_server(unidi_from_client, true, BUF, false)); wt.reset_stream_client(unidi_from_client); wt.cancel_session_client(wt_session.stream_id()); @@ -700,10 +698,10 @@ fn wt_client_session_close_13() { let bidi_client_1 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi); wt.send_data_client(bidi_client_1, BUF); - std::mem::drop(wt.receive_data_server(bidi_client_1, true, BUF, false)); + drop(wt.receive_data_server(bidi_client_1, true, BUF, false)); let bidi_client_2 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi); wt.send_data_client(bidi_client_2, BUF); - std::mem::drop(wt.receive_data_server(bidi_client_2, true, BUF, false)); + drop(wt.receive_data_server(bidi_client_2, true, BUF, false)); wt.cancel_session_client(wt_session.stream_id()); @@ -750,7 +748,7 @@ fn wt_client_session_server_close_1() { let bidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi); wt.send_data_client(bidi_client, BUF); - std::mem::drop(wt.receive_data_server(bidi_client, true, BUF, false)); + drop(wt.receive_data_server(bidi_client, true, BUF, false)); wt.cancel_session_server(&wt_session); @@ -784,7 +782,7 @@ fn wt_client_session_server_close_2() { let unidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi); wt.send_data_client(unidi_client, BUF); - std::mem::drop(wt.receive_data_server(unidi_client, true, BUF, false)); + drop(wt.receive_data_server(unidi_client, true, BUF, false)); wt.cancel_session_server(&wt_session); @@ -1064,10 +1062,10 @@ fn wt_client_session_server_close_11() { let bidi_client_1 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi); wt.send_data_client(bidi_client_1, BUF); - std::mem::drop(wt.receive_data_server(bidi_client_1, true, BUF, false)); + drop(wt.receive_data_server(bidi_client_1, true, BUF, false)); let bidi_client_2 = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::BiDi); wt.send_data_client(bidi_client_2, BUF); - std::mem::drop(wt.receive_data_server(bidi_client_2, true, BUF, false)); + drop(wt.receive_data_server(bidi_client_2, true, BUF, false)); wt.cancel_session_server(&wt_session); diff --git a/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_session.rs b/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_session.rs index ea8a87659c20..82d61f351312 100644 --- a/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_session.rs +++ b/third_party/rust/neqo-http3/src/features/extended_connect/webtransport_session.rs @@ -73,7 +73,7 @@ impl WebTransportSession { first_frame_type: None, }, qpack_decoder, - Box::new(stream_event_listener.clone()), + Box::new(Rc::clone(&stream_event_listener)), None, PriorityHandler::new(false, Priority::default()), )), @@ -82,7 +82,7 @@ impl WebTransportSession { Http3StreamType::ExtendedConnect, session_id, qpack_encoder, - Box::new(stream_event_listener.clone()), + Box::new(Rc::clone(&stream_event_listener)), )), stream_event_listener, session_id, @@ -111,11 +111,11 @@ impl WebTransportSession { control_stream_recv .http_stream() .unwrap() - .set_new_listener(Box::new(stream_event_listener.clone())); + .set_new_listener(Box::new(Rc::clone(&stream_event_listener))); control_stream_send .http_stream() .unwrap() - .set_new_listener(Box::new(stream_event_listener.clone())); + .set_new_listener(Box::new(Rc::clone(&stream_event_listener))); Self { control_stream_recv, control_stream_send, @@ -146,7 +146,7 @@ impl WebTransportSession { } fn receive(&mut self, conn: &mut Connection) -> Res<(ReceiveOutput, bool)> { - qtrace!([self], "receive control data"); + qtrace!("[{self}] receive control data"); let (out, _) = self.control_stream_recv.receive(conn)?; debug_assert!(out == ReceiveOutput::NoOutput); self.maybe_check_headers(); @@ -229,11 +229,7 @@ impl WebTransportSession { if let Some((headers, interim, fin)) = self.stream_event_listener.borrow_mut().get_headers() { - qtrace!( - "ExtendedConnect response headers {:?}, fin={}", - headers, - fin - ); + qtrace!("ExtendedConnect response headers {headers:?}, fin={fin}"); if interim { if fin { @@ -346,7 +342,7 @@ impl WebTransportSession { &mut self.control_stream_recv, )) .map_err(|_| Error::HttpGeneralProtocolStream)?; - qtrace!([self], "Received frame: {:?} fin={}", f, fin); + qtrace!("[{self}] Received frame: {f:?} fin={fin}"); if let Some(WebTransportFrame::CloseSession { error, message }) = f { self.events.session_end( ExtendedConnectType::WebTransport, @@ -410,7 +406,7 @@ impl WebTransportSession { buf: &[u8], id: impl Into, ) -> Res<()> { - qtrace!([self], "send_datagram state={:?}", self.state); + qtrace!("[{self}] send_datagram state={:?}", self.state); if self.state == SessionState::Active { let mut dgram_data = Encoder::default(); dgram_data.encode_varint(self.session_id.as_u64() / 4); @@ -451,7 +447,7 @@ impl RecvStream for Rc> { } fn webtransport(&self) -> Option>> { - Some(self.clone()) + Some(Self::clone(self)) } } diff --git a/third_party/rust/neqo-http3/src/features/mod.rs b/third_party/rust/neqo-http3/src/features/mod.rs index c44ff8eacd2b..e9b41b7b0513 100644 --- a/third_party/rust/neqo-http3/src/features/mod.rs +++ b/third_party/rust/neqo-http3/src/features/mod.rs @@ -63,8 +63,7 @@ impl NegotiationState { } = self { qtrace!( - "set_negotiated {:?} to {}", - feature_type, + "set_negotiated {feature_type:?} to {}", settings.get(*feature_type) ); let cb = mem::take(listener); diff --git a/third_party/rust/neqo-http3/src/frames/hframe.rs b/third_party/rust/neqo-http3/src/frames/hframe.rs index a60b6e948152..157a2032db7e 100644 --- a/third_party/rust/neqo-http3/src/frames/hframe.rs +++ b/third_party/rust/neqo-http3/src/frames/hframe.rs @@ -4,13 +4,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{fmt::Debug, io::Write}; +use std::{fmt::Debug, io::Write as _}; use neqo_common::{Decoder, Encoder}; use neqo_crypto::random; use neqo_transport::StreamId; -use crate::{frames::reader::FrameDecoder, settings::HSettings, Error, Priority, Res}; +use crate::{frames::reader::FrameDecoder, settings::HSettings, Error, Priority, PushId, Res}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct HFrameType(pub u64); @@ -48,20 +48,20 @@ pub enum HFrame { header_block: Vec, }, CancelPush { - push_id: u64, + push_id: PushId, }, Settings { settings: HSettings, }, PushPromise { - push_id: u64, + push_id: PushId, header_block: Vec, }, Goaway { stream_id: StreamId, }, MaxPushId { - push_id: u64, + push_id: PushId, }, Grease, PriorityUpdateRequest { @@ -87,7 +87,9 @@ impl HFrame { Self::PriorityUpdateRequest { .. } => H3_FRAME_TYPE_PRIORITY_UPDATE_REQUEST, Self::PriorityUpdatePush { .. } => H3_FRAME_TYPE_PRIORITY_UPDATE_PUSH, Self::Grease => { - HFrameType(Decoder::from(&random::<7>()).decode_uint(7).unwrap() * 0x1f + 0x21) + let r = Decoder::from(&random::<8>()).decode_uint::().unwrap(); + // Zero out the top 7 bits: 2 for being a varint; 5 to account for the *0x1f. + HFrameType((r >> 7) * 0x1f + 0x21) } } } @@ -115,7 +117,9 @@ impl HFrame { push_id, header_block, } => { - enc.encode_varint((header_block.len() + (Encoder::varint_len(*push_id))) as u64); + enc.encode_varint( + (header_block.len() + (Encoder::varint_len(u64::from(*push_id)))) as u64, + ); enc.encode_varint(*push_id); enc.encode(header_block); } @@ -170,12 +174,12 @@ impl FrameDecoder for HFrame { } else if let Some(payload) = data { let mut dec = Decoder::from(payload); Ok(match frame_type { - H3_FRAME_TYPE_DATA => unreachable!("DATA frame has been handled already."), + H3_FRAME_TYPE_DATA => unreachable!("DATA frame has been handled already"), H3_FRAME_TYPE_HEADERS => Some(Self::Headers { header_block: dec.decode_remainder().to_vec(), }), H3_FRAME_TYPE_CANCEL_PUSH => Some(Self::CancelPush { - push_id: dec.decode_varint().ok_or(Error::HttpFrame)?, + push_id: dec.decode_varint().ok_or(Error::HttpFrame)?.into(), }), H3_FRAME_TYPE_SETTINGS => { let mut settings = HSettings::default(); @@ -189,14 +193,14 @@ impl FrameDecoder for HFrame { Some(Self::Settings { settings }) } H3_FRAME_TYPE_PUSH_PROMISE => Some(Self::PushPromise { - push_id: dec.decode_varint().ok_or(Error::HttpFrame)?, + push_id: dec.decode_varint().ok_or(Error::HttpFrame)?.into(), header_block: dec.decode_remainder().to_vec(), }), H3_FRAME_TYPE_GOAWAY => Some(Self::Goaway { stream_id: StreamId::new(dec.decode_varint().ok_or(Error::HttpFrame)?), }), H3_FRAME_TYPE_MAX_PUSH_ID => Some(Self::MaxPushId { - push_id: dec.decode_varint().ok_or(Error::HttpFrame)?, + push_id: dec.decode_varint().ok_or(Error::HttpFrame)?.into(), }), H3_FRAME_TYPE_PRIORITY_UPDATE_REQUEST | H3_FRAME_TYPE_PRIORITY_UPDATE_PUSH => { let element_id = dec.decode_varint().ok_or(Error::HttpFrame)?; diff --git a/third_party/rust/neqo-http3/src/frames/reader.rs b/third_party/rust/neqo-http3/src/frames/reader.rs index bd1f0811b632..14a8b4c6f2fd 100644 --- a/third_party/rust/neqo-http3/src/frames/reader.rs +++ b/third_party/rust/neqo-http3/src/frames/reader.rs @@ -24,7 +24,7 @@ pub trait FrameDecoder { /// # Errors /// - /// Returns `HttpFrameUnexpected` if frames is not alowed, i.e. is a `H3_RESERVED_FRAME_TYPES`. + /// Returns `HttpFrameUnexpected` if frames is not allowed, i.e. is a `H3_RESERVED_FRAME_TYPES`. fn frame_type_allowed(_frame_type: HFrameType) -> Res<()> { Ok(()) } @@ -154,7 +154,7 @@ impl FrameReader { } } - /// returns true if quic stream was closed. + /// Returns true if QUIC stream was closed. /// /// # Errors /// @@ -173,7 +173,7 @@ impl FrameReader { { (0, f) => (None, false, f), (amount, f) => { - qtrace!("FrameReader::receive: reading {} byte, fin={}", amount, f); + qtrace!("FrameReader::receive: reading {amount} byte, fin={f}"); (self.consume::(Decoder::from(&buf[..amount]))?, true, f) } }; @@ -203,16 +203,15 @@ impl FrameReader { match &mut self.state { FrameReaderState::GetType { decoder } => { if let Some(v) = decoder.consume(&mut input) { - qtrace!("FrameReader::receive: read frame type {}", v); + qtrace!("FrameReader::receive: read frame type {v}"); self.frame_type_decoded::(HFrameType(v))?; } } FrameReaderState::GetLength { decoder } => { if let Some(len) = decoder.consume(&mut input) { qtrace!( - "FrameReader::receive: frame type {:?} length {}", - self.frame_type, - len + "FrameReader::receive: frame type {:?} length {len}", + self.frame_type ); return self.frame_length_decoded::(len); } @@ -235,9 +234,6 @@ impl FrameReader { } Ok(None) } -} - -impl FrameReader { fn frame_type_decoded>(&mut self, frame_type: HFrameType) -> Res<()> { T::frame_type_allowed(frame_type)?; self.frame_type = frame_type; diff --git a/third_party/rust/neqo-http3/src/frames/tests/hframe.rs b/third_party/rust/neqo-http3/src/frames/tests/hframe.rs index e62e6c43f03a..3b8bc42bb826 100644 --- a/third_party/rust/neqo-http3/src/frames/tests/hframe.rs +++ b/third_party/rust/neqo-http3/src/frames/tests/hframe.rs @@ -12,7 +12,7 @@ use super::enc_dec_hframe; use crate::{ frames::HFrame, settings::{HSetting, HSettingType, HSettings}, - Priority, + Priority, PushId, }; #[test] @@ -31,7 +31,9 @@ fn headers_frame() { #[test] fn cancel_push_frame4() { - let f = HFrame::CancelPush { push_id: 5 }; + let f = HFrame::CancelPush { + push_id: PushId::new(5), + }; enc_dec_hframe(&f, "030105", 0); } @@ -46,7 +48,7 @@ fn settings_frame4() { #[test] fn push_promise_frame4() { let f = HFrame::PushPromise { - push_id: 4, + push_id: PushId::new(4), header_block: vec![0x61, 0x62, 0x63, 0x64], }; enc_dec_hframe(&f, "05050461626364", 0); diff --git a/third_party/rust/neqo-http3/src/frames/tests/mod.rs b/third_party/rust/neqo-http3/src/frames/tests/mod.rs index 5c863242ff33..3f93c115476a 100644 --- a/third_party/rust/neqo-http3/src/frames/tests/mod.rs +++ b/third_party/rust/neqo-http3/src/frames/tests/mod.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; - use neqo_common::Encoder; use neqo_crypto::AuthenticationStatus; use neqo_transport::StreamType; @@ -25,21 +23,21 @@ pub fn enc_dec>(d: &Encoder, st: &str, remaining: usize) -> T let out = conn_c.process_output(now()); let out = conn_s.process(out.dgram(), now()); let out = conn_c.process(out.dgram(), now()); - mem::drop(conn_s.process(out.dgram(), now())); + drop(conn_s.process(out.dgram(), now())); conn_c.authenticated(AuthenticationStatus::Ok, now()); let out = conn_c.process_output(now()); - mem::drop(conn_s.process(out.dgram(), now())); + drop(conn_s.process(out.dgram(), now())); // create a stream let stream_id = conn_s.stream_create(StreamType::BiDi).unwrap(); - let mut fr: FrameReader = FrameReader::new(); + let mut fr = FrameReader::new(); - // conver string into u8 vector + // convert string into u8 vector let buf = Encoder::from_hex(st); conn_s.stream_send(stream_id, buf.as_ref()).unwrap(); let out = conn_s.process_output(now()); - mem::drop(conn_c.process(out.dgram(), now())); + drop(conn_c.process(out.dgram(), now())); let (frame, fin) = fr .receive::(&mut StreamReaderConnectionWrapper::new( diff --git a/third_party/rust/neqo-http3/src/frames/tests/reader.rs b/third_party/rust/neqo-http3/src/frames/tests/reader.rs index 46e236ce55d6..0aaba04a931d 100644 --- a/third_party/rust/neqo-http3/src/frames/tests/reader.rs +++ b/third_party/rust/neqo-http3/src/frames/tests/reader.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{fmt::Debug, mem}; +use std::fmt::Debug; use neqo_common::Encoder; use neqo_transport::{Connection, StreamId, StreamType}; @@ -15,7 +15,7 @@ use crate::{ reader::FrameDecoder, FrameReader, HFrame, StreamReaderConnectionWrapper, WebTransportFrame, }, settings::{HSetting, HSettingType, HSettings}, - Error, + Error, PushId, }; struct FrameReaderTest { @@ -40,7 +40,7 @@ impl FrameReaderTest { fn process>(&mut self, v: &[u8]) -> Option { self.conn_s.stream_send(self.stream_id, v).unwrap(); let out = self.conn_s.process_output(now()); - mem::drop(self.conn_c.process(out.dgram(), now())); + drop(self.conn_c.process(out.dgram(), now())); let (frame, fin) = self .fr .receive::(&mut StreamReaderConnectionWrapper::new( @@ -112,7 +112,7 @@ fn frame_reading_with_stream_push_promise() { header_block, } = frame.unwrap() { - assert_eq!(push_id, 257); + assert_eq!(push_id, PushId::new(257)); assert_eq!(header_block, &[0x1, 0x2, 0x3]); } else { panic!("wrong frame type"); @@ -128,7 +128,7 @@ fn frame_reading_with_stream_data() { let frame = fr.process(&[0x0, 0x3, 0x1, 0x2, 0x3]).unwrap(); assert!(matches!(frame, HFrame::Data { len } if len == 3)); - // payloead is still on the stream. + // payload is still on the stream. // assert that we have 3 bytes in the stream let mut buf = [0_u8; 100]; let (amount, _) = fr.conn_c.stream_recv(fr.stream_id, &mut buf).unwrap(); @@ -150,11 +150,11 @@ fn unknown_frame() { buf.resize(UNKNOWN_FRAME_LEN + buf.len(), 0); assert!(fr.process::(&buf).is_none()); - // now receive a CANCEL_PUSH fram to see that frame reader is ok. + // now receive a CANCEL_PUSH frame to see that frame reader is ok. let frame = fr.process(&[0x03, 0x01, 0x05]); assert!(frame.is_some()); if let HFrame::CancelPush { push_id } = frame.unwrap() { - assert!(push_id == 5); + assert!(push_id == PushId::new(5)); } else { panic!("wrong frame type"); } @@ -194,7 +194,7 @@ fn unknown_wt_frame() { buf.resize(UNKNOWN_FRAME_LEN + buf.len(), 0); assert!(fr.process::(&buf).is_none()); - // now receive a WT_FRAME_CLOSE_SESSION fram to see that frame reader is ok. + // now receive a WT_FRAME_CLOSE_SESSION frame to see that frame reader is ok. let frame = fr.process(&[ 0x68, 0x43, 0x09, 0x00, 0x00, 0x00, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, ]); @@ -231,12 +231,12 @@ fn test_reading_frame + PartialEq + Debug>( } let out = fr.conn_s.process_output(now()); - mem::drop(fr.conn_c.process(out.dgram(), now())); + drop(fr.conn_c.process(out.dgram(), now())); if matches!(test_to_send, FrameReadingTestSend::DataThenFin) { fr.conn_s.stream_close_send(fr.stream_id).unwrap(); let out = fr.conn_s.process_output(now()); - mem::drop(fr.conn_c.process(out.dgram(), now())); + drop(fr.conn_c.process(out.dgram(), now())); } let rv = fr.fr.receive::(&mut StreamReaderConnectionWrapper::new( @@ -318,7 +318,7 @@ fn test_complete_and_incomplete_frame + PartialEq + Debug>( done_state: usize, ) { use std::cmp::Ordering; - // Let's consume partial frames. It is enough to test partal frames + // Let's consume partial frames. It is enough to test partial frames // up to 10 byte. 10 byte is greater than frame type and frame // length and bit of data. let len = std::cmp::min(buf.len() - 1, 10); @@ -417,7 +417,9 @@ fn complete_and_incomplete_frames() { test_complete_and_incomplete_frame::(&buf, buf.len()); // H3_FRAME_TYPE_CANCEL_PUSH - let f = HFrame::CancelPush { push_id: 5 }; + let f = HFrame::CancelPush { + push_id: PushId::new(5), + }; let mut enc = Encoder::default(); f.encode(&mut enc); let buf: Vec<_> = enc.into(); @@ -434,7 +436,7 @@ fn complete_and_incomplete_frames() { // H3_FRAME_TYPE_PUSH_PROMISE let f = HFrame::PushPromise { - push_id: 4, + push_id: PushId::new(4), header_block: HEADER_BLOCK.to_vec(), }; let mut enc = Encoder::default(); @@ -452,7 +454,9 @@ fn complete_and_incomplete_frames() { test_complete_and_incomplete_frame::(&buf, buf.len()); // H3_FRAME_TYPE_MAX_PUSH_ID - let f = HFrame::MaxPushId { push_id: 5 }; + let f = HFrame::MaxPushId { + push_id: PushId::new(5), + }; let mut enc = Encoder::default(); f.encode(&mut enc); let buf: Vec<_> = enc.into(); @@ -479,11 +483,11 @@ fn frame_reading_when_stream_is_closed_before_sending_data() { fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap(); let out = fr.conn_s.process_output(now()); - mem::drop(fr.conn_c.process(out.dgram(), now())); + drop(fr.conn_c.process(out.dgram(), now())); assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id)); let out = fr.conn_c.process_output(now()); - mem::drop(fr.conn_s.process(out.dgram(), now())); + drop(fr.conn_s.process(out.dgram(), now())); assert_eq!( Ok((None, true)), fr.fr @@ -502,11 +506,11 @@ fn wt_frame_reading_when_stream_is_closed_before_sending_data() { fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap(); let out = fr.conn_s.process_output(now()); - mem::drop(fr.conn_c.process(out.dgram(), now())); + drop(fr.conn_c.process(out.dgram(), now())); assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id)); let out = fr.conn_c.process_output(now()); - mem::drop(fr.conn_s.process(out.dgram(), now())); + drop(fr.conn_s.process(out.dgram(), now())); assert_eq!( Ok((None, true)), fr.fr diff --git a/third_party/rust/neqo-http3/src/frames/wtframe.rs b/third_party/rust/neqo-http3/src/frames/wtframe.rs index 519d318d5d59..4a962b5ba5dd 100644 --- a/third_party/rust/neqo-http3/src/frames/wtframe.rs +++ b/third_party/rust/neqo-http3/src/frames/wtframe.rs @@ -37,8 +37,7 @@ impl FrameDecoder for WebTransportFrame { if frame_len > WT_FRAME_CLOSE_MAX_MESSAGE_SIZE + 4 { return Err(Error::HttpMessageError); } - let error = - u32::try_from(dec.decode_uint(4).ok_or(Error::HttpMessageError)?).unwrap(); + let error = dec.decode_uint().ok_or(Error::HttpMessageError)?; let Ok(message) = String::from_utf8(dec.decode_remainder().to_vec()) else { return Err(Error::HttpMessageError); }; diff --git a/third_party/rust/neqo-http3/src/headers_checks.rs b/third_party/rust/neqo-http3/src/headers_checks.rs index e5678dc28c97..245e0f6f1109 100644 --- a/third_party/rust/neqo-http3/src/headers_checks.rs +++ b/third_party/rust/neqo-http3/src/headers_checks.rs @@ -5,7 +5,7 @@ // except according to those terms. use enumset::{enum_set, EnumSet, EnumSetType}; -use neqo_common::Header; +use neqo_common::{header::HeadersExt as _, Header}; use crate::{Error, MessageType, Res}; @@ -49,10 +49,9 @@ impl TryFrom<(MessageType, &str)> for PseudoHeaderState { /// Returns an error if response headers do not contain /// a status header or if the value of the header is 101 or cannot be parsed. pub fn is_interim(headers: &[Header]) -> Res { - let status = headers.iter().take(1).find(|h| h.name() == ":status"); - if let Some(h) = status { + if let Some(h) = headers.iter().take(1).find_header(":status") { #[allow(clippy::map_err_ignore)] - let status_code = h.value().parse::().map_err(|_| Error::InvalidHeader)?; + let status_code = h.value().parse::().map_err(|_| Error::InvalidHeader)?; if status_code == 101 { // https://datatracker.ietf.org/doc/html/draft-ietf-quic-http#section-4.3 Err(Error::InvalidHeader) @@ -224,4 +223,18 @@ mod tests { fn valid_webtransport_connect() { assert!(headers_valid(&create_connect_headers(), MessageType::Request).is_ok()); } + + #[test] + fn invalid_webtransport_connect_with_status() { + assert!(headers_valid( + [ + create_connect_headers(), + vec![Header::new(":status", "200")] + ] + .concat() + .as_slice(), + MessageType::Request + ) + .is_err()); + } } diff --git a/third_party/rust/neqo-http3/src/lib.rs b/third_party/rust/neqo-http3/src/lib.rs index a01b00e1a7b7..5f566549ea8b 100644 --- a/third_party/rust/neqo-http3/src/lib.rs +++ b/third_party/rust/neqo-http3/src/lib.rs @@ -145,6 +145,7 @@ mod frames; mod headers_checks; mod priority; mod push_controller; +mod push_id; mod qlog; mod qpack_decoder_receiver; mod qpack_encoder_receiver; @@ -174,6 +175,7 @@ use neqo_transport::{ AppError, Connection, Error as TransportError, RecvStreamStats, SendStreamStats, }; pub use priority::Priority; +pub use push_id::PushId; pub use server::Http3Server; pub use server_events::{ Http3OrWebTransportStream, Http3ServerEvent, WebTransportRequest, WebTransportServerEvent, diff --git a/third_party/rust/neqo-http3/src/push_controller.rs b/third_party/rust/neqo-http3/src/push_controller.rs index 6881ce7174e8..c4bb9f17f24a 100644 --- a/third_party/rust/neqo-http3/src/push_controller.rs +++ b/third_party/rust/neqo-http3/src/push_controller.rs @@ -20,7 +20,7 @@ use crate::{ client_events::{Http3ClientEvent, Http3ClientEvents}, connection::Http3Connection, frames::HFrame, - CloseType, Error, Http3StreamInfo, HttpRecvStreamEvents, RecvStreamEvents, Res, + CloseType, Error, Http3StreamInfo, HttpRecvStreamEvents, PushId, RecvStreamEvents, Res, }; /// `PushStates`: @@ -57,27 +57,27 @@ enum PushState { #[derive(Debug)] struct ActivePushStreams { push_streams: VecDeque, - first_push_id: u64, + first_push_id: PushId, } impl ActivePushStreams { pub const fn new() -> Self { Self { push_streams: VecDeque::new(), - first_push_id: 0, + first_push_id: PushId::new(0), } } /// Returns None if a stream has been closed already. pub fn get_mut( &mut self, - push_id: u64, + push_id: PushId, ) -> Option<&mut >::Output> { if push_id < self.first_push_id { return None; } - let inx = usize::try_from(push_id - self.first_push_id).unwrap(); + let inx = usize::try_from(u64::from(push_id - self.first_push_id)).unwrap(); if inx >= self.push_streams.len() { self.push_streams.resize(inx + 1, PushState::Init); } @@ -88,19 +88,19 @@ impl ActivePushStreams { } /// Returns None if a stream has been closed already. - pub fn get(&mut self, push_id: u64) -> Option<&mut PushState> { + pub fn get(&mut self, push_id: PushId) -> Option<&mut PushState> { self.get_mut(push_id) } /// Returns the State of a closed push stream or None for already closed streams. - pub fn close(&mut self, push_id: u64) -> Option { + pub fn close(&mut self, push_id: PushId) -> Option { match self.get_mut(push_id) { None | Some(PushState::Closed) => None, Some(s) => { let res = mem::replace(s, PushState::Closed); while self.push_streams.front() == Some(&PushState::Closed) { self.push_streams.pop_front(); - self.first_push_id += 1; + self.first_push_id.next(); } Some(res) } @@ -108,7 +108,7 @@ impl ActivePushStreams { } #[must_use] - pub fn number_done(&self) -> u64 { + pub fn number_done(&self) -> PushId { self.first_push_id + u64::try_from( self.push_streams @@ -120,7 +120,7 @@ impl ActivePushStreams { } pub fn clear(&mut self) { - self.first_push_id = 0; + self.first_push_id = PushId::new(0); self.push_streams.clear(); } } @@ -135,7 +135,7 @@ impl ActivePushStreams { /// /// The `PushController` handles: /// `PUSH_PROMISE` frame: frames may change the push state from Init to `PushPromise` and from -/// `OnlyPushStream` to `Active`. Frames for a closed steams are ignored. +/// `OnlyPushStream` to `Active`. Frames for a closed streams are ignored. /// `CANCEL_PUSH` frame: (`handle_cancel_push` will be called). If a push is in state `PushPromise` /// or `Active`, any posted events will be removed and a `PushCanceled` event /// will be posted. If a push is in state `OnlyPushStream` or `Active` the @@ -146,7 +146,7 @@ impl ActivePushStreams { #[derive(Debug)] pub struct PushController { max_concurent_push: u64, - current_max_push_id: u64, + current_max_push_id: PushId, // push_streams holds the states of push streams. // We keep a stream until the stream has been closed. push_streams: ActivePushStreams, @@ -156,24 +156,22 @@ pub struct PushController { conn_events: Http3ClientEvents, } +impl Display for PushController { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "Push controller") + } +} + impl PushController { pub const fn new(max_concurent_push: u64, conn_events: Http3ClientEvents) -> Self { Self { max_concurent_push, - current_max_push_id: 0, + current_max_push_id: PushId::new(0), push_streams: ActivePushStreams::new(), conn_events, } } -} -impl Display for PushController { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Push controler") - } -} - -impl PushController { /// A new `push_promise` has been received. /// /// # Errors @@ -181,15 +179,12 @@ impl PushController { /// `HttpId` if `push_id` greater than it is allowed has been received. pub fn new_push_promise( &mut self, - push_id: u64, + push_id: PushId, ref_stream_id: StreamId, new_headers: Vec
, ) -> Res<()> { qtrace!( - [self], - "New push promise push_id={} headers={:?} max_push={}", - push_id, - new_headers, + "[{self}] New push promise push_id={push_id} headers={new_headers:?} max_push={}", self.max_concurent_push ); @@ -197,7 +192,7 @@ impl PushController { match self.push_streams.get_mut(push_id) { None => { - qtrace!("Push has been closed already {}.", push_id); + qtrace!("Push has been closed already {push_id}"); Ok(()) } Some(push_state) => match push_state { @@ -236,18 +231,13 @@ impl PushController { } } - pub fn add_new_push_stream(&mut self, push_id: u64, stream_id: StreamId) -> Res { - qtrace!( - "A new push stream with push_id={} stream_id={}", - push_id, - stream_id - ); - + pub fn add_new_push_stream(&mut self, push_id: PushId, stream_id: StreamId) -> Res { + qtrace!("A new push stream with push_id={push_id} stream_id={stream_id}"); self.check_push_id(push_id)?; self.push_streams.get_mut(push_id).map_or_else( || { - qinfo!("Push has been closed already."); + qinfo!("Push has been closed already"); Ok(false) }, |push_state| match push_state { @@ -269,17 +259,17 @@ impl PushController { // The following state have already have a push stream: // PushState::OnlyPushStream | PushState::Active _ => { - qerror!("Duplicate push stream."); + qerror!("Duplicate push stream"); Err(Error::HttpId) } }, ) } - fn check_push_id(&self, push_id: u64) -> Res<()> { + fn check_push_id(&self, push_id: PushId) -> Res<()> { // Check if push id is greater than what we allow. if push_id > self.current_max_push_id { - qerror!("Push id is greater than current_max_push_id."); + qerror!("Push id is greater than current_max_push_id"); Err(Error::HttpId) } else { Ok(()) @@ -288,17 +278,17 @@ impl PushController { pub fn handle_cancel_push( &mut self, - push_id: u64, + push_id: PushId, conn: &mut Connection, base_handler: &mut Http3Connection, ) -> Res<()> { - qtrace!("CANCEL_PUSH frame has been received, push_id={}", push_id); + qtrace!("CANCEL_PUSH frame has been received, push_id={push_id}"); self.check_push_id(push_id)?; match self.push_streams.close(push_id) { None => { - qtrace!("Push has already been closed (push_id={}).", push_id); + qtrace!("Push has already been closed (push_id={push_id})"); Ok(()) } Some(ps) => match ps { @@ -310,7 +300,7 @@ impl PushController { } PushState::OnlyPushStream { stream_id, .. } | PushState::Active { stream_id, .. } => { - mem::drop(base_handler.stream_stop_sending( + drop(base_handler.stream_stop_sending( conn, stream_id, Error::HttpRequestCancelled.code(), @@ -324,8 +314,8 @@ impl PushController { } } - pub fn close(&mut self, push_id: u64) { - qtrace!("Push stream has been closed."); + pub fn close(&mut self, push_id: PushId) { + qtrace!("Push stream has been closed"); if let Some(push_state) = self.push_streams.close(push_id) { debug_assert!(matches!(push_state, PushState::Active { .. })); } else { @@ -335,17 +325,17 @@ impl PushController { pub fn cancel( &mut self, - push_id: u64, + push_id: PushId, conn: &mut Connection, base_handler: &mut Http3Connection, ) -> Res<()> { - qtrace!("Cancel push_id={}", push_id); + qtrace!("Cancel push_id={push_id}"); self.check_push_id(push_id)?; match self.push_streams.get(push_id) { None => { - qtrace!("Push has already been closed."); + qtrace!("Push has already been closed"); // If we have some events for the push_id in the event queue, the caller still does // not not know that the push has been closed. Otherwise return // InvalidStreamId. @@ -365,7 +355,7 @@ impl PushController { Some(PushState::Active { stream_id, .. }) => { self.conn_events.remove_events_for_push_id(push_id); // Cancel the stream. The transport stream may already be done, so ignore an error. - mem::drop(base_handler.stream_stop_sending( + drop(base_handler.stream_stop_sending( conn, *stream_id, Error::HttpRequestCancelled.code(), @@ -377,9 +367,8 @@ impl PushController { } } - pub fn push_stream_reset(&mut self, push_id: u64, close_type: CloseType) { - qtrace!("Push stream has been reset, push_id={}", push_id); - + pub fn push_stream_reset(&mut self, push_id: PushId, close_type: CloseType) { + qtrace!("Push stream has been reset, push_id={push_id}"); if let Some(push_state) = self.push_streams.get(push_id) { match push_state { PushState::OnlyPushStream { .. } => { @@ -397,14 +386,14 @@ impl PushController { _ => { debug_assert!( false, - "Reset cannot actually happen because we do not have a stream." + "Reset cannot actually happen because we do not have a stream" ); } } } } - pub fn get_active_stream_id(&mut self, push_id: u64) -> Option { + pub fn get_active_stream_id(&mut self, push_id: PushId) -> Option { match self.push_streams.get(push_id) { Some(PushState::Active { stream_id, .. }) => Some(*stream_id), _ => None, @@ -414,7 +403,7 @@ impl PushController { pub fn maybe_send_max_push_id_frame(&mut self, base_handler: &mut Http3Connection) { let push_done = self.push_streams.number_done(); if self.max_concurent_push > 0 - && (self.current_max_push_id - push_done) <= (self.max_concurent_push / 2) + && (self.current_max_push_id - push_done) <= (self.max_concurent_push / 2).into() { self.current_max_push_id = push_done + self.max_concurent_push; base_handler.queue_control_frame(&HFrame::MaxPushId { @@ -424,7 +413,7 @@ impl PushController { } pub fn handle_zero_rtt_rejected(&mut self) { - self.current_max_push_id = 0; + self.current_max_push_id = PushId::new(0); } pub fn clear(&mut self) { @@ -435,10 +424,10 @@ impl PushController { self.max_concurent_push > 0 } - pub fn new_stream_event(&mut self, push_id: u64, event: Http3ClientEvent) { + pub fn new_stream_event(&mut self, push_id: PushId, event: Http3ClientEvent) { match self.push_streams.get_mut(push_id) { None => { - debug_assert!(false, "Push has been closed already."); + debug_assert!(false, "Push has been closed already"); } Some(PushState::OnlyPushStream { events, .. }) => { events.push(event); @@ -460,12 +449,12 @@ impl PushController { /// a `push_promise` has not been yet received for the stream. #[derive(Debug)] pub struct RecvPushEvents { - push_id: u64, + push_id: PushId, push_handler: Rc>, } impl RecvPushEvents { - pub const fn new(push_id: u64, push_handler: Rc>) -> Self { + pub const fn new(push_id: PushId, push_handler: Rc>) -> Self { Self { push_id, push_handler, diff --git a/third_party/rust/neqo-http3/src/push_id.rs b/third_party/rust/neqo-http3/src/push_id.rs new file mode 100644 index 000000000000..72398f65f2c5 --- /dev/null +++ b/third_party/rust/neqo-http3/src/push_id.rs @@ -0,0 +1,55 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::{Add, Sub}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)] +pub struct PushId(u64); + +impl PushId { + #[must_use] + pub const fn new(id: u64) -> Self { + Self(id) + } + + pub fn next(&mut self) { + self.0 += 1; + } +} + +impl From for PushId { + fn from(id: u64) -> Self { + Self(id) + } +} + +impl From for u64 { + fn from(id: PushId) -> Self { + id.0 + } +} + +impl ::std::fmt::Display for PushId { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Sub for PushId { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + Self(self.0 - rhs.0) + } +} + +impl Add for PushId { + type Output = Self; + + fn add(self, rhs: u64) -> Self { + Self(self.0 + rhs) + } +} diff --git a/third_party/rust/neqo-http3/src/recv_message.rs b/third_party/rust/neqo-http3/src/recv_message.rs index cb85cdb6e66e..b64b0bffc39f 100644 --- a/third_party/rust/neqo-http3/src/recv_message.rs +++ b/third_party/rust/neqo-http3/src/recv_message.rs @@ -6,7 +6,7 @@ use std::{cell::RefCell, cmp::min, collections::VecDeque, fmt::Debug, rc::Rc}; -use neqo_common::{qdebug, qinfo, qtrace, Header}; +use neqo_common::{header::HeadersExt as _, qdebug, qinfo, qtrace, Header}; use neqo_qpack::decoder::QPackDecoder; use neqo_transport::{Connection, StreamId}; @@ -16,7 +16,7 @@ use crate::{ priority::PriorityHandler, push_controller::PushController, qlog, CloseType, Error, Http3StreamInfo, Http3StreamType, HttpRecvStream, HttpRecvStreamEvents, - MessageType, Priority, ReceiveOutput, RecvStream, Res, Stream, + MessageType, Priority, PushId, ReceiveOutput, RecvStream, Res, Stream, }; #[allow(clippy::module_name_repetitions)] @@ -61,7 +61,7 @@ enum RecvMessageState { #[derive(Debug)] struct PushInfo { - push_id: u64, + push_id: PushId, header_block: Vec, } @@ -126,7 +126,7 @@ impl RecvMessage { RecvMessageState::WaitingForFinAfterTrailers {..} => { return Err(Error::HttpFrameUnexpected); } - _ => unreachable!("This functions is only called in WaitingForResponseHeaders | WaitingForData | WaitingForFinAfterTrailers state.") + _ => unreachable!("This functions is only called in WaitingForResponseHeaders | WaitingForData | WaitingForFinAfterTrailers state") } Ok(()) } @@ -146,13 +146,13 @@ impl RecvMessage { }; } } - _ => unreachable!("This functions is only called in WaitingForResponseHeaders | WaitingForData | WaitingForFinAfterTrailers state.") + _ => unreachable!("This functions is only called in WaitingForResponseHeaders | WaitingForData | WaitingForFinAfterTrailers state") } Ok(()) } fn add_headers(&mut self, mut headers: Vec
, fin: bool) -> Res<()> { - qtrace!([self], "Add new headers fin={}", fin); + qtrace!("[{self}] Add new headers fin={fin}"); let interim = match self.message_type { MessageType::Request => false, MessageType::Response => is_interim(&headers)?, @@ -167,12 +167,8 @@ impl RecvMessage { } let is_web_transport = self.message_type == MessageType::Request - && headers - .iter() - .any(|h| h.name() == ":method" && h.value() == "CONNECT") - && headers - .iter() - .any(|h| h.name() == ":protocol" && h.value() == "webtransport"); + && headers.contains_header(":method", "CONNECT") + && headers.contains_header(":protocol", "webtransport"); if is_web_transport { self.conn_events .extended_connect_new_session(self.stream_id, headers); @@ -203,7 +199,10 @@ impl RecvMessage { fn set_state_to_close_pending(&mut self, post_readable_event: bool) -> Res<()> { // Stream has received fin. Depending on headers state set header_ready // or data_readable event so that app can pick up the fin. - qtrace!([self], "set_state_to_close_pending: state={:?}", self.state); + qtrace!( + "[{self}] set_state_to_close_pending: state={:?}", + self.state + ); match self.state { RecvMessageState::WaitingForResponseHeaders { .. } => { @@ -216,7 +215,7 @@ impl RecvMessage { self.conn_events.data_readable(self.get_stream_info()); } } - _ => unreachable!("Closing an already closed transaction."), + _ => unreachable!("Closing an already closed transaction"), } if !matches!(self.state, RecvMessageState::Closed) { self.state = RecvMessageState::ClosePending; @@ -224,7 +223,7 @@ impl RecvMessage { Ok(()) } - fn handle_push_promise(&mut self, push_id: u64, header_block: Vec) -> Res<()> { + fn handle_push_promise(&mut self, push_id: PushId, header_block: Vec) -> Res<()> { if self.push_handler.is_none() { return Err(Error::HttpFrameUnexpected); } @@ -254,9 +253,8 @@ impl RecvMessage { } fn receive_internal(&mut self, conn: &mut Connection, post_readable_event: bool) -> Res<()> { - let label = ::neqo_common::log_subject!(::log::Level::Debug, self); loop { - qdebug!([label], "state={:?}.", self.state); + qdebug!("[{self}] state={:?}", self.state); match &mut self.state { // In the following 3 states we need to read frames. RecvMessageState::WaitingForResponseHeaders { frame_reader } @@ -272,11 +270,7 @@ impl RecvMessage { (None, false) => break Ok(()), (Some(frame), fin) => { qdebug!( - [self], - "A new frame has been received: {:?}; state={:?} fin={}", - frame, - self.state, - fin, + "[{self}] A new frame has been received: {frame:?}; state={:?} fin={fin}", self.state, ); match frame { HFrame::Headers { header_block } => { @@ -300,10 +294,7 @@ impl RecvMessage { } }; } - RecvMessageState::DecodingHeaders { - ref header_block, - fin, - } => { + RecvMessageState::DecodingHeaders { header_block, fin } => { if self .qpack_decoder .borrow() @@ -311,8 +302,7 @@ impl RecvMessage { && !self.blocked_push_promise.is_empty() { qinfo!( - [self], - "decoding header is blocked waiting for a push_promise header block." + "[{self}] decoding header is blocked waiting for a push_promise header block" ); break Ok(()); } @@ -330,7 +320,7 @@ impl RecvMessage { break Ok(()); } } else { - qinfo!([self], "decoding header is blocked."); + qinfo!("[{self}] decoding header is blocked"); break Ok(()); } } diff --git a/third_party/rust/neqo-http3/src/send_message.rs b/third_party/rust/neqo-http3/src/send_message.rs index 378786d12fdd..3fbaefa5a665 100644 --- a/third_party/rust/neqo-http3/src/send_message.rs +++ b/third_party/rust/neqo-http3/src/send_message.rs @@ -119,7 +119,7 @@ impl SendMessage { encoder: Rc>, conn_events: Box, ) -> Self { - qdebug!("Create a request stream_id={}", stream_id); + qdebug!("Create a request stream_id={stream_id}"); Self { state: MessageState::WaitingForHeaders, message_type, @@ -166,7 +166,7 @@ impl Stream for SendMessage { } impl SendStream for SendMessage { fn send_data(&mut self, conn: &mut Connection, buf: &[u8]) -> Res { - qtrace!([self], "send_body: len={}", buf.len()); + qtrace!("[{self}] send_body: len={}", buf.len()); self.state.new_data()?; @@ -200,12 +200,7 @@ impl SendStream for SendMessage { min(buf.len(), available - 9) }; - qdebug!( - [self], - "send_request_body: available={} to_send={}.", - available, - to_send - ); + qdebug!("[{self}] send_request_body: available={available} to_send={to_send}"); let data_frame = HFrame::Data { len: to_send as u64, @@ -250,14 +245,14 @@ impl SendStream for SendMessage { fn send(&mut self, conn: &mut Connection) -> Res<()> { let sent = Error::map_error(self.stream.send_buffer(conn), Error::HttpInternal(5))?; - qtrace!([self], "{} bytes sent", sent); + qtrace!("[{self}] {sent} bytes sent"); if !self.stream.has_buffered_data() { if self.state.done() { Error::map_error( conn.stream_close_send(self.stream_id()), Error::HttpInternal(6), )?; - qtrace!([self], "done sending request"); + qtrace!("[{self}] done sending request"); } else { // DataWritable is just a signal for an application to try to write more data, // if writing fails it is fine. Therefore we do not need to properly check diff --git a/third_party/rust/neqo-http3/src/server.rs b/third_party/rust/neqo-http3/src/server.rs index 798fd7c70cef..ad8025f55f74 100644 --- a/third_party/rust/neqo-http3/src/server.rs +++ b/third_party/rust/neqo-http3/src/server.rs @@ -119,13 +119,13 @@ impl Http3Server { } pub fn process(&mut self, dgram: Option>>, now: Instant) -> Output { - qtrace!([self], "Process."); + qtrace!("[{self}] Process"); let out = self.server.process(dgram, now); self.process_http3(now); // If we do not that a dgram already try again after process_http3. match out { Output::Datagram(d) => { - qtrace!([self], "Send packet: {:?}", d); + qtrace!("[{self}] Send packet: {d:?}"); Output::Datagram(d) } _ => self.server.process(Option::::None, now), @@ -134,7 +134,7 @@ impl Http3Server { /// Process HTTP3 layer. fn process_http3(&mut self, now: Instant) { - qtrace!([self], "Process http3 internal."); + qtrace!("[{self}] Process http3 internal"); // `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable // types. #[allow(clippy::mutable_key_type)] @@ -152,6 +152,7 @@ impl Http3Server { } } + #[allow(clippy::too_many_lines)] fn process_events(&mut self, conn: &ConnectionRef, now: Instant) { let mut remove = false; let http3_parameters = &self.http3_parameters; @@ -172,7 +173,11 @@ impl Http3Server { headers, fin, } => self.events.headers( - Http3OrWebTransportStream::new(conn.clone(), handler.clone(), stream_info), + Http3OrWebTransportStream::new( + conn.clone(), + Rc::clone(handler), + stream_info, + ), headers, fin, ), @@ -188,15 +193,19 @@ impl Http3Server { } Http3ServerConnEvent::DataWritable { stream_info } => self .events - .data_writable(conn.clone(), handler.clone(), stream_info), + .data_writable(conn.clone(), Rc::clone(handler), stream_info), Http3ServerConnEvent::StreamReset { stream_info, error } => { - self.events - .stream_reset(conn.clone(), handler.clone(), stream_info, error); + self.events.stream_reset( + conn.clone(), + Rc::clone(handler), + stream_info, + error, + ); } Http3ServerConnEvent::StreamStopSending { stream_info, error } => { self.events.stream_stop_sending( conn.clone(), - handler.clone(), + Rc::clone(handler), stream_info, error, ); @@ -216,7 +225,7 @@ impl Http3Server { } Http3ServerConnEvent::ExtendedConnect { stream_id, headers } => { self.events.webtransport_new_session( - WebTransportRequest::new(conn.clone(), handler.clone(), stream_id), + WebTransportRequest::new(conn.clone(), Rc::clone(handler), stream_id), headers, ); } @@ -226,7 +235,7 @@ impl Http3Server { headers, .. } => self.events.webtransport_session_closed( - WebTransportRequest::new(conn.clone(), handler.clone(), stream_id), + WebTransportRequest::new(conn.clone(), Rc::clone(handler), stream_id), reason, headers, ), @@ -234,14 +243,14 @@ impl Http3Server { .events .webtransport_new_stream(Http3OrWebTransportStream::new( conn.clone(), - handler.clone(), + Rc::clone(handler), stream_info, )), Http3ServerConnEvent::ExtendedConnectDatagram { session_id, datagram, } => self.events.webtransport_datagram( - WebTransportRequest::new(conn.clone(), handler.clone(), session_id), + WebTransportRequest::new(conn.clone(), Rc::clone(handler), session_id), datagram, ), } @@ -294,7 +303,7 @@ fn prepare_data( data.resize(amount, 0); } - events.data(conn.clone(), handler.clone(), stream_info, data, fin); + events.data(conn.clone(), Rc::clone(handler), stream_info, data, fin); } if amount < MAX_EVENT_DATA_SIZE || fin { break; @@ -311,11 +320,10 @@ fn prepare_data( mod tests { use std::{ collections::HashMap, - mem, ops::{Deref, DerefMut}, }; - use neqo_common::{event::Provider, Encoder}; + use neqo_common::{event::Provider as _, Encoder}; use neqo_crypto::{AuthenticationStatus, ZeroRttCheckResult, ZeroRttChecker}; use neqo_qpack::{encoder::QPackEncoder, QpackSettings}; use neqo_transport::{ @@ -502,11 +510,11 @@ mod tests { (server, client) } - // Test http3 connection inintialization. + // Test http3 connection initialization. // The server will open the control and qpack streams and send SETTINGS frame. #[test] fn server_connect() { - mem::drop(connect_and_receive_settings()); + drop(connect_and_receive_settings()); } struct PeerConnection { @@ -559,9 +567,9 @@ mod tests { assert_eq!(sent, Ok(1)); let out1 = neqo_trans_conn.process_output(now()); let out2 = server.process(out1.dgram(), now()); - mem::drop(neqo_trans_conn.process(out2.dgram(), now())); + drop(neqo_trans_conn.process(out2.dgram(), now())); - // assert no error occured. + // assert no error occurred. assert_not_closed(server); PeerConnection { @@ -579,7 +587,7 @@ mod tests { // Server: Test receiving a new control stream and a SETTINGS frame. #[test] fn server_receive_control_frame() { - mem::drop(connect()); + drop(connect()); } // Server: Test that the connection will be closed if control stream @@ -685,13 +693,13 @@ mod tests { test_wrong_frame_on_control_stream(&[0x0, 0x2, 0x1, 0x2]); } - // send HEADERS frame on a cortrol stream + // send HEADERS frame on a control stream #[test] fn server_headers_frame_on_control_stream() { test_wrong_frame_on_control_stream(&[0x1, 0x2, 0x1, 0x2]); } - // send PUSH_PROMISE frame on a cortrol stream + // send PUSH_PROMISE frame on a control stream #[test] fn server_push_promise_frame_on_control_stream() { test_wrong_frame_on_control_stream(&[0x5, 0x2, 0x1, 0x2]); @@ -710,9 +718,9 @@ mod tests { .unwrap(); let out = peer_conn.process_output(now()); let out = hconn.process(out.dgram(), now()); - mem::drop(peer_conn.process(out.dgram(), now())); + drop(peer_conn.process(out.dgram(), now())); let out = hconn.process_output(now()); - mem::drop(peer_conn.process(out.dgram(), now())); + drop(peer_conn.process(out.dgram(), now())); // check for stop-sending with Error::HttpStreamCreation. let mut stop_sending_event_found = false; @@ -741,7 +749,7 @@ mod tests { _ = peer_conn.stream_send(push_stream_id, &[0x1]).unwrap(); let out = peer_conn.process_output(now()); let out = hconn.process(out.dgram(), now()); - mem::drop(peer_conn.conn.process(out.dgram(), now())); + drop(peer_conn.conn.process(out.dgram(), now())); assert_closed(&hconn, &Error::HttpStreamCreation); } @@ -836,7 +844,7 @@ mod tests { fn test_incomplete_frame(res: &[u8]) { let (mut hconn, mut peer_conn) = connect_and_receive_settings(); - // send an incomplete reequest. + // send an incomplete request. let stream_id = peer_conn.stream_create(StreamType::BiDi).unwrap(); peer_conn.stream_send(stream_id, res).unwrap(); peer_conn.stream_close_send(stream_id).unwrap(); diff --git a/third_party/rust/neqo-http3/src/server_events.rs b/third_party/rust/neqo-http3/src/server_events.rs index 3f174ba0a039..54ff3ebda30a 100644 --- a/third_party/rust/neqo-http3/src/server_events.rs +++ b/third_party/rust/neqo-http3/src/server_events.rs @@ -35,7 +35,7 @@ pub struct StreamHandler { impl ::std::fmt::Display for StreamHandler { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { let conn: &Connection = &self.conn.borrow(); - write!(f, "conn={} stream_info={:?}", conn, self.stream_info) + write!(f, "conn={conn} stream_info={:?}", self.stream_info) } } @@ -115,10 +115,8 @@ impl StreamHandler { /// It may return `InvalidStreamId` if a stream does not exist anymore. pub fn stream_stop_sending(&self, app_error: AppError) -> Res<()> { qdebug!( - [self], - "stop sending stream_id:{} error:{}.", - self.stream_info.stream_id(), - app_error + "[{self}] stop sending stream_id:{} error:{app_error}", + self.stream_info.stream_id() ); self.handler.borrow_mut().stream_stop_sending( self.stream_info.stream_id(), @@ -134,10 +132,8 @@ impl StreamHandler { /// It may return `InvalidStreamId` if a stream does not exist anymore. pub fn stream_reset_send(&self, app_error: AppError) -> Res<()> { qdebug!( - [self], - "reset send stream_id:{} error:{}.", - self.stream_info.stream_id(), - app_error + "[{self}] reset send stream_id:{} error:{app_error}", + self.stream_info.stream_id() ); self.handler.borrow_mut().stream_reset_send( self.stream_info.stream_id(), @@ -152,7 +148,7 @@ impl StreamHandler { /// /// It may return `InvalidStreamId` if a stream does not exist anymore pub fn cancel_fetch(&self, app_error: AppError) -> Res<()> { - qdebug!([self], "reset error:{}.", app_error); + qdebug!("[{self}] reset error:{app_error}"); self.handler.borrow_mut().cancel_fetch( self.stream_info.stream_id(), app_error, @@ -202,7 +198,7 @@ impl Http3OrWebTransportStream { /// /// It may return `InvalidStreamId` if a stream does not exist anymore. pub fn send_data(&self, data: &[u8]) -> Res { - qdebug!([self], "Set new response."); + qdebug!("[{self}] Set new response"); self.stream_handler.send_data(data) } @@ -212,7 +208,7 @@ impl Http3OrWebTransportStream { /// /// It may return `InvalidStreamId` if a stream does not exist anymore. pub fn stream_close_send(&self) -> Res<()> { - qdebug!([self], "Set new response."); + qdebug!("[{self}] Set new response"); self.stream_handler.stream_close_send() } } @@ -283,7 +279,7 @@ impl WebTransportRequest { /// /// It may return `InvalidStreamId` if a stream does not exist anymore. pub fn response(&self, accept: &WebTransportSessionAcceptAction) -> Res<()> { - qdebug!([self], "Set a response for a WebTransport session."); + qdebug!("[{self}] Set a response for a WebTransport session"); self.stream_handler .handler .borrow_mut() @@ -335,7 +331,7 @@ impl WebTransportRequest { Ok(Http3OrWebTransportStream::new( self.stream_handler.conn.clone(), - self.stream_handler.handler.clone(), + Rc::clone(&self.stream_handler.handler), Http3StreamInfo::new(id, Http3StreamType::WebTransport(session_id)), )) } diff --git a/third_party/rust/neqo-http3/src/stream_type_reader.rs b/third_party/rust/neqo-http3/src/stream_type_reader.rs index 8ab8e404b3d0..645b46b810f6 100644 --- a/third_party/rust/neqo-http3/src/stream_type_reader.rs +++ b/third_party/rust/neqo-http3/src/stream_type_reader.rs @@ -11,7 +11,7 @@ use neqo_transport::{Connection, StreamId, StreamType}; use crate::{ control_stream_local::HTTP3_UNI_STREAM_TYPE_CONTROL, frames::{hframe::HFrameType, reader::FrameDecoder, HFrame, H3_FRAME_TYPE_HEADERS}, - CloseType, Error, Http3StreamType, ReceiveOutput, RecvStream, Res, Stream, + CloseType, Error, Http3StreamType, PushId, ReceiveOutput, RecvStream, Res, Stream, }; pub const HTTP3_UNI_STREAM_TYPE_PUSH: u64 = 0x1; @@ -23,7 +23,7 @@ pub enum NewStreamType { Control, Decoder, Encoder, - Push(u64), + Push(PushId), WebTransportStream(u64), Http(u64), Unknown, @@ -137,7 +137,7 @@ impl NewStreamHeadReader { return Ok(None); }; - qtrace!("Decoded uint {}", output); + qtrace!("Decoded uint {output}"); match self { Self::ReadType { role, stream_id, .. @@ -178,12 +178,12 @@ impl NewStreamHeadReader { Self::ReadId { stream_type, .. } => { let is_push = *stream_type == HTTP3_UNI_STREAM_TYPE_PUSH; *self = Self::Done; - qtrace!("New Stream stream push_id={}", output); + qtrace!("New Stream stream push_id={output}"); if fin { return Err(Error::HttpGeneralProtocol); } return if is_push { - Ok(Some(NewStreamType::Push(output))) + Ok(Some(NewStreamType::Push(PushId::new(output)))) } else { Ok(Some(NewStreamType::WebTransportStream(output))) }; @@ -204,7 +204,7 @@ impl NewStreamHeadReader { Some(NewStreamType::Http(_)) => Err(Error::HttpFrame), Some(NewStreamType::Unknown) => Ok(decoded), Some(NewStreamType::Push(_) | NewStreamType::WebTransportStream(_)) => { - unreachable!("PushStream and WebTransport are mapped to None at this stage.") + unreachable!("PushStream and WebTransport are mapped to None at this stage") } } } @@ -237,8 +237,6 @@ impl RecvStream for NewStreamHeadReader { #[cfg(test)] mod tests { - use std::mem; - use neqo_common::{Encoder, Role}; use neqo_qpack::{ decoder::QPACK_UNI_STREAM_TYPE_DECODER, encoder::QPACK_UNI_STREAM_TYPE_ENCODER, @@ -253,7 +251,7 @@ mod tests { use crate::{ control_stream_local::HTTP3_UNI_STREAM_TYPE_CONTROL, frames::{H3_FRAME_TYPE_HEADERS, H3_FRAME_TYPE_SETTINGS}, - CloseType, Error, NewStreamType, ReceiveOutput, RecvStream, Res, + CloseType, Error, NewStreamType, PushId, ReceiveOutput, RecvStream as _, Res, }; struct Test { @@ -269,7 +267,7 @@ mod tests { // create a stream let stream_id = conn_s.stream_create(stream_type).unwrap(); let out = conn_s.process_output(now()); - mem::drop(conn_c.process(out.dgram(), now())); + drop(conn_c.process(out.dgram(), now())); Self { conn_c, @@ -292,7 +290,7 @@ mod tests { .stream_send(self.stream_id, &enc[i..=i]) .unwrap(); let out = self.conn_s.process_output(now()); - mem::drop(self.conn_c.process(out.dgram(), now())); + drop(self.conn_c.process(out.dgram(), now())); assert_eq!( self.decoder.receive(&mut self.conn_c).unwrap(), (ReceiveOutput::NoOutput, false) @@ -306,7 +304,7 @@ mod tests { self.conn_s.stream_close_send(self.stream_id).unwrap(); } let out = self.conn_s.process_output(now()); - mem::drop(self.conn_c.process(out.dgram(), now())); + drop(self.conn_c.process(out.dgram(), now())); assert_eq!(&self.decoder.receive(&mut self.conn_c), outcome); assert_eq!(self.decoder.done(), done); } @@ -366,7 +364,7 @@ mod tests { &[HTTP3_UNI_STREAM_TYPE_PUSH, 0xaaaa_aaaa], false, &Ok(( - ReceiveOutput::NewStream(NewStreamType::Push(0xaaaa_aaaa)), + ReceiveOutput::NewStream(NewStreamType::Push(PushId::new(0xaaaa_aaaa))), true, )), true, @@ -429,7 +427,7 @@ mod tests { * HTTP3_UNI_STREAM_TYPE_PUSH */ false, &Ok(( - ReceiveOutput::NewStream(NewStreamType::Push(0xaaaa_aaaa)), + ReceiveOutput::NewStream(NewStreamType::Push(PushId::new(0xaaaa_aaaa))), true, )), true, diff --git a/third_party/rust/neqo-http3/tests/httpconn.rs b/third_party/rust/neqo-http3/tests/httpconn.rs index 5e192e01cc52..90494361c5dc 100644 --- a/third_party/rust/neqo-http3/tests/httpconn.rs +++ b/third_party/rust/neqo-http3/tests/httpconn.rs @@ -4,12 +4,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{ - mem, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; -use neqo_common::{event::Provider, qtrace, Datagram}; +use neqo_common::{event::Provider as _, qtrace, Datagram}; use neqo_crypto::{AuthenticationStatus, ResumptionToken}; use neqo_http3::{ Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server, @@ -97,7 +94,7 @@ fn connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option let out = hconn_c.process_output(now()); // Initial let out = hconn_s.process(out.dgram(), now()); // Initial + Handshake let out = hconn_c.process(out.dgram(), now()); // ACK - mem::drop(hconn_s.process(out.dgram(), now())); // consume ACK + drop(hconn_s.process(out.dgram(), now())); // consume ACK let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded); assert!(hconn_c.events().any(authentication_needed)); hconn_c.authenticated(AuthenticationStatus::Ok, now()); @@ -189,14 +186,14 @@ fn fetch() { let out = hconn_c.process(dgram, now()); qtrace!("-----server"); let out = hconn_s.process(out.dgram(), now()); - mem::drop(hconn_c.process(out.dgram(), now())); + drop(hconn_c.process(out.dgram(), now())); process_server_events(&hconn_s); let out = hconn_s.process(None::, now()); qtrace!("-----client"); - mem::drop(hconn_c.process(out.dgram(), now())); + drop(hconn_c.process(out.dgram(), now())); let out = hconn_s.process(None::, now()); - mem::drop(hconn_c.process(out.dgram(), now())); + drop(hconn_c.process(out.dgram(), now())); process_client_events(&mut hconn_c); } @@ -218,7 +215,7 @@ fn response_103() { let out = hconn_c.process(dgram, now()); let out = hconn_s.process(out.dgram(), now()); - mem::drop(hconn_c.process(out.dgram(), now())); + drop(hconn_c.process(out.dgram(), now())); let request = receive_request(&hconn_s).unwrap(); let info_headers = [ Header::new(":status", "103"), @@ -228,7 +225,7 @@ fn response_103() { request.send_headers(&info_headers).unwrap(); let out = hconn_s.process(None::, now()); - mem::drop(hconn_c.process(out.dgram(), now())); + drop(hconn_c.process(out.dgram(), now())); let info_headers_event = |e| { matches!(e, Http3ClientEvent::HeaderReady { headers, @@ -239,7 +236,7 @@ fn response_103() { set_response(&request); let out = hconn_s.process(None::, now()); - mem::drop(hconn_c.process(out.dgram(), now())); + drop(hconn_c.process(out.dgram(), now())); process_client_events(&mut hconn_c); } @@ -256,7 +253,7 @@ fn data_writable_events_low_watermark() -> Result<(), Box ConnectionParameters::default().max_stream_data(StreamType::BiDi, false, STREAM_LIMIT), )); let mut hconn_s = default_http3_server(); - mem::drop(connect_peers(&mut hconn_c, &mut hconn_s)); + drop(connect_peers(&mut hconn_c, &mut hconn_s)); // Client sends GET to server. let stream_id = hconn_c.fetch( @@ -298,7 +295,7 @@ fn data_writable_events_low_watermark() -> Result<(), Box exchange_packets(&mut hconn_c, &mut hconn_s, None); assert!(hconn_s.events().any(data_writable)); - // Sending more fails, given that each data frame needs to be preceeded by a + // Sending more fails, given that each data frame needs to be preceded by a // header, i.e. needs more than 1 byte of send space to send 1 byte payload. assert_eq!(request.available()?, 1); assert_eq!(request.send_data(&buf)?, 0); @@ -330,7 +327,7 @@ fn data_writable_events() { )); let mut hconn_s = default_http3_server(); - mem::drop(connect_peers(&mut hconn_c, &mut hconn_s)); + drop(connect_peers(&mut hconn_c, &mut hconn_s)); // Create a request. let req = hconn_c @@ -433,7 +430,7 @@ fn zerortt() { let mut hconn_c = default_http3_client(); hconn_c .enable_resumption(now(), &token) - .expect("Set resumption token."); + .expect("Set resumption token"); let mut hconn_s = default_http3_server(); // Create a request. diff --git a/third_party/rust/neqo-http3/tests/priority.rs b/third_party/rust/neqo-http3/tests/priority.rs index cafebe09b5ed..7edb2d03b955 100644 --- a/third_party/rust/neqo-http3/tests/priority.rs +++ b/third_party/rust/neqo-http3/tests/priority.rs @@ -6,7 +6,7 @@ use std::time::Instant; -use neqo_common::event::Provider; +use neqo_common::event::Provider as _; use neqo_crypto::AuthenticationStatus; use neqo_http3::{ Header, Http3Client, Http3ClientEvent, Http3Server, Http3ServerEvent, Http3State, Priority, @@ -25,7 +25,7 @@ fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) { } } -// Perform only Quic transport handshake. +// Perform only QUIC transport handshake. fn connect_with(client: &mut Http3Client, server: &mut Http3Server) { assert_eq!(client.state(), Http3State::Initializing); let out = client.process_output(now()); @@ -45,7 +45,7 @@ fn connect_with(client: &mut Http3Client, server: &mut Http3Server) { assert!(client.events().any(connected)); assert_eq!(client.state(), Http3State::Connected); - // Exchange H3 setttings + // Exchange H3 settings let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); let out = server.process(out.dgram(), now()); @@ -83,11 +83,7 @@ fn priority_update() { }; match header_event { - Http3ServerEvent::Headers { - stream: _, - headers, - fin, - } => { + Http3ServerEvent::Headers { headers, fin, .. } => { let expected_headers = &[ Header::new(":method", "GET"), Header::new(":scheme", "https"), diff --git a/third_party/rust/neqo-http3/tests/send_message.rs b/third_party/rust/neqo-http3/tests/send_message.rs index 19a47cde7cd5..469e79ab7518 100644 --- a/third_party/rust/neqo-http3/tests/send_message.rs +++ b/third_party/rust/neqo-http3/tests/send_message.rs @@ -6,7 +6,7 @@ use std::sync::OnceLock; -use neqo_common::event::Provider; +use neqo_common::event::Provider as _; use neqo_crypto::AuthenticationStatus; use neqo_http3::{ Error, Header, Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Server, diff --git a/third_party/rust/neqo-http3/tests/webtransport.rs b/third_party/rust/neqo-http3/tests/webtransport.rs index b2d2d571fbb4..6291020f5810 100644 --- a/third_party/rust/neqo-http3/tests/webtransport.rs +++ b/third_party/rust/neqo-http3/tests/webtransport.rs @@ -6,14 +6,14 @@ use std::{cell::RefCell, rc::Rc}; -use neqo_common::{event::Provider, Header}; +use neqo_common::{event::Provider as _, header::HeadersExt as _}; use neqo_crypto::AuthenticationStatus; use neqo_http3::{ Http3Client, Http3ClientEvent, Http3OrWebTransportStream, Http3Parameters, Http3Server, Http3ServerEvent, Http3State, WebTransportEvent, WebTransportRequest, WebTransportServerEvent, WebTransportSessionAcceptAction, }; -use neqo_transport::{StreamId, StreamType}; +use neqo_transport::{ConnectionParameters, StreamId, StreamType}; use test_fixture::{ anti_replay, fixture_init, now, CountingConnectionIdGenerator, DEFAULT_ADDR, DEFAULT_ALPN_H3, DEFAULT_KEYS, DEFAULT_SERVER_NAME, @@ -59,7 +59,7 @@ fn connect() -> (Http3Client, Http3Server) { assert_eq!(client.state(), Http3State::Connected); - // Exchange H3 setttings + // Exchange H3 settings loop { out = server.process(out, now()).dgram(); let dgram_present = out.is_some(); @@ -96,12 +96,8 @@ fn create_wt_session(client: &mut Http3Client, server: &mut Http3Server) -> WebT headers, }) => { assert!( - headers - .iter() - .any(|h| h.name() == ":method" && h.value() == "CONNECT") - && headers - .iter() - .any(|h| h.name() == ":protocol" && h.value() == "webtransport") + headers.contains_header(":method", "CONNECT") + && headers.contains_header(":protocol", "webtransport") ); session .response(&WebTransportSessionAcceptAction::Accept) @@ -127,7 +123,7 @@ fn create_wt_session(client: &mut Http3Client, server: &mut Http3Server) -> WebT }) if ( stream_id == wt_session_id && status == 200 && - headers.contains(&Header::new(":status", "200")) + headers.contains_header(":status", "200") ) ) }; @@ -229,6 +225,17 @@ fn receive_data_server( wt_stream.unwrap() } +#[test] +fn wt_keepalive() { + let (mut client, mut server) = connect(); + let _wt_session = create_wt_session(&mut client, &mut server); + let idle_timeout = ConnectionParameters::default().get_idle_timeout(); + // Expect client and server to send PING after half of the idle timeout in order to keep + // connection alive. + assert_eq!(client.process_output(now()).callback(), idle_timeout / 2); + assert_eq!(server.process_output(now()).callback(), idle_timeout / 2); +} + #[test] fn wt_client_stream_uni() { const BUF_CLIENT: &[u8] = &[0; 10]; diff --git a/third_party/rust/neqo-qpack/.cargo-checksum.json b/third_party/rust/neqo-qpack/.cargo-checksum.json index 21e2ca716405..8b58b302f9d0 100644 --- a/third_party/rust/neqo-qpack/.cargo-checksum.json +++ b/third_party/rust/neqo-qpack/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f58a82c0437489fabe141b44181a181af4f0d0ff83855d4d844c7dece45fab4f","src/decoder.rs":"5c76a8407e02999a805ecaeae0ec2743121abe1e35b75126994d52ff7deb6af7","src/decoder_instructions.rs":"addf304fbd566ca387e5111cbe25784f7f50e0112ce0372b1ad6d18185b45a02","src/encoder.rs":"b6b9e3b87d2e56c07bf8e2ca3ad1688b313dd716f2239de89cf2b54242841a7a","src/encoder_instructions.rs":"746569e9f90f07af1aa49ed93f48c3fa3c41f13cea5f0ae88485a78a43a59470","src/header_block.rs":"47ad4a03d7a78e6d2269f8e004a884cb1e001c272a206121f479e29b8446f824","src/huffman.rs":"6976f1b4d3e5ef849a6b080cfb2e8804bf01cfe3b9bd9e3994a319d5405cd8f3","src/huffman_decode_helper.rs":"9ce470e318b3664f58aa109bed483ab15bfd9e0b17d261ea2b609668a42a9d80","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"f9bad0fe7643c618d034c4941ebd30ad5f6015b8b87b484b0ea79681d13d8b49","src/prefix.rs":"d9ad12838d61b38dc2300948e3da01fd65371215edde1c370cf54ccd87d64d46","src/qlog.rs":"d8e8482624f0cc4388546169772846d37a0422ce10287ee2f716dfc5f7a56c3d","src/qpack_send_buf.rs":"48f8d0e011e0fb8e4bd0774279d3465e2be01fd9480eaf374ae2adada6be430d","src/reader.rs":"937e9db6ca4dd8d6f599e58bc2123f3b76b269b089b4e98e3922efd80861dd92","src/static_table.rs":"6e5ec26e2b6bd63375d2d77e72748151d430d1629a8e497ec0d0ea21c078524a","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"2d2c9e6070a1e90048a4ad7c8279f9e1ce7615b44d7d8145fb0f140e554f5ca2"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"5c1632f128048c857a1aceed231a744069576011d582a55271744f8e5d41a68e","src/decoder.rs":"4d83a4f375cd6fdd01af5e9f3ad03deb7a6362c4ad1cf56d1c693e76946ae84d","src/decoder_instructions.rs":"0e6c2036372061b16f71b172e3b6f7796683c0992f5f6a39e6c4b37d9fff349a","src/encoder.rs":"77f4229ce9cb0b466ea0cd5108bb0128824f34962d87e94f76b757ce821a281f","src/encoder_instructions.rs":"033b7aeda62f8df2cf9b09a93d449cbae74376e9f49791683543874d46f64e08","src/header_block.rs":"4285d03556b6eba3a00715c9450b00af676a3ee5f3aa07a9f4e5e33944695ee3","src/huffman.rs":"6976f1b4d3e5ef849a6b080cfb2e8804bf01cfe3b9bd9e3994a319d5405cd8f3","src/huffman_decode_helper.rs":"9ce470e318b3664f58aa109bed483ab15bfd9e0b17d261ea2b609668a42a9d80","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"f9bad0fe7643c618d034c4941ebd30ad5f6015b8b87b484b0ea79681d13d8b49","src/prefix.rs":"1655af52fcc58c27984d78af6639d66a26c2307995e7ff22eb309fd7e4d50a81","src/qlog.rs":"d8e8482624f0cc4388546169772846d37a0422ce10287ee2f716dfc5f7a56c3d","src/qpack_send_buf.rs":"c0c2bc22ffd72b0dc2fb2f6d5590fc6a2fa4a19cc32b1407e9373140cbf44414","src/reader.rs":"ae15506441a52ad522f15048796c37ad791680e3ca020a50f7c84f54ab95435e","src/static_table.rs":"6e5ec26e2b6bd63375d2d77e72748151d430d1629a8e497ec0d0ea21c078524a","src/stats.rs":"cb01723249f60e15a5cd7efd9cbab409fddc588d1df655ed06ba8c80e3d5d28e","src/table.rs":"f7aac571794f192ef4bed1dc4c1ddd96dac5553b0341a5a99ff2fadcc46d8f7d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-qpack/Cargo.toml b/third_party/rust/neqo-qpack/Cargo.toml index 42d1c240f6fb..2f7bca5b0f88 100644 --- a/third_party/rust/neqo-qpack/Cargo.toml +++ b/third_party/rust/neqo-qpack/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "neqo-qpack" -version = "0.11.0" +version = "0.12.2" authors = ["The Neqo Authors "] build = false autolib = false @@ -68,8 +68,29 @@ default-features = false [dev-dependencies.test-fixture] path = "../test-fixture" +[features] +bench = [ + "neqo-common/bench", + "neqo-transport/bench", +] + [lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" [lints.clippy.cargo] level = "warn" @@ -82,3 +103,19 @@ priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/neqo-qpack/src/decoder.rs b/third_party/rust/neqo-qpack/src/decoder.rs index ed1d0b8a1853..beee78f62353 100644 --- a/third_party/rust/neqo-qpack/src/decoder.rs +++ b/third_party/rust/neqo-qpack/src/decoder.rs @@ -40,7 +40,7 @@ impl QPackDecoder { /// If settings include invalid values. #[must_use] pub fn new(qpack_settings: &QpackSettings) -> Self { - qdebug!("Decoder: creating a new qpack decoder."); + qdebug!("Decoder: creating a new qpack decoder"); let mut send_buf = QpackData::default(); send_buf.encode_varint(QPACK_UNI_STREAM_TYPE_DECODER); Self { @@ -93,7 +93,7 @@ impl QPackDecoder { let r = self .blocked_streams .iter() - .filter_map(|(id, req)| if *req <= base_new { Some(*id) } else { None }) + .filter_map(|(id, req)| (*req <= base_new).then_some(*id)) .collect::>(); self.blocked_streams.retain(|(_, req)| *req > base_new); Ok(r) @@ -139,14 +139,14 @@ impl QPackDecoder { self.stats.dynamic_table_inserts += 1; } DecodedEncoderInstruction::NoInstruction => { - unreachable!("This can be call only with an instruction."); + unreachable!("This can be call only with an instruction"); } } Ok(()) } fn set_capacity(&mut self, cap: u64) -> Res<()> { - qdebug!([self], "received instruction capacity cap={}", cap); + qdebug!("[{self}] received instruction capacity cap={cap}"); if cap > self.max_table_size { return Err(Error::EncoderStream); } @@ -182,11 +182,11 @@ impl QPackDecoder { DecoderInstruction::InsertCountIncrement { increment }.marshal(&mut self.send_buf); self.acked_inserts = self.table.base(); } - if self.send_buf.len() != 0 && self.local_stream_id.is_some() { + if !self.send_buf.is_empty() && self.local_stream_id.is_some() { let r = conn .stream_send(self.local_stream_id.unwrap(), &self.send_buf[..]) .map_err(|_| Error::DecoderStream)?; - qdebug!([self], "{} bytes sent.", r); + qdebug!("[{self}] {r} bytes sent"); self.send_buf.read(r); } Ok(()) @@ -214,7 +214,7 @@ impl QPackDecoder { buf: &[u8], stream_id: StreamId, ) -> Res>> { - qdebug!([self], "decode header block."); + qdebug!("[{self}] decode header block"); let mut decoder = HeaderDecoder::new(buf); match decoder.decode_header_block(&self.table, self.max_entries, self.table.base()) { @@ -225,7 +225,7 @@ impl QPackDecoder { let r = self .blocked_streams .iter() - .filter_map(|(id, req)| if *id == stream_id { Some(*req) } else { None }) + .filter_map(|(id, req)| (*id == stream_id).then_some(*req)) .collect::>(); if !r.is_empty() { debug_assert!(r.len() == 1); @@ -285,8 +285,6 @@ fn map_error(err: &Error) -> Error { #[cfg(test)] mod tests { - use std::mem; - use neqo_common::Header; use neqo_transport::{StreamId, StreamType}; use test_fixture::now; @@ -334,7 +332,7 @@ mod tests { .stream_send(decoder.recv_stream_id, encoder_instruction) .unwrap(); let out = decoder.peer_conn.process_output(now()); - mem::drop(decoder.conn.process(out.dgram(), now())); + drop(decoder.conn.process(out.dgram(), now())); assert_eq!( decoder .decoder @@ -346,7 +344,7 @@ mod tests { fn send_instructions_and_check(decoder: &mut TestDecoder, decoder_instruction: &[u8]) { decoder.decoder.send(&mut decoder.conn).unwrap(); let out = decoder.conn.process_output(now()); - mem::drop(decoder.peer_conn.process(out.dgram(), now())); + drop(decoder.peer_conn.process(out.dgram(), now())); let mut buf = [0_u8; 100]; let (amount, fin) = decoder .peer_conn diff --git a/third_party/rust/neqo-qpack/src/decoder_instructions.rs b/third_party/rust/neqo-qpack/src/decoder_instructions.rs index f69f9da3acea..db9cf5039dfc 100644 --- a/third_party/rust/neqo-qpack/src/decoder_instructions.rs +++ b/third_party/rust/neqo-qpack/src/decoder_instructions.rs @@ -89,7 +89,7 @@ impl DecoderInstructionReader { /// 2) `ClosedCriticalStream` /// 3) other errors will be translated to `DecoderStream` by the caller of this function. pub fn read_instructions(&mut self, recv: &mut R) -> Res { - qdebug!([self], "read a new instruction"); + qdebug!("[{self}] read a new instruction"); loop { match &mut self.state { DecoderInstructionReaderState::ReadInstruction => { @@ -108,7 +108,7 @@ impl DecoderInstructionReader { } DecoderInstructionReaderState::ReadInt { reader } => { let val = reader.read(recv)?; - qtrace!([self], "varint read {}", val); + qtrace!("[{self}] varint read {val}"); match &mut self.instruction { DecoderInstruction::InsertCountIncrement { increment: v } => { *v = val; @@ -128,7 +128,7 @@ impl DecoderInstructionReader { )); } DecoderInstruction::NoInstruction => { - unreachable!("This instruction cannot be in this state."); + unreachable!("This instruction cannot be in this state"); } } } diff --git a/third_party/rust/neqo-qpack/src/encoder.rs b/third_party/rust/neqo-qpack/src/encoder.rs index e82237eb3042..5b17ddb94629 100644 --- a/third_party/rust/neqo-qpack/src/encoder.rs +++ b/third_party/rust/neqo-qpack/src/encoder.rs @@ -93,9 +93,7 @@ impl QPackEncoder { } qdebug!( - [self], - "Set max capacity to new capacity:{} old:{} max_table_size={}.", - cap, + "[{self}] Set max capacity to new capacity:{cap} old:{} max_table_size={}", self.table.capacity(), self.max_table_size, ); @@ -129,7 +127,7 @@ impl QPackEncoder { } fn read_instructions(&mut self, conn: &mut Connection, stream_id: StreamId) -> Res<()> { - qdebug!([self], "read a new instruction"); + qdebug!("[{self}] read a new instruction"); loop { let mut recv = ReceiverConnWrapper::new(conn, stream_id); match self.instruction_reader.read_instructions(&mut recv) { @@ -172,7 +170,7 @@ impl QPackEncoder { } } } else { - debug_assert!(false, "We should have at least one header block."); + debug_assert!(false, "We should have at least one header block"); } if hb_list.is_empty() { self.unacked_header_blocks.remove(&stream_id); @@ -203,7 +201,7 @@ impl QPackEncoder { } fn call_instruction(&mut self, instruction: DecoderInstruction, qlog: &NeqoQlog) -> Res<()> { - qdebug!([self], "call intruction {:?}", instruction); + qdebug!("[{self}] call instruction {instruction:?}"); match instruction { DecoderInstruction::InsertCountIncrement { increment } => { qlog::qpack_read_insert_count_increment_instruction( @@ -247,7 +245,7 @@ impl QPackEncoder { name: &[u8], value: &[u8], ) -> Res { - qdebug!([self], "insert {:?} {:?}.", name, value); + qdebug!("[{self}] insert {name:?} {value:?}"); let entry_size = name.len() + value.len() + ADDITIONAL_TABLE_ENTRY_SIZE; @@ -280,7 +278,7 @@ impl QPackEncoder { } fn change_capacity(&mut self, value: u64) { - qdebug!([self], "change capacity: {}", value); + qdebug!("[{self}] change capacity: {value}"); self.next_capacity = Some(value); } @@ -290,7 +288,7 @@ impl QPackEncoder { stream_id: StreamId, ) -> Res<()> { if let Some(cap) = self.next_capacity { - // Check if it is possible to reduce the capacity, e.g. if enough space can be make free + // Check if it is possible to reduce the capacity, e.g. if enough space can be made free // for the reduction. if cap < self.table.capacity() && !self.table.can_evict_to(cap) { return Err(Error::DynamicTableFull); @@ -321,7 +319,7 @@ impl QPackEncoder { pub fn send_encoder_updates(&mut self, conn: &mut Connection) -> Res<()> { match self.local_stream { LocalStreamState::NoStream => { - qerror!("Send call but there is no stream yet."); + qerror!("Send call but there is no stream yet"); Ok(()) } LocalStreamState::Uninitialized(stream_id) => { @@ -368,7 +366,7 @@ impl QPackEncoder { h: &[Header], stream_id: StreamId, ) -> HeaderEncoder { - qdebug!([self], "encoding headers."); + qdebug!("[{self}] encoding headers"); // Try to send capacity instructions if present. // This code doesn't try to deal with errors, it just tries @@ -393,7 +391,7 @@ impl QPackEncoder { for iter in h { let name = iter.name().as_bytes().to_vec(); let value = iter.value().as_bytes().to_vec(); - qtrace!("encoding {:x?} {:x?}.", name, value); + qtrace!("encoding {name:x?} {value:x?}"); if let Some(LookupResult { index, @@ -402,10 +400,8 @@ impl QPackEncoder { }) = self.table.lookup(&name, &value, can_block) { qtrace!( - [self], - "found a {} entry, value-match={}", - if static_table { "static" } else { "dynamic" }, - value_matches + "[{self}] found a {} entry, value-match={value_matches}", + if static_table { "static" } else { "dynamic" } ); if value_matches { if static_table { @@ -528,8 +524,6 @@ fn map_stream_send_atomic_error(err: &TransportError) -> Error { #[cfg(test)] mod tests { - use std::mem; - use neqo_transport::{ConnectionParameters, StreamId, StreamType}; use test_fixture::{default_client, default_server, handshake, new_server, now, DEFAULT_ALPN}; @@ -576,7 +570,7 @@ mod tests { self.encoder.send_encoder_updates(&mut self.conn).unwrap(); let out = self.conn.process_output(now()); let out2 = self.peer_conn.process(out.dgram(), now()); - mem::drop(self.conn.process(out2.dgram(), now())); + drop(self.conn.process(out2.dgram(), now())); let mut buf = [0_u8; 100]; let (amount, fin) = self .peer_conn @@ -638,7 +632,7 @@ mod tests { .stream_send(encoder.recv_stream_id, decoder_instruction) .unwrap(); let out = encoder.peer_conn.process_output(now()); - mem::drop(encoder.conn.process(out.dgram(), now())); + drop(encoder.conn.process(out.dgram(), now())); assert!(encoder .encoder .read_instructions(&mut encoder.conn, encoder.recv_stream_id) @@ -891,7 +885,7 @@ mod tests { assert!(res.is_ok()); encoder.send_instructions(HEADER_CONTENT_LENGTH_VALUE_1_NAME_LITERAL); - // insert "content-length: 12345 which will fail because the ntry in the table cannot be + // insert "content-length: 12345 which will fail because the entry in the table cannot be // evicted. let res = encoder @@ -912,7 +906,7 @@ mod tests { encoder.send_instructions(HEADER_CONTENT_LENGTH_VALUE_2_NAME_LITERAL); } - // Test inserts block on waiting for acks + // Test inserts block on waiting for ACKs // test the table insertion is blocked: // 0 - waiting for a header ack // 2 - waiting for a stream cancel. @@ -1220,7 +1214,7 @@ mod tests { // receive a header_ack for the first header block. recv_instruction(&mut encoder, HEADER_ACK_STREAM_ID_1); - // The stream is not blocking anymore because header ack also acks the instruction. + // The stream is not blocking anymore because header ack also ACKs the instruction. assert_eq!(encoder.encoder.blocked_stream_cnt(), 0); } @@ -1260,7 +1254,7 @@ mod tests { // receive a header_ack for the second header block. This will ack the first as well recv_instruction(&mut encoder, HEADER_ACK_STREAM_ID_2); - // The stream is not blocking anymore because header ack also acks the instruction. + // The stream is not blocking anymore because header ack also ACKs the instruction. assert_eq!(encoder.encoder.blocked_stream_cnt(), 0); } @@ -1302,7 +1296,7 @@ mod tests { // acked. and the second steam will still be blocking. recv_instruction(&mut encoder, STREAM_CANCELED_ID_1); - // The stream is not blocking anymore because header ack also acks the instruction. + // The stream is not blocking anymore because header ack also ACKs the instruction. assert_eq!(encoder.encoder.blocked_stream_cnt(), 1); } @@ -1566,7 +1560,7 @@ mod tests { // exchange a flow control update. let out = encoder.peer_conn.process_output(now()); - mem::drop(encoder.conn.process(out.dgram(), now())); + drop(encoder.conn.process(out.dgram(), now())); // Try writing a new header block. Now, headers will be added to the dynamic table again, // because instructions can be sent. @@ -1613,7 +1607,7 @@ mod tests { .send_encoder_updates(&mut encoder.conn) .unwrap(); let out = encoder.conn.process_output(now()); - mem::drop(encoder.peer_conn.process(out.dgram(), now())); + drop(encoder.peer_conn.process(out.dgram(), now())); // receive an insert count increment. recv_instruction(&mut encoder, &[0x01]); @@ -1636,7 +1630,7 @@ mod tests { 0x36, 0x04, 0x31, 0x32, 0x33, 0x34 ] ); - // Also check that ther is no new instruction send by the encoder. + // Also check that there is no new instruction send by the encoder. assert!(encoder.conn.process_output(now()).dgram().is_none()); } diff --git a/third_party/rust/neqo-qpack/src/encoder_instructions.rs b/third_party/rust/neqo-qpack/src/encoder_instructions.rs index 1a513bd461cc..55e13cc9e465 100644 --- a/third_party/rust/neqo-qpack/src/encoder_instructions.rs +++ b/third_party/rust/neqo-qpack/src/encoder_instructions.rs @@ -18,17 +18,33 @@ use crate::{ Res, }; -// The encoder only uses InsertWithNameLiteral, therefore clippy is complaining about dead_code. -// We may decide to use othe instruction in the future. -// All instructions are used for testing, therefore they are defined. -#[allow(dead_code)] +// The encoder only uses InsertWithNameLiteral. +// All instructions are used for testing, therefore they are guarded with `#[cfg(test)]`. #[derive(Debug, PartialEq, Eq)] pub enum EncoderInstruction<'a> { - Capacity { value: u64 }, - InsertWithNameRefStatic { index: u64, value: &'a [u8] }, - InsertWithNameRefDynamic { index: u64, value: &'a [u8] }, - InsertWithNameLiteral { name: &'a [u8], value: &'a [u8] }, - Duplicate { index: u64 }, + Capacity { + value: u64, + }, + #[cfg(test)] + InsertWithNameRefStatic { + index: u64, + value: &'a [u8], + }, + #[cfg(test)] + InsertWithNameRefDynamic { + index: u64, + value: &'a [u8], + }, + InsertWithNameLiteral { + name: &'a [u8], + value: &'a [u8], + }, + #[cfg(test)] + Duplicate { + index: u64, + }, + #[cfg(test)] + #[allow(dead_code)] NoInstruction, } @@ -38,10 +54,12 @@ impl EncoderInstruction<'_> { Self::Capacity { value } => { enc.encode_prefixed_encoded_int(ENCODER_CAPACITY, *value); } + #[cfg(test)] Self::InsertWithNameRefStatic { index, value } => { enc.encode_prefixed_encoded_int(ENCODER_INSERT_WITH_NAME_REF_STATIC, *index); enc.encode_literal(use_huffman, NO_PREFIX, value); } + #[cfg(test)] Self::InsertWithNameRefDynamic { index, value } => { enc.encode_prefixed_encoded_int(ENCODER_INSERT_WITH_NAME_REF_DYNAMIC, *index); enc.encode_literal(use_huffman, NO_PREFIX, value); @@ -50,9 +68,11 @@ impl EncoderInstruction<'_> { enc.encode_literal(use_huffman, ENCODER_INSERT_WITH_NAME_LITERAL, name); enc.encode_literal(use_huffman, NO_PREFIX, value); } + #[cfg(test)] Self::Duplicate { index } => { enc.encode_prefixed_encoded_int(ENCODER_DUPLICATE, *index); } + #[cfg(test)] Self::NoInstruction => {} } } @@ -81,12 +101,14 @@ impl<'a> From<&'a EncoderInstruction<'a>> for DecodedEncoderInstruction { fn from(inst: &'a EncoderInstruction) -> Self { match inst { EncoderInstruction::Capacity { value } => Self::Capacity { value: *value }, + #[cfg(test)] EncoderInstruction::InsertWithNameRefStatic { index, value } => { Self::InsertWithNameRefStatic { index: *index, value: value.to_vec(), } } + #[cfg(test)] EncoderInstruction::InsertWithNameRefDynamic { index, value } => { Self::InsertWithNameRefDynamic { index: *index, @@ -99,7 +121,9 @@ impl<'a> From<&'a EncoderInstruction<'a>> for DecodedEncoderInstruction { value: value.to_vec(), } } + #[cfg(test)] EncoderInstruction::Duplicate { index } => Self::Duplicate { index: *index }, + #[cfg(test)] EncoderInstruction::NoInstruction => Self::NoInstruction, } } @@ -150,9 +174,9 @@ impl EncoderInstructionReader { } else if ENCODER_DUPLICATE.cmp_prefix(b) { DecodedEncoderInstruction::Duplicate { index: 0 } } else { - unreachable!("The above patterns match everything."); + unreachable!("The above patterns match everything"); }; - qdebug!([self], "instruction decoded"); + qdebug!("[{self}] instruction decoded"); } fn decode_instruction_type(&mut self, recv: &mut T) -> Res<()> { @@ -181,7 +205,7 @@ impl EncoderInstructionReader { } } DecodedEncoderInstruction::NoInstruction => { - unreachable!("We must have instruction at this point."); + unreachable!("We must have instruction at this point"); } } Ok(()) @@ -196,7 +220,7 @@ impl EncoderInstructionReader { &mut self, recv: &mut T, ) -> Res { - qdebug!([self], "reading instructions"); + qdebug!("[{self}] reading instructions"); loop { match &mut self.state { EncoderInstructionReaderState::ReadInstruction => { @@ -205,7 +229,7 @@ impl EncoderInstructionReader { EncoderInstructionReaderState::ReadFirstInt { reader } => { let val = reader.read(recv)?; - qtrace!([self], "First varint read {}", val); + qtrace!("[{self}] First varint read {val}"); match &mut self.instruction { DecodedEncoderInstruction::Capacity { value: v, .. } | DecodedEncoderInstruction::Duplicate { index: v } => { @@ -219,13 +243,13 @@ impl EncoderInstructionReader { reader: LiteralReader::default(), }; } - _ => unreachable!("This instruction cannot be in this state."), + _ => unreachable!("This instruction cannot be in this state"), } } EncoderInstructionReaderState::ReadFirstLiteral { reader } => { let val = reader.read(recv)?; - qtrace!([self], "first literal read {:?}", val); + qtrace!("[{self}] first literal read {val:?}"); match &mut self.instruction { DecodedEncoderInstruction::InsertWithNameRefStatic { value, .. } | DecodedEncoderInstruction::InsertWithNameRefDynamic { value, .. } => { @@ -238,19 +262,19 @@ impl EncoderInstructionReader { reader: LiteralReader::default(), }; } - _ => unreachable!("This instruction cannot be in this state."), + _ => unreachable!("This instruction cannot be in this state"), } } EncoderInstructionReaderState::ReadSecondLiteral { reader } => { let val = reader.read(recv)?; - qtrace!([self], "second literal read {:?}", val); + qtrace!("[{self}] second literal read {val:?}"); match &mut self.instruction { DecodedEncoderInstruction::InsertWithNameLiteral { value, .. } => { *value = val; self.state = EncoderInstructionReaderState::Done; } - _ => unreachable!("This instruction cannot be in this state."), + _ => unreachable!("This instruction cannot be in this state"), } } EncoderInstructionReaderState::Done => {} diff --git a/third_party/rust/neqo-qpack/src/header_block.rs b/third_party/rust/neqo-qpack/src/header_block.rs index 1c5072ee9606..5c95368fcd05 100644 --- a/third_party/rust/neqo-qpack/src/header_block.rs +++ b/third_party/rust/neqo-qpack/src/header_block.rs @@ -6,7 +6,7 @@ use std::{ mem, - ops::{Deref, Div}, + ops::{Deref, Div as _}, }; use neqo_common::{qtrace, Header}; @@ -60,7 +60,7 @@ impl HeaderEncoder { } pub fn encode_indexed_static(&mut self, index: u64) { - qtrace!([self], "encode static index {}.", index); + qtrace!("[{self}] encode static index {index}"); self.buf .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_STATIC, index); } @@ -76,7 +76,7 @@ impl HeaderEncoder { } pub fn encode_indexed_dynamic(&mut self, index: u64) { - qtrace!([self], "encode dynamic index {}.", index); + qtrace!("[{self}] encode dynamic index {index}"); if index < self.base { self.buf .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_DYNAMIC, self.base - index - 1); @@ -88,13 +88,7 @@ impl HeaderEncoder { } pub fn encode_literal_with_name_ref(&mut self, is_static: bool, index: u64, value: &[u8]) { - qtrace!( - [self], - "encode literal with name ref - index={}, static={}, value={:x?}", - index, - is_static, - value - ); + qtrace!("[{self}] encode literal with name ref - index={index}, static={is_static}, value={value:x?}"); if is_static { self.buf .encode_prefixed_encoded_int(HEADER_FIELD_LITERAL_NAME_REF_STATIC, index); @@ -116,12 +110,7 @@ impl HeaderEncoder { } pub fn encode_literal_with_name_literal(&mut self, name: &[u8], value: &[u8]) { - qtrace!( - [self], - "encode literal with name literal - name={:x?}, value={:x?}.", - name, - value - ); + qtrace!("[{self}] encode literal with name literal - name={name:x?}, value={value:x?}"); self.buf .encode_literal(self.use_huffman, HEADER_FIELD_LITERAL_NAME_LITERAL, name); self.buf.encode_literal(self.use_huffman, NO_PREFIX, value); @@ -148,13 +137,9 @@ impl HeaderEncoder { } }); qtrace!( - [self], - "encode header block prefix max_dynamic_index_ref={:?}, base={}, enc_insert_cnt={}, delta={}, prefix={:?}.", + "[{self}] encode header block prefix max_dynamic_index_ref={:?}, base={}, enc_insert_cnt={enc_insert_cnt}, delta={delta}, prefix={prefix:?}", self.max_dynamic_index_ref, - self.base, - enc_insert_cnt, - delta, - prefix + self.base ); self.buf @@ -224,8 +209,7 @@ impl<'a> HeaderDecoder<'a> { if table.base() < self.req_insert_cnt { qtrace!( - [self], - "decoding is blocked, requested inserts count={}", + "[{self}] decoding is blocked, requested inserts count={}", self.req_insert_cnt ); return Ok(HeaderDecoderResult::Blocked(self.req_insert_cnt)); @@ -274,7 +258,7 @@ impl<'a> HeaderDecoder<'a> { } } - qtrace!([self], "done decoding header block."); + qtrace!("[{self}] done decoding header block"); Ok(HeaderDecoderResult::Headers(h)) } @@ -300,8 +284,7 @@ impl<'a> HeaderDecoder<'a> { .ok_or(Error::DecompressionFailed)? }; qtrace!( - [self], - "requested inserts count is {} and base is {}", + "[{self}] requested inserts count is {} and base is {}", self.req_insert_cnt, self.base ); @@ -335,7 +318,7 @@ impl<'a> HeaderDecoder<'a> { let index = self .buf .read_prefixed_int(HEADER_FIELD_INDEX_STATIC.len())?; - qtrace!([self], "decoder static indexed {}.", index); + qtrace!("[{self}] decoder static indexed {index}"); let entry = HeaderTable::get_static(index)?; Ok(Header::new( parse_utf8(entry.name())?, @@ -347,7 +330,7 @@ impl<'a> HeaderDecoder<'a> { let index = self .buf .read_prefixed_int(HEADER_FIELD_INDEX_DYNAMIC.len())?; - qtrace!([self], "decoder dynamic indexed {}.", index); + qtrace!("[{self}] decoder dynamic indexed {index}"); let entry = table.get_dynamic(index, self.base, false)?; Ok(Header::new( parse_utf8(entry.name())?, @@ -359,7 +342,7 @@ impl<'a> HeaderDecoder<'a> { let index = self .buf .read_prefixed_int(HEADER_FIELD_INDEX_DYNAMIC_POST.len())?; - qtrace!([self], "decode post-based {}.", index); + qtrace!("[{self}] decode post-based {index}"); let entry = table.get_dynamic(index, self.base, true)?; Ok(Header::new( parse_utf8(entry.name())?, @@ -368,10 +351,7 @@ impl<'a> HeaderDecoder<'a> { } fn read_literal_with_name_ref_static(&mut self) -> Res
{ - qtrace!( - [self], - "read literal with name reference to the static table." - ); + qtrace!("[{self}] read literal with name reference to the static table"); let index = self .buf @@ -384,10 +364,7 @@ impl<'a> HeaderDecoder<'a> { } fn read_literal_with_name_ref_dynamic(&mut self, table: &HeaderTable) -> Res
{ - qtrace!( - [self], - "read literal with name reference ot the dynamic table." - ); + qtrace!("[{self}] read literal with name reference of the dynamic table"); let index = self .buf @@ -400,7 +377,7 @@ impl<'a> HeaderDecoder<'a> { } fn read_literal_with_name_ref_dynamic_post(&mut self, table: &HeaderTable) -> Res
{ - qtrace!([self], "decoder literal with post-based index."); + qtrace!("[{self}] decoder literal with post-based index"); let index = self .buf @@ -413,7 +390,7 @@ impl<'a> HeaderDecoder<'a> { } fn read_literal_with_name_literal(&mut self) -> Res
{ - qtrace!([self], "decode literal with name literal."); + qtrace!("[{self}] decode literal with name literal"); let name = self .buf diff --git a/third_party/rust/neqo-qpack/src/prefix.rs b/third_party/rust/neqo-qpack/src/prefix.rs index d83798a3dc28..2ed04668f22c 100644 --- a/third_party/rust/neqo-qpack/src/prefix.rs +++ b/third_party/rust/neqo-qpack/src/prefix.rs @@ -15,9 +15,9 @@ pub struct Prefix { impl Prefix { pub fn new(prefix: u8, len: u8) -> Self { // len should never be larger than 7. - // Most of Prefixes are instantiated as consts bellow. The only place where this - // construcrtor is used is in tests and when literals are encoded and the Huffman - // bit is added to one of the consts bellow. create_prefix guaranty that all const + // Most of Prefixes are instantiated as consts below. The only place where this + // constructor is used is in tests and when literals are encoded and the Huffman + // bit is added to one of the consts below. create_prefix guaranty that all const // have len < 7 so we can safely assert that len is <=7. assert!(len <= 7); assert!((len == 0) || (prefix & ((1 << (8 - len)) - 1) == 0)); diff --git a/third_party/rust/neqo-qpack/src/qpack_send_buf.rs b/third_party/rust/neqo-qpack/src/qpack_send_buf.rs index d5e3e0c2e06c..0856c1311670 100644 --- a/third_party/rust/neqo-qpack/src/qpack_send_buf.rs +++ b/third_party/rust/neqo-qpack/src/qpack_send_buf.rs @@ -90,7 +90,7 @@ impl QpackData { pub fn read(&mut self, r: usize) { assert!( r <= self.buf.len(), - "want to set more bytes read than remain in the buffer." + "want to set more bytes read than remain in the buffer" ); self.buf = self.buf.split_off(r); } diff --git a/third_party/rust/neqo-qpack/src/reader.rs b/third_party/rust/neqo-qpack/src/reader.rs index 1b28ab3f7c31..e9e8f64241ae 100644 --- a/third_party/rust/neqo-qpack/src/reader.rs +++ b/third_party/rust/neqo-qpack/src/reader.rs @@ -156,7 +156,7 @@ pub struct IntReader { } impl IntReader { - /// `IntReader` is created by suppling the first byte anf prefix length. + /// `IntReader` is created by supplying the first byte and prefix length. /// A varint may take only one byte, In that case already the first by has set state to done. /// /// # Panics @@ -164,7 +164,7 @@ impl IntReader { /// When `prefix_len` is 8 or larger. #[must_use] pub fn new(first_byte: u8, prefix_len: u8) -> Self { - debug_assert!(prefix_len < 8, "prefix cannot larger than 7."); + debug_assert!(prefix_len < 8, "prefix cannot larger than 7"); let mask = if prefix_len == 0 { 0xff } else { @@ -251,7 +251,7 @@ pub struct LiteralReader { impl LiteralReader { /// Creates `LiteralReader` with the first byte. This constructor is always used - /// when a litreral has a prefix. + /// when a literal has a prefix. /// For literals without a prefix please use the default constructor. /// /// # Panics @@ -315,7 +315,7 @@ impl LiteralReader { break Err(Error::NeedMoreData); } LiteralReaderState::Done => { - panic!("Should not call read() in this state."); + panic!("Should not call read() in this state"); } } } @@ -379,7 +379,7 @@ mod tests { use test_receiver::TestReceiver; use super::{ - parse_utf8, str, test_receiver, Error, IntReader, LiteralReader, ReadByte, + parse_utf8, str, test_receiver, Error, IntReader, LiteralReader, ReadByte as _, ReceiverBufferWrapper, Res, }; diff --git a/third_party/rust/neqo-qpack/src/stats.rs b/third_party/rust/neqo-qpack/src/stats.rs index 7cb334b0c77b..0dd2c9dd93b5 100644 --- a/third_party/rust/neqo-qpack/src/stats.rs +++ b/third_party/rust/neqo-qpack/src/stats.rs @@ -10,7 +10,7 @@ /// `QPack` statistics pub struct Stats { pub dynamic_table_inserts: usize, - // This is the munber of header blockes that reference the dynamic table. + // This is the number of header blocks that reference the dynamic table. pub dynamic_table_references: usize, pub stream_cancelled_recv: usize, pub header_acks_recv: usize, diff --git a/third_party/rust/neqo-qpack/src/table.rs b/third_party/rust/neqo-qpack/src/table.rs index ea6ae58d3533..2dc8a2e591e7 100644 --- a/third_party/rust/neqo-qpack/src/table.rs +++ b/third_party/rust/neqo-qpack/src/table.rs @@ -73,7 +73,7 @@ pub struct HeaderTable { /// The total number of inserts thus far. base: u64, /// This is number of inserts that are acked. this correspond to index of the first not acked. - /// This is only used by thee encoder. + /// This is only used by the encoder. acked_inserts_cnt: u64, } @@ -112,11 +112,11 @@ impl HeaderTable { /// /// # Errors /// - /// `ChangeCapacity` if table capacity cannot be reduced. - /// The table cannot be reduce if there are entries that are referred at the moment or their - /// inserts are unacked. + /// [`Error::ChangeCapacity`] if table capacity cannot be reduced. + /// The table cannot be reduced if there are entries that are referred to at + /// the moment, or whose inserts are unacked. pub fn set_capacity(&mut self, cap: u64) -> Res<()> { - qtrace!([self], "set capacity to {}", cap); + qtrace!("[{self}] set capacity to {cap}"); if !self.evict_to(cap) { return Err(Error::ChangeCapacity); } @@ -181,7 +181,7 @@ impl HeaderTable { /// Remove a reference to a dynamic table entry. pub fn remove_ref(&mut self, index: u64) { - qtrace!([self], "remove reference to entry {}", index); + qtrace!("[{self}] remove reference to entry {index}"); self.get_dynamic_with_abs_index(index) .expect("we should have the entry") .remove_ref(); @@ -189,7 +189,7 @@ impl HeaderTable { /// Add a reference to a dynamic table entry. pub fn add_ref(&mut self, index: u64) { - qtrace!([self], "add reference to entry {}", index); + qtrace!("[{self}] add reference to entry {index}"); self.get_dynamic_with_abs_index(index) .expect("we should have the entry") .add_ref(); @@ -199,13 +199,7 @@ impl HeaderTable { /// The function returns `LookupResult`: `index`, `static_table` (if it is a static table entry) /// and `value_matches` (if the header value matches as well not only header name) pub fn lookup(&mut self, name: &[u8], value: &[u8], can_block: bool) -> Option { - qtrace!( - [self], - "lookup name:{:?} value {:?} can_block={}", - name, - value, - can_block - ); + qtrace!("[{self}] lookup name:{name:?} value {value:?} can_block={can_block}",); let mut name_match = None; for iter in HEADER_STATIC_TABLE { if iter.name() == name { @@ -253,20 +247,9 @@ impl HeaderTable { } fn evict_to(&mut self, reduce: u64) -> bool { - self.evict_to_internal(reduce, false) - } - - pub fn can_evict_to(&mut self, reduce: u64) -> bool { - self.evict_to_internal(reduce, true) - } - - pub fn evict_to_internal(&mut self, reduce: u64, only_check: bool) -> bool { qtrace!( - [self], - "reduce table to {}, currently used:{} only_check:{}", - reduce, + "[{self}] reduce table to {reduce}, currently used:{}", self.used, - only_check ); let mut used = self.used; while (!self.dynamic.is_empty()) && used > reduce { @@ -275,16 +258,26 @@ impl HeaderTable { return false; } used -= u64::try_from(e.size()).unwrap(); - if !only_check { - self.used -= u64::try_from(e.size()).unwrap(); - self.dynamic.pop_back(); - } + self.used -= u64::try_from(e.size()).unwrap(); + self.dynamic.pop_back(); } } true } - pub fn insert_possible(&mut self, size: usize) -> bool { + pub fn can_evict_to(&self, reduce: u64) -> bool { + let evictable_size: usize = self + .dynamic + .iter() + .rev() + .take_while(|e| e.can_reduce(self.acked_inserts_cnt)) + .map(DynamicTableEntry::size) + .sum(); + + self.used - u64::try_from(evictable_size).unwrap() <= reduce + } + + pub fn insert_possible(&self, size: usize) -> bool { u64::try_from(size).unwrap() <= self.capacity && self.can_evict_to(self.capacity - u64::try_from(size).unwrap()) } @@ -296,7 +289,7 @@ impl HeaderTable { /// `DynamicTableFull` if an entry cannot be added to the table because there is not enough /// space and/or other entry cannot be evicted. pub fn insert(&mut self, name: &[u8], value: &[u8]) -> Res { - qtrace!([self], "insert name={:?} value={:?}", name, value); + qtrace!("[{self}] insert name={name:?} value={value:?}"); let entry = DynamicTableEntry { name: name.to_vec(), value: value.to_vec(), @@ -329,15 +322,12 @@ impl HeaderTable { value: &[u8], ) -> Res { qtrace!( - [self], - "insert with ref to index={} in {} value={:?}", - name_index, + "[{self}] insert with ref to index={name_index} in {} value={value:?}", if name_static_table { "static" } else { "dynamic" }, - value ); let name = if name_static_table { Self::get_static(name_index)?.name().to_vec() @@ -357,7 +347,7 @@ impl HeaderTable { /// space and/or other entry cannot be evicted. /// `HeaderLookup` if the index dos not exits in the static/dynamic table. pub fn duplicate(&mut self, index: u64) -> Res { - qtrace!([self], "duplicate entry={}", index); + qtrace!("[{self}] duplicate entry={index}"); // need to remember name and value because insert may delete the entry. let name: Vec; let value: Vec; @@ -365,7 +355,7 @@ impl HeaderTable { let entry = self.get_dynamic(index, self.base, false)?; name = entry.name().to_vec(); value = entry.value().to_vec(); - qtrace!([self], "dumplicate name={:?} value={:?}", name, value); + qtrace!("[{self}] duplicate name={name:?} value={value:?}"); } self.insert(&name, &value) } @@ -376,7 +366,7 @@ impl HeaderTable { /// /// `IncrementAck` if ack is greater than actual number of inserts. pub fn increment_acked(&mut self, increment: u64) -> Res<()> { - qtrace!([self], "increment acked by {}", increment); + qtrace!("[{self}] increment acked by {increment}"); self.acked_inserts_cnt += increment; if self.base < self.acked_inserts_cnt { return Err(Error::IncrementAck); @@ -389,3 +379,54 @@ impl HeaderTable { self.acked_inserts_cnt } } + +#[cfg(test)] +mod tests { + use super::*; + + /// Due to a bug in [`HeaderTable::can_evict_to`], the function would + /// continuously subtract the size of the last entry instead of the size of + /// each entry starting from the back. + /// + /// See for details. + mod issue_2306 { + use super::*; + + const VALUE: &[u8; 2] = b"42"; + + /// Given two entries where the first is smaller than the second, + /// subtracting the size of the second from the overall size twice leads + /// to an underflow. + #[test] + fn can_evict_to_no_underflow() { + let mut table = HeaderTable::new(true); + table.set_capacity(10000).unwrap(); + + table.insert(b"header1", VALUE).unwrap(); + table.insert(b"larger-header1", VALUE).unwrap(); + + table.increment_acked(2).unwrap(); + + assert!(table.can_evict_to(0)); + } + + /// Given two entries where only the first is acked, continuously + /// subtracting the size of the last entry would give a false-positive + /// on whether both entries can be evicted. + #[test] + fn can_evict_to_false() { + let mut table = HeaderTable::new(true); + table.set_capacity(10000).unwrap(); + + table.insert(b"header1", VALUE).unwrap(); + table.insert(b"header2", VALUE).unwrap(); + + table.increment_acked(1).unwrap(); + + let first_entry_size = table.get_dynamic_with_abs_index(0).unwrap().size() as u64; + + assert!(table.can_evict_to(first_entry_size)); + assert!(!table.can_evict_to(0)); + } + } +} diff --git a/third_party/rust/neqo-transport/.cargo-checksum.json b/third_party/rust/neqo-transport/.cargo-checksum.json index 841ef745ea69..563cc125fc19 100644 --- a/third_party/rust/neqo-transport/.cargo-checksum.json +++ b/third_party/rust/neqo-transport/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"dd4a18b947748e6767de007cf45e56663b4db2d7c77bacedd33832bc74b71f66","benches/range_tracker.rs":"4b0b04e33f6ddfd55a1377bd2995f9897025dc30986d6befc911cfcb071305df","benches/rx_stream_orderer.rs":"53a008357703251a18100521a12d8fa9443c5601ddc3cbd1b3c2899074da4c4f","benches/sent_packets.rs":"2a90b96314428f910e850374457f4f32dc8d7ab3d4a767d796926dddd66069f3","benches/transfer.rs":"3e09b0cd11f5eca8c572c4d76e0326e7315e6d4de737d1b62cec08f243ea9ced","build.rs":"78ec79c93bf13c3a40ceef8bba1ea2eada61c8f2dfc15ea7bf117958d367949c","src/ackrate.rs":"a863ed4fe1cb5b8c7ebe687b5fb840ab1de1fc6b23e6f274e6b1335f1ba27386","src/addr_valid.rs":"db90730ae9db2c2004f125ffc4339acd7123637e90a5c6a171a107a8bc7e12f5","src/cc/classic_cc.rs":"62184828c5329ca7c22bfb22cf121cdc550d7871d24fae6a0fec66282d36c308","src/cc/cubic.rs":"ffa8a6647a11ad6496d8a62de1affeccc0e2bae3f5b4e94b9385ca5cf4342c9c","src/cc/mod.rs":"bee8df1314e3bbcbb386d05ea528e8daaa629f944af99252bf40bea3a85ce33b","src/cc/new_reno.rs":"f438b5ab39413f8a9dad3575c6229bbae12140a316d8da34b5dcd9397551d5f7","src/cc/tests/cubic.rs":"d1880c126b95a95be6f3114bf6109c66e9f7336faa320fef832a4fb3049540be","src/cc/tests/mod.rs":"44f8df551e742ae1037cd1cdb85b2c1334c2e5ab3c23ed63d856dbc6b8743afc","src/cc/tests/new_reno.rs":"7a581fb76aeedce27f211fc4c1689409052bbab130bc6284b035614c9043a0cf","src/cid.rs":"dca61fd135cb4e072f3e238801021c7142aa37bd20c2e2bdbf79877584f44464","src/connection/dump.rs":"93184eb3b246ae42145fac4f3f925aa68800e4759470aeb35015ad7d3b6e041b","src/connection/idle.rs":"c399f7ca96e2b6e5f8d9917e90a86cb9efbf8d1e5a4d038159358066f0386698","src/connection/mod.rs":"5711364f54883f736f3028f22b848732989a03ce20b674d0f999cbba3f8e8550","src/connection/params.rs":"1f22666ab7a751f75173a3749195283e206e70d2c8c77b19590febe58d09eea1","src/connection/saved.rs":"90201b1df2af9f9e2fd4f7b41e094e88c1aa67ff2983c371d54cc933d104c20f","src/connection/state.rs":"b485b1c286a51f0f42c89a3897ecb8c01e774d4333b0ad95f8ac7fe02dfd9748","src/connection/test_internal.rs":"f3ebfe97b25c9c716d41406066295e5aff4e96a3051ef4e2b5fb258282bbc14c","src/connection/tests/ackrate.rs":"3d2a7f7809fdee01094c78a395b3930214842486cce4675d705b323189cc9e7c","src/connection/tests/cc.rs":"adaf985c82f52a78f1e76298eac7e70ff61a6c0543862a50a221529ad878d9ac","src/connection/tests/close.rs":"4e0d2a8028fb2e2e5ac41bd462d3dd359d657669246eb7193f4d77dd5d557ef0","src/connection/tests/datagram.rs":"ce58def0a795d64eba6b500cdb3bcb3463b217104de53e26a0522cf0a5036aba","src/connection/tests/ecn.rs":"a825c65a2e79a42efecae26332737147a36749865f4dab5d0ecd20125873013b","src/connection/tests/handshake.rs":"9814d1a6f5804ece17530aa1d138aa260f05e7e42c98acc7b647133aa17309e7","src/connection/tests/idle.rs":"aa3d6b594e131b3f86ec74c894b9a2a6e4df4219b5661edf0dea94ce9aadc15a","src/connection/tests/keys.rs":"59aff4f8abe186a264d39ec3eb5d699e629192695c0bdcd799e978e28ee4f81e","src/connection/tests/migration.rs":"9201b79e0262f458de791ad3fed7b4b73806d01796e030f073b714acf14bc8ab","src/connection/tests/mod.rs":"8e364fa6784819f488559209262b6a9040b0833e850f8cadbd78d6fefef3ed17","src/connection/tests/null.rs":"d39d34c895c40ea88bcc137cba43c34386ef9759c6f66f3487ffd41a5099feb8","src/connection/tests/priority.rs":"c103a16bafe6be4206a0154078eea93824d3629ed0b59b3de61e7ec01e0b68cd","src/connection/tests/recovery.rs":"972d9ab8e80ab2f23699db4f877109a0362926c43fc90e14b0246612c42e418a","src/connection/tests/resumption.rs":"571402b90813d7e8f6ed1cba982dbe4301749e65ff4eac6ad3e2535f4991818a","src/connection/tests/stream.rs":"95c27c564b0f4baebcb6e1b1cf1a5261b5de632066c5211a96fc42504e576098","src/connection/tests/vn.rs":"8bad801864ae507192e3bdfb4f79b6443b369b2390955ccde209818c18535d20","src/connection/tests/zerortt.rs":"46de18c01db4ad13ce5a20a512bf6aa2eb19f0890419fedaebd55c71d533836a","src/crypto.rs":"ddebbb6ccc8e51d0f47a14e4ff695f5ddbd21c461c325849db2661da07472b81","src/ecn.rs":"8f25ca6002e3efb0a38e001bdc893dc5b0854e0597576584d4bc9238208f1625","src/events.rs":"3cdd7d5496b2745626db4ceb863b5a91ae943090a43a5816a1f9bcf873fba2be","src/fc.rs":"bca35a3946f73e0564a01249307929b2a0b258abc94b42bfb1e239fcd90644e9","src/frame.rs":"370b4655a5b9bc584470e4cbbe843f144c289c2e6dfe213eac484be6e71f40bd","src/lib.rs":"28d84f642e242883ade269dffe2fc60fa91c9eb1dad91033a97b6406fc198445","src/pace.rs":"354bf09c0a88863af13fcfbb3381db4e780a983a3a967e97e1899e32d6e6250c","src/packet/mod.rs":"a709388970944ba4bb484f9665d6f54d9deb6fa84f934bbabcff9f3d541b4f91","src/packet/retry.rs":"4b515f6c04a5ce563494b592bdccf92bf31e9c361955279a66fb59908d0405fa","src/path.rs":"534d521f81cf1cb928624c204cb4330641c9af1dbe314dc4b974200c67772ee8","src/pmtud.rs":"00ca062d3121dcf3c3386af49bf58776bc874f3587536dec3de4c42607567824","src/qlog.rs":"360104b8039fee67b576002f9777f72cb962c20dfb6241a31712035f83d89f79","src/quic_datagrams.rs":"737af616e06f40ba0e68072c0e5c44a75630acb47fcb580f37af4887055a5115","src/recovery/mod.rs":"4bcde39d041c9da3f7cb8d90341b9e0d2cba993252f4e07d87a16dda69d0ab6f","src/recovery/sent.rs":"a17dce473294b2cc0f288752ee631789725fe2c4722dc71b7ec91a6884a632b0","src/recovery/token.rs":"c1e4190c6733afd2bf5e60060d8ba3ab9fb136e02252e2480b281871a54d6066","src/recv_stream.rs":"8a526fb925d78e7712ddc79f71b667eae480bdf04f3da12d0a98b6a5dce19686","src/rtt.rs":"2bf80ca48c7928d8355fd9585194ab90ba6891504b00dbee0c5c93da426105bb","src/send_stream.rs":"a4d0c34d49a70f3dcf0ab6e8132a688cf5b94770cff73d5f9872420d1d91f594","src/sender.rs":"3049b6832c28a20f0b0f3502fd3883fec0177c66033f94f11f55bb763d45d33c","src/server.rs":"cffe0d801b4558189f26ed5e256c7195b1e19669f04851b8189d5917698ce8bb","src/stats.rs":"f7a686afd626121dc97d7a4ef9a86b40af645448465fa86e325847db2e4b0a86","src/stream_id.rs":"f11a2a92a9620da288ae049fb14fe978a46554c90ed6fda66163f0565e5b3623","src/streams.rs":"77fdca9b0836525bd50ded43ecb69cfbcd1b7a90e106542ae3730c60e71e306f","src/tparams.rs":"3eae078d88eec7ee68f3c1bc0396dbea8d103838f3cd5406569036ec2390dbb3","src/tracking.rs":"b7daf14ccb7a99874452964fed49c728f451bfdb0fc8cb7ba32ee3022c121d97","src/version.rs":"9147a7b83fac986f921b09f84222bbd6eec2c12daeed9270ba30d843a3c3dcc1","tests/common/mod.rs":"d26b56f91f3b18e045e939620e9cf3a593caba8e4e358c63293fc277fda6164f","tests/conn_vectors.rs":"0e4a1b92c02b527842c127b789e70f6c4372c2b61b1a59a8e695f744ce155e2a","tests/connection.rs":"d90635c1cec51296889da510f93de27c3a5da188ddd5c48f240b8f52e88efc9b","tests/network.rs":"04921aa5af583e842e6d2176a898fbfea747e831bbe292b5ef8441eaf546b93a","tests/retry.rs":"69f6e38658ba52e1d94b841a65423f09ef3e162f5049c46a2cb7408a2e36bf88","tests/server.rs":"7fd3ec8108cd3a80becb874da16d7cd299536c9f6d6baa37e7d5b13ef5a85547"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"0e34d9c810504d2114dd1237c35f5f745e381c8e58f29a48a8e1bc7949efc297","benches/range_tracker.rs":"4b0b04e33f6ddfd55a1377bd2995f9897025dc30986d6befc911cfcb071305df","benches/rx_stream_orderer.rs":"53a008357703251a18100521a12d8fa9443c5601ddc3cbd1b3c2899074da4c4f","benches/sent_packets.rs":"2a90b96314428f910e850374457f4f32dc8d7ab3d4a767d796926dddd66069f3","benches/transfer.rs":"3e09b0cd11f5eca8c572c4d76e0326e7315e6d4de737d1b62cec08f243ea9ced","build.rs":"78ec79c93bf13c3a40ceef8bba1ea2eada61c8f2dfc15ea7bf117958d367949c","src/ackrate.rs":"aa43b2c136f39f6cb4c81367c1dece7e9d2059ab4a56609b5e51e4b06aef0553","src/addr_valid.rs":"2f28437c8a4eb7816ddf138221bb35a4767308e28575bdb324c24e6ee6a3678d","src/cc/classic_cc.rs":"530b2b6865bc349ecf4bfbad7608dc938fe66ba750b0b8279924a6f45b64ac0a","src/cc/cubic.rs":"8ff40c549937522be4a5d038f08ed2c9d235266b1f1eea5c0a9d1fb4d107f18a","src/cc/mod.rs":"bee8df1314e3bbcbb386d05ea528e8daaa629f944af99252bf40bea3a85ce33b","src/cc/new_reno.rs":"f438b5ab39413f8a9dad3575c6229bbae12140a316d8da34b5dcd9397551d5f7","src/cc/tests/cubic.rs":"b65da2dfab0ec10d18bf53aba0a8c9e29806a5c1c031dd38eba910ad1fa0b739","src/cc/tests/mod.rs":"017bf402a9a8c71b5c43343677635644babb57a849d81d0affc328b4b4b9cebb","src/cc/tests/new_reno.rs":"1b79773d1438d4449cb4d3af28b335d0422ba1d0932a3a2f8c5f10b8d6bb6994","src/cid.rs":"0d1e7142b9eb2c19968eaec7b8988ec31d00589882d6ed6890bbc72ee14a353b","src/connection/dump.rs":"1874f1ffef3df434bb5a2ae2098fa59c3294c844fdd44d617bcd07f0c8ca817e","src/connection/idle.rs":"74c3a871bb8515f980193d4f0152354712df26c140012af0cd810fd55f90a80a","src/connection/mod.rs":"9e89d6292486c20748d92bad9e994a662497686060c38fddf167c4b978ff49a7","src/connection/params.rs":"f66068328c8a8013a1bea1a40616694a9ea1849a5faba72238244645028bacc1","src/connection/saved.rs":"90201b1df2af9f9e2fd4f7b41e094e88c1aa67ff2983c371d54cc933d104c20f","src/connection/state.rs":"8893e06f00429ed4ced92b51d57a0828c895b472a5174b4b5d2d695bea1cd1e1","src/connection/test_internal.rs":"f3ebfe97b25c9c716d41406066295e5aff4e96a3051ef4e2b5fb258282bbc14c","src/connection/tests/ackrate.rs":"3a242d85de100dc7500074969fab12a64e62f6a48994a5486d28e15c27c4faa1","src/connection/tests/cc.rs":"e32a5e435435584147a832ef8af610b42e79650d2e3b23dcfea96a2056ca4311","src/connection/tests/close.rs":"4e0d2a8028fb2e2e5ac41bd462d3dd359d657669246eb7193f4d77dd5d557ef0","src/connection/tests/datagram.rs":"aa3ab7aabc211742e1976871808e3162c3f90a2547d6720196756a91409a0c53","src/connection/tests/ecn.rs":"37566087cc3cc7e79eca73eb157278e21655dbb3e3d6799fbc532be920780e4d","src/connection/tests/handshake.rs":"947caac4c5b92ea437a55120bc82ff450ab93a8357e50357bcf53df741e99ae1","src/connection/tests/idle.rs":"782b64529c6a3cf915a52f4eb537c514c1dca5a53ff6ca9a7da88a15cfd790ab","src/connection/tests/keys.rs":"00f7c90882497db7018f65d8f08dc1a37c9d81e22e7dd7a0c6372787c12428db","src/connection/tests/migration.rs":"6a85a8c460ce8cd957ca9e743774f413681e55ca67962749ea23af23d5e96c0a","src/connection/tests/mod.rs":"e93da3d5989141c4ae1971a2acd3693f5c96b3eb4f9cb9ac2e06242452c86361","src/connection/tests/null.rs":"d39d34c895c40ea88bcc137cba43c34386ef9759c6f66f3487ffd41a5099feb8","src/connection/tests/priority.rs":"3cdb9b5f1cb375a058012844f579e6032e5ebe4c120b12c807a2f97dfe7c0225","src/connection/tests/recovery.rs":"cb1365d49301b2f09fa78940daf845c97caec6f74b053c9e0d49f3c5e9f4368c","src/connection/tests/resumption.rs":"92b54d2a0dc2b1d44d563da4850c1275b9915c1935c685cfdcf08659b4ac0537","src/connection/tests/stream.rs":"0a565e5579c1eb71a105db0f777af52b194d1db25e8dbf349b764c7ce22a145d","src/connection/tests/vn.rs":"1cb267f14c6762a56dcb0baf72c444711db30131526873840e66d821f4357099","src/connection/tests/zerortt.rs":"ea8fdb43512fd203351fd2f9264e2cd14a317397a15464613d1f99decfd88fdf","src/crypto.rs":"5e13111f0498bc92474238bae587ae8e7c712139e04eb3fdb4555e9255d8c470","src/ecn.rs":"38aaf104621efbb4c4b295a5deebb844a40ce47834aebf18b846cbb61ee6a02f","src/events.rs":"fc14337104318a3a76dae8fb2e988fb8d1435e1052a1fb4f2a5cf9163e6feb41","src/fc.rs":"2c5765c01d5d9e4dfd217c1d4978ca00a1628d6ab8177a74dc0cb110b68c65ea","src/frame.rs":"56de068ca6817791f4518e2f3e465f2f75af3257e4b48d38c89c0ebf2cea862c","src/lib.rs":"284b15acbf61ef7588a1b65a117987896f68adc5a5c65a22698477ea7c6b7bd2","src/pace.rs":"78e101f5bf623e9c312081276034c186009cbfec606294f8a65ab58e468d4bb9","src/packet/mod.rs":"75d724837d66b3b242cefc2884cd219b7e05be3f093681b4058c40fb35d625c3","src/packet/retry.rs":"b7b10dda0290e728cfd60151d2dbc90cbb25e830c3a467441954b99f3f029173","src/path.rs":"8fb09beb96f6ddbd97dd0d28b72e2d674c9a239c7202743739bd9cb9027c4b5c","src/pmtud.rs":"332c62ffbe1a0fcb2219032098f95b7ecfd39a69ea983d41b802f74b334555c8","src/qlog.rs":"9a025ee6846d1fcce7fd2233c9889986b7af29e03f56ab2a285c9fac6cb774a3","src/quic_datagrams.rs":"8a436e17c4b8cd1184b856a0a83a3ae43a8dcb660eee837485fa076322a49a5b","src/recovery/mod.rs":"a521d6b76bfe74123576db808791fab402850d20b631a84a04239afbbabd1215","src/recovery/sent.rs":"bc355263b8376998cd0167766f2a7b5e2bbf8f30066cb7270b9966992d1355a3","src/recovery/token.rs":"c1e4190c6733afd2bf5e60060d8ba3ab9fb136e02252e2480b281871a54d6066","src/recv_stream.rs":"94ad2c53e4dc9671803fce20281787d118551d164006ccb3f4f597c9ed942998","src/rtt.rs":"e7bc1ab22e662382f9df1501bd99564a0af4e30da524b809245a27deb6e3527f","src/send_stream.rs":"3ba05204585032e954393cce164bccfc9e2e2cd5ed1c7d8f2fc16537f84786b5","src/sender.rs":"2bfdcab2dc0fdc801b9385f9e2bd0e8de924e41d3a033f887920105ac63ccb18","src/server.rs":"c11f9e754a9498a94fcf3a489663ce13e241011d95ee93352c3b2c360ee9af76","src/shuffle.rs":"262feb2ef3d6c255e90f76fc4f5504e7335d3a8656f6fce8e0a92902c36f88a2","src/stats.rs":"042c459cf5a0dc1b30c3101cfe11e1902526c29e83d2d58c7e0280ec3a9ab81f","src/stream_id.rs":"d60001fc316bfba29c3aaf1fccbba8099fb776c7e0a2492645ada5bba468a5b5","src/streams.rs":"2c932b3d7f5f9fad78257426eea544f7818406a7ae3b1064810a3e5f4c9f9974","src/tparams.rs":"f694009ce56742d1e625fcd61c617695c6df10997f8b71ed41e6c44ed6963565","src/tracking.rs":"5c11ae6bc549f2d8c2696741898dc0f42f4f43002c2e1d970d3f3313b6ed67cd","src/version.rs":"a895fa9a6ad38c482f926cee6026ad8ba41c8834d2f2aefa1645e0e3eb71646a","tests/common/mod.rs":"5d86b0457cb8390c9c44cf269efc8c9cee3643ed819f97c5509349a660cb8d51","tests/conn_vectors.rs":"0e4a1b92c02b527842c127b789e70f6c4372c2b61b1a59a8e695f744ce155e2a","tests/connection.rs":"e6b69a00c668a73933f9b6fcec7ac354123d0b1b46103056bf3db48db681dc63","tests/network.rs":"04921aa5af583e842e6d2176a898fbfea747e831bbe292b5ef8441eaf546b93a","tests/retry.rs":"0eb85fc05f53765440a8351ecc55304cd05689d05a08ac7f99b6df8bf36f9a52","tests/server.rs":"5b26812a498d19d3c6431541f9783a57310467420afa1b35793eccbb77b87c5d","tests/stats.rs":"1889f2b81cf3f61d4aa6b1ac70bc2f930590186d9d8b61d9dc3e8a0c2385f76d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-transport/Cargo.toml b/third_party/rust/neqo-transport/Cargo.toml index 9f4a037802de..d3ff3c4870d3 100644 --- a/third_party/rust/neqo-transport/Cargo.toml +++ b/third_party/rust/neqo-transport/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.76.0" name = "neqo-transport" -version = "0.11.0" +version = "0.12.2" authors = ["The Neqo Authors "] build = "build.rs" autolib = false @@ -64,6 +64,10 @@ path = "tests/retry.rs" name = "server" path = "tests/server.rs" +[[test]] +name = "stats" +path = "tests/stats.rs" + [[bench]] name = "range_tracker" path = "benches/range_tracker.rs" @@ -100,6 +104,10 @@ default-features = false version = "0.4" default-features = false +[dependencies.mtu] +version = "0.2.3" +default-features = false + [dependencies.neqo-common] path = "../neqo-common" @@ -122,11 +130,18 @@ default-features = false version = "0.5" default-features = false +[dev-dependencies.neqo-transport] +path = "." +features = ["draft-29"] + [dev-dependencies.test-fixture] path = "../test-fixture" [features] -bench = ["test-fixture/bench"] +bench = [ + "neqo-common/bench", + "neqo-crypto/bench", +] build-fuzzing-corpus = [ "neqo-common/build-fuzzing-corpus", "neqo-crypto/disable-encryption", @@ -134,9 +149,26 @@ build-fuzzing-corpus = [ "test-fixture/disable-random", ] disable-encryption = ["neqo-crypto/disable-encryption"] +draft-29 = [] +gecko = ["mtu/gecko"] [lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" [lints.clippy.cargo] level = "warn" @@ -149,3 +181,19 @@ priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/neqo-transport/src/ackrate.rs b/third_party/rust/neqo-transport/src/ackrate.rs index bad69d0a9b28..000cef1107c3 100644 --- a/third_party/rust/neqo-transport/src/ackrate.rs +++ b/third_party/rust/neqo-transport/src/ackrate.rs @@ -37,7 +37,7 @@ impl AckRate { let packets = packets.clamp(MIN_PACKETS, MAX_PACKETS) - 1; let delay = rtt * RTT_RATIO / u32::from(ratio); let delay = delay.clamp(minimum, MAX_DELAY); - qtrace!("AckRate inputs: {}/{}/{}, {:?}", cwnd, mtu, ratio, rtt); + qtrace!("AckRate inputs: {cwnd}/{mtu}/{ratio}, {rtt:?}"); Self { packets, delay } } @@ -82,12 +82,7 @@ impl FlexibleAckRate { mtu: usize, rtt: Duration, ) -> Self { - qtrace!( - "FlexibleAckRate: {:?} {:?} {}", - max_ack_delay, - min_ack_delay, - ratio - ); + qtrace!("FlexibleAckRate: {max_ack_delay:?} {min_ack_delay:?} {ratio}"); let ratio = max(ACK_RATIO_SCALE, ratio); // clamp it Self { current: AckRate { diff --git a/third_party/rust/neqo-transport/src/addr_valid.rs b/third_party/rust/neqo-transport/src/addr_valid.rs index 2570134dc30d..8ad2f8d0fba8 100644 --- a/third_party/rust/neqo-transport/src/addr_valid.rs +++ b/third_party/rust/neqo-transport/src/addr_valid.rs @@ -148,7 +148,7 @@ impl AddressValidation { } pub fn set_validation(&mut self, validation: ValidateAddress) { - qtrace!("AddressValidation {:p}: set to {:?}", self, validation); + qtrace!("AddressValidation {self:p}: set to {validation:?}"); self.validation = validation; } @@ -166,11 +166,11 @@ impl AddressValidation { let peer_addr = Self::encode_aad(peer_address, retry); let data = self.self_encrypt.open(peer_addr.as_ref(), token).ok()?; let mut dec = Decoder::new(&data); - match dec.decode_uint(4) { + match dec.decode_uint::() { Some(d) => { - let end = self.start_time + Duration::from_millis(d); + let end = self.start_time + Duration::from_millis(u64::from(d)); if end < now { - qtrace!("Expired token: {:?} vs. {:?}", end, now); + qtrace!("Expired token: {end:?} vs. {now:?}"); return None; } } @@ -199,11 +199,7 @@ impl AddressValidation { peer_address: SocketAddr, now: Instant, ) -> AddressValidationResult { - qtrace!( - "AddressValidation {:p}: validate {:?}", - self, - self.validation - ); + qtrace!("AddressValidation {self:p}: validate {:?}", self.validation); if token.is_empty() { if self.validation == ValidateAddress::Never { @@ -227,7 +223,7 @@ impl AddressValidation { if retry { // This is from Retry, so we should have an ODCID >= 8. if cid.len() >= 8 { - qinfo!("AddressValidation: valid Retry token for {}", cid); + qinfo!("AddressValidation: valid Retry token for {cid}"); AddressValidationResult::ValidRetry(cid) } else { panic!("AddressValidation: Retry token with small CID {cid}"); @@ -292,7 +288,7 @@ impl NewTokenState { /// Is there a token available? pub fn has_token(&self) -> bool { match self { - Self::Client { ref pending, .. } => !pending.is_empty(), + Self::Client { pending, .. } => !pending.is_empty(), Self::Server(..) => false, } } @@ -322,7 +318,7 @@ impl NewTokenState { pub fn save_token(&mut self, token: Vec) { if let Self::Client { ref mut pending, - ref old, + old, } = self { for t in old.iter().rev().chain(pending.iter().rev()) { diff --git a/third_party/rust/neqo-transport/src/cc/classic_cc.rs b/third_party/rust/neqo-transport/src/cc/classic_cc.rs index 0c629afb59f4..f1051e45caeb 100644 --- a/third_party/rust/neqo-transport/src/cc/classic_cc.rs +++ b/third_party/rust/neqo-transport/src/cc/classic_cc.rs @@ -12,6 +12,9 @@ use std::{ time::{Duration, Instant}, }; +use ::qlog::events::{quic::CongestionStateUpdated, EventData}; +use neqo_common::{const_max, const_min, qdebug, qinfo, qlog::NeqoQlog, qtrace}; + use super::CongestionControl; use crate::{ packet::PacketNumber, @@ -21,9 +24,6 @@ use crate::{ sender::PACING_BURST_SIZE, Pmtud, }; -#[rustfmt::skip] // to keep `::` and thus prevent conflict with `crate::qlog` -use ::qlog::events::{quic::CongestionStateUpdated, EventData}; -use neqo_common::{const_max, const_min, qdebug, qinfo, qlog::NeqoQlog, qtrace}; pub const CWND_INITIAL_PKTS: usize = 10; const PERSISTENT_CONG_THRESH: u32 = 3; @@ -88,7 +88,7 @@ pub trait WindowAdjustment: Display + Debug { max_datagram_size: usize, now: Instant, ) -> usize; - /// This function is called when a congestion event has beed detected and it + /// This function is called when a congestion event has been detected and it /// returns new (decreased) values of `curr_cwnd` and `acked_bytes`. /// This value can be very small; the calling code is responsible for ensuring that the /// congestion window doesn't drop below the minimum of `CWND_MIN`. @@ -185,19 +185,16 @@ impl CongestionControl for ClassicCongestionControl { &mut self.pmtud } - // Multi-packet version of OnPacketAckedCC fn on_packets_acked(&mut self, acked_pkts: &[SentPacket], rtt_est: &RttEstimate, now: Instant) { let mut is_app_limited = true; let mut new_acked = 0; for pkt in acked_pkts { qtrace!( - "packet_acked this={:p}, pn={}, ps={}, ignored={}, lost={}, rtt_est={:?}", - self, + "packet_acked this={self:p}, pn={}, ps={}, ignored={}, lost={}, rtt_est={rtt_est:?}", pkt.pn(), pkt.len(), i32::from(!pkt.cc_outstanding()), i32::from(pkt.lost()), - rtt_est, ); if !pkt.cc_outstanding() { continue; @@ -225,7 +222,7 @@ impl CongestionControl for ClassicCongestionControl { if is_app_limited { self.cc_algorithm.on_app_limited(); - qdebug!("on_packets_acked this={:p}, limited=1, bytes_in_flight={}, cwnd={}, state={:?}, new_acked={}", self, self.bytes_in_flight, self.congestion_window, self.state, new_acked); + qdebug!("on_packets_acked this={self:p}, limited=1, bytes_in_flight={}, cwnd={}, state={:?}, new_acked={new_acked}", self.bytes_in_flight, self.congestion_window, self.state); return; } @@ -235,7 +232,7 @@ impl CongestionControl for ClassicCongestionControl { let increase = min(self.ssthresh - self.congestion_window, self.acked_bytes); self.congestion_window += increase; self.acked_bytes -= increase; - qdebug!([self], "slow start += {}", increase); + qdebug!("[{self}] slow start += {increase}"); if self.congestion_window == self.ssthresh { // This doesn't look like it is necessary, but it can happen // after persistent congestion. @@ -278,7 +275,7 @@ impl CongestionControl for ClassicCongestionControl { ], now, ); - qdebug!([self], "on_packets_acked this={:p}, limited=0, bytes_in_flight={}, cwnd={}, state={:?}, new_acked={}", self, self.bytes_in_flight, self.congestion_window, self.state, new_acked); + qdebug!("[{self}] on_packets_acked this={self:p}, limited=0, bytes_in_flight={}, cwnd={}, state={:?}, new_acked={new_acked}", self.bytes_in_flight, self.congestion_window, self.state); } /// Update congestion controller state based on lost packets. @@ -296,8 +293,7 @@ impl CongestionControl for ClassicCongestionControl { for pkt in lost_packets.iter().filter(|pkt| pkt.cc_in_flight()) { qdebug!( - "packet_lost this={:p}, pn={}, ps={}", - self, + "packet_lost this={self:p}, pn={}, ps={}", pkt.pn(), pkt.len() ); @@ -332,8 +328,7 @@ impl CongestionControl for ClassicCongestionControl { now, ); qdebug!( - "on_packets_lost this={:p}, bytes_in_flight={}, cwnd={}, state={:?}", - self, + "on_packets_lost this={self:p}, bytes_in_flight={}, cwnd={}, state={:?}", self.bytes_in_flight, self.congestion_window, self.state @@ -358,7 +353,7 @@ impl CongestionControl for ClassicCongestionControl { &[QlogMetric::BytesInFlight(self.bytes_in_flight)], now, ); - qtrace!([self], "Ignore pkt with size {}", pkt.len()); + qtrace!("[{self}] Ignore pkt with size {}", pkt.len()); } } @@ -391,8 +386,7 @@ impl CongestionControl for ClassicCongestionControl { self.bytes_in_flight += pkt.len(); qdebug!( - "packet_sent this={:p}, pn={}, ps={}", - self, + "packet_sent this={self:p}, pn={}, ps={}", pkt.pn(), pkt.len() ); @@ -457,7 +451,7 @@ impl ClassicCongestionControl { fn set_state(&mut self, state: State, now: Instant) { if self.state != state { - qdebug!([self], "state -> {:?}", state); + qdebug!("[{self}] state -> {state:?}"); let old_state = self.state; self.qlog.add_event_data_with_instant( || { @@ -520,7 +514,7 @@ impl ClassicCongestionControl { .checked_duration_since(t) .expect("time is monotonic"); if elapsed > pc_period { - qinfo!([self], "persistent congestion"); + qinfo!("[{self}] persistent congestion"); self.congestion_window = self.cwnd_min(); self.acked_bytes = 0; self.set_state(State::PersistentCongestion, now); @@ -567,8 +561,7 @@ impl ClassicCongestionControl { self.acked_bytes = acked_bytes; self.ssthresh = self.congestion_window; qdebug!( - [self], - "Cong event -> recovery; cwnd {}, ssthresh {}", + "[{self}] Cong event -> recovery; cwnd {}, ssthresh {}", self.congestion_window, self.ssthresh ); @@ -604,10 +597,7 @@ impl ClassicCongestionControl { #[cfg(test)] mod tests { - use std::{ - net::{IpAddr, Ipv4Addr}, - time::{Duration, Instant}, - }; + use std::time::{Duration, Instant}; use neqo_common::{qinfo, IpTosEcn}; use test_fixture::now; @@ -618,6 +608,7 @@ mod tests { classic_cc::State, cubic::{Cubic, CUBIC_BETA_USIZE_DIVIDEND, CUBIC_BETA_USIZE_DIVISOR}, new_reno::NewReno, + tests::{IP_ADDR, MTU, RTT}, CongestionControl, CongestionControlAlgorithm, CWND_INITIAL_PKTS, }, packet::{PacketNumber, PacketType}, @@ -626,10 +617,8 @@ mod tests { Pmtud, }; - const IP_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); - const PTO: Duration = Duration::from_millis(100); - const RTT: Duration = Duration::from_millis(98); - const RTT_ESTIMATE: RttEstimate = RttEstimate::from_duration(Duration::from_millis(98)); + const PTO: Duration = RTT; + const RTT_ESTIMATE: RttEstimate = RttEstimate::from_duration(RTT); const ZERO: Duration = Duration::from_secs(0); const EPSILON: Duration = Duration::from_nanos(1); const GAP: Duration = Duration::from_secs(1); @@ -665,11 +654,11 @@ mod tests { match cc { CongestionControlAlgorithm::NewReno => Box::new(ClassicCongestionControl::new( NewReno::default(), - Pmtud::new(IP_ADDR), + Pmtud::new(IP_ADDR, MTU), )), CongestionControlAlgorithm::Cubic => Box::new(ClassicCongestionControl::new( Cubic::default(), - Pmtud::new(IP_ADDR), + Pmtud::new(IP_ADDR, MTU), )), } } @@ -908,13 +897,13 @@ mod tests { fn persistent_congestion_no_lost() { let lost = make_lost(&[]); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost @@ -926,13 +915,13 @@ mod tests { fn persistent_congestion_one_lost() { let lost = make_lost(&[1]); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost @@ -946,37 +935,37 @@ mod tests { // sample are not considered. So 0 is ignored. let lost = make_lost(&[0, PERSISTENT_CONG_THRESH + 1, PERSISTENT_CONG_THRESH + 2]); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 1, 1, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 0, 1, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 1, 0, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 1, 1, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 0, 1, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 1, 0, &lost @@ -997,13 +986,13 @@ mod tests { lost[0].len(), ); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost )); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost @@ -1017,13 +1006,13 @@ mod tests { fn persistent_congestion_min() { let lost = make_lost(&[1, PERSISTENT_CONG_THRESH + 2]); assert!(persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost )); assert!(persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost @@ -1036,7 +1025,7 @@ mod tests { #[test] fn persistent_congestion_no_prev_ack_newreno() { let lost = make_lost(&[1, PERSISTENT_CONG_THRESH + 2]); - let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)); + let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)); cc.detect_persistent_congestion(Some(by_pto(0)), None, PTO, lost.iter(), Instant::now()); assert_eq!(cc.cwnd(), cc.cwnd_min()); } @@ -1044,7 +1033,7 @@ mod tests { #[test] fn persistent_congestion_no_prev_ack_cubic() { let lost = make_lost(&[1, PERSISTENT_CONG_THRESH + 2]); - let mut cc = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)); + let mut cc = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)); cc.detect_persistent_congestion(Some(by_pto(0)), None, PTO, lost.iter(), Instant::now()); assert_eq!(cc.cwnd(), cc.cwnd_min()); } @@ -1055,7 +1044,7 @@ mod tests { fn persistent_congestion_unsorted_newreno() { let lost = make_lost(&[PERSISTENT_CONG_THRESH + 2, 1]); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost @@ -1068,7 +1057,7 @@ mod tests { fn persistent_congestion_unsorted_cubic() { let lost = make_lost(&[PERSISTENT_CONG_THRESH + 2, 1]); assert!(!persistent_congestion_by_pto( - ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)), + ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)), 0, 0, &lost @@ -1079,7 +1068,7 @@ mod tests { fn app_limited_slow_start() { const BELOW_APP_LIMIT_PKTS: usize = 5; const ABOVE_APP_LIMIT_PKTS: usize = BELOW_APP_LIMIT_PKTS + 1; - let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)); + let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)); let cwnd = cc.congestion_window; let mut now = now(); let mut next_pn = 0; @@ -1163,7 +1152,7 @@ mod tests { const BELOW_APP_LIMIT_PKTS: usize = CWND_PKTS_CA - 2; const ABOVE_APP_LIMIT_PKTS: usize = BELOW_APP_LIMIT_PKTS + 1; - let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)); + let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)); let mut now = now(); // Change state to congestion avoidance by introducing loss. @@ -1279,7 +1268,7 @@ mod tests { #[test] fn ecn_ce() { let now = now(); - let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)); + let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)); let p_ce = SentPacket::new( PacketType::Short, 1, diff --git a/third_party/rust/neqo-transport/src/cc/cubic.rs b/third_party/rust/neqo-transport/src/cc/cubic.rs index c8c0188ddb5d..6a4630f58e1f 100644 --- a/third_party/rust/neqo-transport/src/cc/cubic.rs +++ b/third_party/rust/neqo-transport/src/cc/cubic.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! CUBIC congestion control + use std::{ fmt::{self, Display}, time::{Duration, Instant}, @@ -13,19 +15,38 @@ use neqo_common::qtrace; use crate::cc::classic_cc::WindowAdjustment; -// CUBIC congestion control - -// C is a constant fixed to determine the aggressiveness of window -// increase in high BDP networks. +/// > C is a constant fixed to determine the aggressiveness of window +/// > increase in high BDP networks. +/// +/// +/// +/// See discussion for rational for concrete value. +/// +/// pub const CUBIC_C: f64 = 0.4; +/// TCP-friendly region additive factor +/// +/// pub const CUBIC_ALPHA: f64 = 3.0 * (1.0 - 0.7) / (1.0 + 0.7); -// CUBIC_BETA = 0.7; +/// `CUBIC_BETA` = 0.7; +/// +/// > Principle 4: To balance between the scalability and convergence speed, +/// > CUBIC sets the multiplicative window decrease factor to 0.7 while Standard +/// > TCP uses 0.5. While this improves the scalability of CUBIC, a side effect +/// > of this decision is slower convergence, especially under low statistical +/// > multiplexing environments. +/// +/// pub const CUBIC_BETA_USIZE_DIVIDEND: usize = 7; pub const CUBIC_BETA_USIZE_DIVISOR: usize = 10; -/// The fast convergence ratio further reduces the congestion window when a congestion event -/// occurs before reaching the previous `W_max`. +/// The fast convergence ratio further reduces the congestion window when a +/// congestion event occurs before reaching the previous `W_max`. +/// +/// See formula defined below. +/// +/// pub const CUBIC_FAST_CONVERGENCE: f64 = 0.85; // (1.0 + CUBIC_BETA) / 2.0; /// The minimum number of multiples of the datagram size that need @@ -47,11 +68,41 @@ pub fn convert_to_f64(v: usize) -> f64 { #[derive(Debug)] pub struct Cubic { + /// Maximum Window size two congestion events ago. + /// + /// > With fast convergence, when a congestion event occurs, before the + /// > window reduction of the congestion window, a flow remembers the last + /// > value of W_max before it updates W_max for the current congestion + /// > event. + /// + /// last_max_cwnd: f64, + /// Estimate of Standard TCP congestion window for Cubic's TCP-friendly + /// Region. + /// + /// > Standard TCP performs well in certain types of networks, for example, + /// > under short RTT and small bandwidth (or small BDP) networks. In + /// > these networks, we use the TCP-friendly region to ensure that CUBIC + /// > achieves at least the same throughput as Standard TCP. + /// + /// estimated_tcp_cwnd: f64, + /// > K is the time period that the above function takes to increase the + /// > current window size to W_max if there are no further congestion events + /// + /// k: f64, + /// > W_max is the window size just before the window is reduced in the last + /// > congestion event. + /// + /// w_max: f64, + /// > the elapsed time from the beginning of the current congestion + /// > avoidance + /// + /// ca_epoch_start: Option, + /// Number of bytes acked since the last Standard TCP congestion window increase. tcp_acked_bytes: f64, } @@ -91,12 +142,16 @@ impl Cubic { /// /// From that equation we can calculate K as: /// K = cubic_root((W_max - W_cubic) / C / MSS); + /// + /// fn calc_k(&self, curr_cwnd: f64, max_datagram_size: usize) -> f64 { ((self.w_max - curr_cwnd) / CUBIC_C / convert_to_f64(max_datagram_size)).cbrt() } /// W_cubic(t) = C*(t-K)^3 + W_max (Eq. 1) /// t is relative to the start of the congestion avoidance phase and it is in seconds. + /// + /// fn w_cubic(&self, t: f64, max_datagram_size: usize) -> f64 { (CUBIC_C * (t - self.k).powi(3)).mul_add(convert_to_f64(max_datagram_size), self.w_max) } @@ -119,7 +174,7 @@ impl Cubic { self.w_max = self.last_max_cwnd; self.k = self.calc_k(curr_cwnd_f64, max_datagram_size); } - qtrace!([self], "New epoch"); + qtrace!("[{self}] New epoch"); } } @@ -144,6 +199,10 @@ impl WindowAdjustment for Cubic { self.tcp_acked_bytes += new_acked_f64; } + // Cubic concave or convex region + // + // + // let time_ca = self .ca_epoch_start .map_or(min_rtt, |t| { @@ -158,6 +217,9 @@ impl WindowAdjustment for Cubic { .as_secs_f64(); let target_cubic = self.w_cubic(time_ca, max_datagram_size); + // Cubic TCP-friendly region + // + // let max_datagram_size = convert_to_f64(max_datagram_size); let tcp_cnt = self.estimated_tcp_cwnd / CUBIC_ALPHA; let incr = (self.tcp_acked_bytes / tcp_cnt).floor(); @@ -166,10 +228,19 @@ impl WindowAdjustment for Cubic { self.estimated_tcp_cwnd += incr * max_datagram_size; } + // Take the larger cwnd of Cubic concave or convex and Cubic + // TCP-friendly region. + // + // > When receiving an ACK in congestion avoidance (cwnd could be + // > greater than or less than W_max), CUBIC checks whether W_cubic(t) is + // > less than W_est(t). If so, CUBIC is in the TCP-friendly region and + // > cwnd SHOULD be set to W_est(t) at each reception of an ACK. + // + // let target_cwnd = target_cubic.max(self.estimated_tcp_cwnd); // Calculate the number of bytes that would need to be acknowledged for an increase - // of `MAX_DATAGRAM_SIZE` to match the increase of `target - cwnd / cwnd` as defined + // of `max_datagram_size` to match the increase of `target - cwnd / cwnd` as defined // in the specification (Sections 4.4 and 4.5). // The amount of data required therefore reduces asymptotically as the target increases. // If the target is not significantly higher than the congestion window, require a very @@ -191,10 +262,13 @@ impl WindowAdjustment for Cubic { ) -> (usize, usize) { let curr_cwnd_f64 = convert_to_f64(curr_cwnd); // Fast Convergence + // // If congestion event occurs before the maximum congestion window before the last // congestion event, we reduce the the maximum congestion window and thereby W_max. // check cwnd + MAX_DATAGRAM_SIZE instead of cwnd because with cwnd in bytes, cwnd may be // slightly off. + // + // self.last_max_cwnd = if curr_cwnd_f64 + convert_to_f64(max_datagram_size) < self.last_max_cwnd { curr_cwnd_f64 * CUBIC_FAST_CONVERGENCE diff --git a/third_party/rust/neqo-transport/src/cc/tests/cubic.rs b/third_party/rust/neqo-transport/src/cc/tests/cubic.rs index e62c063b909a..cf76ae130068 100644 --- a/third_party/rust/neqo-transport/src/cc/tests/cubic.rs +++ b/third_party/rust/neqo-transport/src/cc/tests/cubic.rs @@ -8,7 +8,6 @@ #![allow(clippy::cast_sign_loss)] use std::{ - net::{IpAddr, Ipv4Addr}, ops::Sub, time::{Duration, Instant}, }; @@ -16,6 +15,7 @@ use std::{ use neqo_common::IpTosEcn; use test_fixture::now; +use super::{IP_ADDR, MTU, RTT}; use crate::{ cc::{ classic_cc::ClassicCongestionControl, @@ -23,7 +23,7 @@ use crate::{ convert_to_f64, Cubic, CUBIC_ALPHA, CUBIC_BETA_USIZE_DIVIDEND, CUBIC_BETA_USIZE_DIVISOR, CUBIC_C, CUBIC_FAST_CONVERGENCE, }, - CongestionControl, + CongestionControl as _, }, packet::PacketType, pmtud::Pmtud, @@ -31,9 +31,6 @@ use crate::{ rtt::RttEstimate, }; -const IP_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); -const RTT: Duration = Duration::from_millis(100); - const fn cwnd_after_loss(cwnd: usize) -> usize { cwnd * CUBIC_BETA_USIZE_DIVIDEND / CUBIC_BETA_USIZE_DIVISOR } @@ -95,7 +92,7 @@ fn expected_tcp_acks(cwnd_rtt_start: usize, mtu: usize) -> u64 { #[test] fn tcp_phase() { - let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)); + let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)); // change to congestion avoidance state. cubic.set_ssthresh(1); @@ -183,7 +180,7 @@ fn tcp_phase() { assert!(num_acks2 < expected_ack_tcp_increase2); // The time needed to increase cwnd by MAX_DATAGRAM_SIZE using the cubic equation will be - // calculates from: W_cubic(elapsed_time + t_to_increase) - W_cubic(elapsed_time) = + // calculated from: W_cubic(elapsed_time + t_to_increase) - W_cubic(elapsed_time) = // MAX_DATAGRAM_SIZE => CUBIC_C * (elapsed_time + t_to_increase)^3 * MAX_DATAGRAM_SIZE + // CWND_INITIAL - CUBIC_C * elapsed_time^3 * MAX_DATAGRAM_SIZE + CWND_INITIAL = // MAX_DATAGRAM_SIZE => t_to_increase = cbrt((1 + CUBIC_C * elapsed_time^3) / CUBIC_C) - @@ -202,8 +199,8 @@ fn tcp_phase() { #[test] fn cubic_phase() { - let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)); - let cwnd_initial_f64: f64 = convert_to_f64(cubic.cwnd_initial()); + let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)); + let cwnd_initial_f64 = convert_to_f64(cubic.cwnd_initial()); // Set last_max_cwnd to a higher number make sure that cc is the cubic phase (cwnd is calculated // by the cubic equation). cubic.set_last_max_cwnd(cwnd_initial_f64 * 10.0); @@ -257,7 +254,7 @@ fn assert_within + PartialOrd + Copy>(value: T, expected: T, #[test] fn congestion_event_slow_start() { - let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)); + let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)); _ = fill_cwnd(&mut cubic, 0, now()); ack_packet(&mut cubic, 0, now()); @@ -274,7 +271,7 @@ fn congestion_event_slow_start() { packet_lost(&mut cubic, 1); // last_max_cwnd is equal to cwnd before decrease. - let cwnd_initial_f64: f64 = convert_to_f64(cubic.cwnd_initial()); + let cwnd_initial_f64 = convert_to_f64(cubic.cwnd_initial()); assert_within( cubic.last_max_cwnd(), cwnd_initial_f64 + convert_to_f64(cubic.max_datagram_size()), @@ -288,7 +285,7 @@ fn congestion_event_slow_start() { #[test] fn congestion_event_congestion_avoidance() { - let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)); + let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)); // Set ssthresh to something small to make sure that cc is in the congection avoidance phase. cubic.set_ssthresh(1); @@ -305,20 +302,20 @@ fn congestion_event_congestion_avoidance() { // Trigger a congestion_event in slow start phase packet_lost(&mut cubic, 1); - let cwnd_initial_f64: f64 = convert_to_f64(cubic.cwnd_initial()); + let cwnd_initial_f64 = convert_to_f64(cubic.cwnd_initial()); assert_within(cubic.last_max_cwnd(), cwnd_initial_f64, f64::EPSILON); assert_eq!(cubic.cwnd(), cwnd_after_loss(cubic.cwnd_initial())); } #[test] fn congestion_event_congestion_avoidance_2() { - let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)); + let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)); // Set ssthresh to something small to make sure that cc is in the congection avoidance phase. cubic.set_ssthresh(1); // Set last_max_cwnd to something higher than cwnd so that the fast convergence is triggered. - let cwnd_initial_f64: f64 = convert_to_f64(cubic.cwnd_initial()); + let cwnd_initial_f64 = convert_to_f64(cubic.cwnd_initial()); cubic.set_last_max_cwnd(cwnd_initial_f64 * 10.0); _ = fill_cwnd(&mut cubic, 0, now()); @@ -341,13 +338,13 @@ fn congestion_event_congestion_avoidance_2() { #[test] fn congestion_event_congestion_avoidance_no_overflow() { const PTO: Duration = Duration::from_millis(120); - let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR)); + let mut cubic = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU)); // Set ssthresh to something small to make sure that cc is in the congection avoidance phase. cubic.set_ssthresh(1); // Set last_max_cwnd to something higher than cwnd so that the fast convergence is triggered. - let cwnd_initial_f64: f64 = convert_to_f64(cubic.cwnd_initial()); + let cwnd_initial_f64 = convert_to_f64(cubic.cwnd_initial()); cubic.set_last_max_cwnd(cwnd_initial_f64 * 10.0); _ = fill_cwnd(&mut cubic, 0, now()); diff --git a/third_party/rust/neqo-transport/src/cc/tests/mod.rs b/third_party/rust/neqo-transport/src/cc/tests/mod.rs index 879693fb24df..45bed8fd8814 100644 --- a/third_party/rust/neqo-transport/src/cc/tests/mod.rs +++ b/third_party/rust/neqo-transport/src/cc/tests/mod.rs @@ -4,5 +4,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::{ + net::{IpAddr, Ipv4Addr}, + time::Duration, +}; + mod cubic; mod new_reno; + +pub const IP_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED); +pub const MTU: Option = Some(1_500); +pub const RTT: Duration = Duration::from_millis(100); diff --git a/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs b/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs index 0b4e64af5559..640e59e800fa 100644 --- a/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs +++ b/third_party/rust/neqo-transport/src/cc/tests/new_reno.rs @@ -6,25 +6,21 @@ // Congestion control -use std::{ - net::{IpAddr, Ipv4Addr}, - time::Duration, -}; +use std::time::Duration; use neqo_common::IpTosEcn; use test_fixture::now; +use super::{IP_ADDR, MTU, RTT}; use crate::{ - cc::{new_reno::NewReno, ClassicCongestionControl, CongestionControl}, + cc::{new_reno::NewReno, ClassicCongestionControl, CongestionControl as _}, packet::PacketType, pmtud::Pmtud, recovery::SentPacket, rtt::RttEstimate, }; -const IP_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); -const PTO: Duration = Duration::from_millis(100); -const RTT: Duration = Duration::from_millis(98); +const PTO: Duration = RTT; const RTT_ESTIMATE: RttEstimate = RttEstimate::from_duration(RTT); fn cwnd_is_default(cc: &ClassicCongestionControl) { @@ -40,7 +36,7 @@ fn cwnd_is_halved(cc: &ClassicCongestionControl) { #[test] #[allow(clippy::too_many_lines)] fn issue_876() { - let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)); + let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)); let now = now(); let before = now.checked_sub(Duration::from_millis(100)).unwrap(); let after = now + Duration::from_millis(150); @@ -151,7 +147,7 @@ fn issue_876() { #[test] // https://github.com/mozilla/neqo/pull/1465 fn issue_1465() { - let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR)); + let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU)); let mut pn = 0; let mut now = now(); let max_datagram_size = cc.max_datagram_size(); diff --git a/third_party/rust/neqo-transport/src/cid.rs b/third_party/rust/neqo-transport/src/cid.rs index 0e3144a70782..72587da5ba46 100644 --- a/third_party/rust/neqo-transport/src/cid.rs +++ b/third_party/rust/neqo-transport/src/cid.rs @@ -93,7 +93,7 @@ impl<'a> From> for ConnectionId { } } -impl std::ops::Deref for ConnectionId { +impl Deref for ConnectionId { type Target = [u8]; fn deref(&self) -> &Self::Target { @@ -142,7 +142,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> From<&'a T> for ConnectionIdRef<'a> { } } -impl std::ops::Deref for ConnectionIdRef<'_> { +impl Deref for ConnectionIdRef<'_> { type Target = [u8]; fn deref(&self) -> &Self::Target { diff --git a/third_party/rust/neqo-transport/src/connection/dump.rs b/third_party/rust/neqo-transport/src/connection/dump.rs index 10e102552459..68f892818bc2 100644 --- a/third_party/rust/neqo-transport/src/connection/dump.rs +++ b/third_party/rust/neqo-transport/src/connection/dump.rs @@ -7,7 +7,7 @@ // Enable just this file for logging to just see packets. // e.g. "RUST_LOG=neqo_transport::dump neqo-client ..." -use std::fmt::Write; +use std::fmt::Write as _; use neqo_common::{qdebug, Decoder, IpTos}; @@ -42,17 +42,11 @@ pub fn dump_packet( }; let x = f.dump(); if !x.is_empty() { - _ = write!(&mut s, "\n {} {}", dir, &x); + _ = write!(&mut s, "\n {dir} {}", &x); } } qdebug!( - [conn], - "pn={} type={:?} {} {:?} len {}{}", - pn, - pt, - path.borrow(), - tos, - len, - s + "[{conn}] pn={pn} type={pt:?} {} {tos:?} len {len}{s}", + path.borrow() ); } diff --git a/third_party/rust/neqo-transport/src/connection/idle.rs b/third_party/rust/neqo-transport/src/connection/idle.rs index c5b570a09c31..6e327705f8b5 100644 --- a/third_party/rust/neqo-transport/src/connection/idle.rs +++ b/third_party/rust/neqo-transport/src/connection/idle.rs @@ -39,9 +39,6 @@ impl IdleTimeout { keep_alive_outstanding: false, } } -} - -impl IdleTimeout { pub fn set_peer_timeout(&mut self, peer_timeout: Duration) { self.timeout = min(self.timeout, peer_timeout); } diff --git a/third_party/rust/neqo-transport/src/connection/mod.rs b/third_party/rust/neqo-transport/src/connection/mod.rs index bb8098abaa9a..dcdbb7bebef5 100644 --- a/third_party/rust/neqo-transport/src/connection/mod.rs +++ b/third_party/rust/neqo-transport/src/connection/mod.rs @@ -6,6 +6,8 @@ // The class implementing a QUIC connection. +#![allow(clippy::module_name_repetitions)] + use std::{ cell::RefCell, cmp::{max, min}, @@ -36,7 +38,7 @@ use crate::{ ConnectionIdRef, ConnectionIdStore, LOCAL_ACTIVE_CID_LIMIT, }, crypto::{Crypto, CryptoDxState, CryptoSpace}, - ecn::EcnCount, + ecn, events::{ConnectionEvent, ConnectionEvents, OutgoingDatagramOutcome}, frame::{ CloseError, Frame, FrameType, FRAME_TYPE_CONNECTION_CLOSE_APPLICATION, @@ -53,10 +55,7 @@ use crate::{ stats::{Stats, StatsCell}, stream_id::StreamType, streams::{SendOrder, Streams}, - tparams::{ - self, TransportParameter, TransportParameterId, TransportParameters, - TransportParametersHandler, - }, + tparams::{self, TransportParameters, TransportParametersHandler}, tracking::{AckTracker, PacketNumberSpace, RecvdPackets}, version::{Version, WireVersion}, AppError, CloseReason, Error, Res, StreamId, @@ -201,7 +200,7 @@ impl AddressValidationInfo { pub fn generate_new_token(&self, peer_address: SocketAddr, now: Instant) -> Option> { match self { - Self::Server(ref w) => w.upgrade().and_then(|validation| { + Self::Server(w) => w.upgrade().and_then(|validation| { validation .borrow() .generate_new_token(peer_address, now) @@ -337,6 +336,7 @@ impl Connection { c.conn_params.pacing_enabled(), NeqoQlog::default(), now, + &mut c.stats.borrow_mut(), ); c.setup_handshake_path(&Rc::new(RefCell::new(path)), now); Ok(c) @@ -403,7 +403,7 @@ impl Connection { state: State::Init, paths: Paths::default(), cid_manager, - tps: tphandler.clone(), + tps: Rc::clone(&tphandler), zero_rtt_state: ZeroRttState::Init, address_validation: AddressValidationInfo::None, local_initial_source_cid, @@ -441,7 +441,7 @@ impl Connection { zero_rtt_checker: impl ZeroRttChecker + 'static, ) -> Res<()> { self.crypto - .server_enable_0rtt(self.tps.clone(), anti_replay, zero_rtt_checker) + .server_enable_0rtt(Rc::clone(&self.tps), anti_replay, zero_rtt_checker) } /// # Errors @@ -496,17 +496,18 @@ impl Connection { /// When the transport parameter is invalid. /// # Panics /// This panics if the transport parameter is known to this crate. - pub fn set_local_tparam(&self, tp: TransportParameterId, value: TransportParameter) -> Res<()> { - #[cfg(not(test))] - { - assert!(!tparams::INTERNAL_TRANSPORT_PARAMETERS.contains(&tp)); - } + #[cfg(test)] + pub fn set_local_tparam( + &self, + tp: tparams::TransportParameterId, + value: tparams::TransportParameter, + ) -> Res<()> { if *self.state() == State::Init { self.tps.borrow_mut().local.set(tp, value); Ok(()) } else { qerror!("Current state: {:?}", self.state()); - qerror!("Cannot set local tparam when not in an initial connection state."); + qerror!("Cannot set local tparam when not in an initial connection state"); Err(Error::ConnectionState) } } @@ -522,13 +523,7 @@ impl Connection { retry_cid: &ConnectionId, ) { debug_assert_eq!(self.role, Role::Server); - qtrace!( - [self], - "Retry CIDs: odcid={} remote={} retry={}", - odcid, - remote_cid, - retry_cid - ); + qtrace!("[{self}] Retry CIDs: odcid={odcid} remote={remote_cid} retry={retry_cid}"); // We advertise "our" choices in transport parameters. let local_tps = &mut self.tps.borrow_mut().local; local_tps.set_bytes(tparams::ORIGINAL_DESTINATION_CONNECTION_ID, odcid.to_vec()); @@ -560,7 +555,7 @@ impl Connection { /// When the operation fails, which is usually due to bad inputs or bad connection state. pub fn set_ciphers(&mut self, ciphers: &[Cipher]) -> Res<()> { if self.state != State::Init { - qerror!([self], "Cannot enable ciphers in state {:?}", self.state); + qerror!("[{self}] Cannot enable ciphers in state {:?}", self.state); return Err(Error::ConnectionState); } self.crypto.tls.set_ciphers(ciphers)?; @@ -572,7 +567,7 @@ impl Connection { /// When the operation fails, which is usually due to bad inputs or bad connection state. pub fn set_groups(&mut self, groups: &[Group]) -> Res<()> { if self.state != State::Init { - qerror!([self], "Cannot enable groups in state {:?}", self.state); + qerror!("[{self}] Cannot enable groups in state {:?}", self.state); return Err(Error::ConnectionState); } self.crypto.tls.set_groups(groups)?; @@ -584,7 +579,7 @@ impl Connection { /// When the operation fails, which is usually due to bad inputs or bad connection state. pub fn send_additional_key_shares(&mut self, count: usize) -> Res<()> { if self.state != State::Init { - qerror!([self], "Cannot enable groups in state {:?}", self.state); + qerror!("[{self}] Cannot enable groups in state {:?}", self.state); return Err(Error::ConnectionState); } self.crypto.tls.send_additional_key_shares(count)?; @@ -649,8 +644,7 @@ impl Connection { } qtrace!( - [self], - "Maybe create resumption token: {} {}", + "[{self}] Maybe create resumption token: {} {}", self.crypto.has_resumption_token(), self.new_token.has_token() ); @@ -698,15 +692,13 @@ impl Connection { pub fn take_resumption_token(&mut self, now: Instant) -> Option { assert_eq!(self.role, Role::Client); - if self.crypto.has_resumption_token() { + self.crypto.has_resumption_token().then(|| { let token = self.make_resumption_token(); if self.crypto.has_resumption_token() { self.release_resumption_token_timer = Some(now + 3 * self.pto()); } - Some(token) - } else { - None - } + token + }) } /// Enable resumption, using a token previously provided. @@ -717,7 +709,7 @@ impl Connection { /// When the operation fails, which is usually due to bad inputs or bad connection state. pub fn enable_resumption(&mut self, now: Instant, token: impl AsRef<[u8]>) -> Res<()> { if self.state != State::Init { - qerror!([self], "set token in state {:?}", self.state); + qerror!("[{self}] set token in state {:?}", self.state); return Err(Error::ConnectionState); } if self.role == Role::Server { @@ -725,34 +717,34 @@ impl Connection { } qinfo!( - [self], - "resumption token {}", + "[{self}] resumption token {}", hex_snip_middle(token.as_ref()) ); let mut dec = Decoder::from(token.as_ref()); - let version = Version::try_from(u32::try_from( - dec.decode_uint(4).ok_or(Error::InvalidResumptionToken)?, - )?)?; - qtrace!([self], " version {:?}", version); + let version = Version::try_from( + dec.decode_uint::() + .ok_or(Error::InvalidResumptionToken)?, + )?; + qtrace!("[{self}] version {version:?}"); if !self.conn_params.get_versions().all().contains(&version) { return Err(Error::DisabledVersion); } let rtt = Duration::from_millis(dec.decode_varint().ok_or(Error::InvalidResumptionToken)?); - qtrace!([self], " RTT {:?}", rtt); + qtrace!("[{self}] RTT {rtt:?}"); let tp_slice = dec.decode_vvec().ok_or(Error::InvalidResumptionToken)?; - qtrace!([self], " transport parameters {}", hex(tp_slice)); + qtrace!("[{self}] transport parameters {}", hex(tp_slice)); let mut dec_tp = Decoder::from(tp_slice); let tp = TransportParameters::decode(&mut dec_tp).map_err(|_| Error::InvalidResumptionToken)?; let init_token = dec.decode_vvec().ok_or(Error::InvalidResumptionToken)?; - qtrace!([self], " Initial token {}", hex(init_token)); + qtrace!("[{self}] Initial token {}", hex(init_token)); let tok = dec.decode_remainder(); - qtrace!([self], " TLS token {}", hex(tok)); + qtrace!("[{self}] TLS token {}", hex(tok)); match self.crypto.tls { Agent::Client(ref mut c) => { @@ -787,7 +779,7 @@ impl Connection { } pub(crate) fn set_validation(&mut self, validation: &Rc>) { - qtrace!([self], "Enabling NEW_TOKEN"); + qtrace!("[{self}] Enabling NEW_TOKEN"); assert_eq!(self.role, Role::Server); self.address_validation = AddressValidationInfo::Server(Rc::downgrade(validation)); } @@ -808,7 +800,7 @@ impl Connection { }); enc.encode(extra); let records = s.send_ticket(now, enc.as_ref())?; - qdebug!([self], "send session ticket {}", hex(&enc)); + qdebug!("[{self}] send session ticket {}", hex(&enc)); self.crypto.buffer_records(records)?; } else { unreachable!(); @@ -854,7 +846,7 @@ impl Connection { /// the connection to fail. However, if no packets have been /// exchanged, it's not OK. pub fn authenticated(&mut self, status: AuthenticationStatus, now: Instant) { - qdebug!([self], "Authenticated {:?}", status); + qdebug!("[{self}] Authenticated {status:?}"); self.crypto.tls.authenticated(status); let res = self.handshake(now, self.version, PacketNumberSpace::Handshake, None); self.absorb_error(now, res); @@ -916,7 +908,7 @@ impl Connection { State::Closing { error: err, .. } | State::Draining { error: err, .. } | State::Closed(err) => { - qwarn!([self], "Closing again after error {:?}", err); + qwarn!("[{self}] Closing again after error {err:?}"); } State::Init => { // We have not even sent anything just close the connection without sending any @@ -984,7 +976,7 @@ impl Connection { let pto = self.pto(); if self.idle_timeout.expired(now, pto) { - qinfo!([self], "idle timeout expired"); + qinfo!("[{self}] idle timeout expired"); self.set_state( State::Closed(CloseReason::Transport(Error::IdleTimeout)), now, @@ -993,7 +985,7 @@ impl Connection { } if self.state.closing() { - qtrace!([self], "Closing, not processing other timers"); + qtrace!("[{self}] Closing, not processing other timers"); return; } @@ -1016,7 +1008,7 @@ impl Connection { .paths .process_timeout(now, pto, &mut self.stats.borrow_mut()) { - qinfo!([self], "last available path failed"); + qinfo!("[{self}] last available path failed"); self.absorb_error::(now, Err(Error::NoAvailablePath)); } } @@ -1052,7 +1044,7 @@ impl Connection { /// Get the time that we next need to be called back, relative to `now`. fn next_delay(&mut self, now: Instant, paced: bool) -> Duration { - qtrace!([self], "Get callback delay {:?}", now); + qtrace!("[{self}] Get callback delay {now:?}"); // Only one timer matters when closing... if let State::Closing { timeout, .. } | State::Draining { timeout, .. } = self.state { @@ -1062,7 +1054,7 @@ impl Connection { let mut delays = SmallVec::<[_; 7]>::new(); if let Some(ack_time) = self.acks.ack_time(now) { - qtrace!([self], "Delayed ACK timer {:?}", ack_time); + qtrace!("[{self}] Delayed ACK timer {ack_time:?}"); delays.push(ack_time); } @@ -1072,36 +1064,36 @@ impl Connection { let pto = rtt.pto(self.confirmed()); let idle_time = self.idle_timeout.expiry(now, pto); - qtrace!([self], "Idle timer {:?}", idle_time); + qtrace!("[{self}] Idle timer {idle_time:?}"); delays.push(idle_time); if self.streams.need_keep_alive() { if let Some(keep_alive_time) = self.idle_timeout.next_keep_alive(now, pto) { - qtrace!([self], "Keep alive timer {:?}", keep_alive_time); + qtrace!("[{self}] Keep alive timer {keep_alive_time:?}"); delays.push(keep_alive_time); } } if let Some(lr_time) = self.loss_recovery.next_timeout(&path) { - qtrace!([self], "Loss recovery timer {:?}", lr_time); + qtrace!("[{self}] Loss recovery timer {lr_time:?}"); delays.push(lr_time); } if paced { if let Some(pace_time) = path.sender().next_paced(rtt.estimate()) { - qtrace!([self], "Pacing timer {:?}", pace_time); + qtrace!("[{self}] Pacing timer {pace_time:?}"); delays.push(pace_time); } } if let Some(path_time) = self.paths.next_timeout(pto) { - qtrace!([self], "Path probe timer {:?}", path_time); + qtrace!("[{self}] Path probe timer {path_time:?}"); delays.push(path_time); } } if let Some(key_update_time) = self.crypto.states.update_time() { - qtrace!([self], "Key update timer {:?}", key_update_time); + qtrace!("[{self}] Key update timer {key_update_time:?}"); delays.push(key_update_time); } @@ -1115,7 +1107,7 @@ impl Connection { // rather than just clamping to zero here. debug_assert!(earliest > now); let delay = earliest.saturating_duration_since(now); - qdebug!([self], "delay duration {:?}", delay); + qdebug!("[{self}] delay duration {delay:?}"); self.hrtime.update(delay / 4); delay } @@ -1126,7 +1118,7 @@ impl Connection { /// even if no incoming packets. #[must_use = "Output of the process_output function must be handled"] pub fn process_output(&mut self, now: Instant) -> Output { - qtrace!([self], "process_output {:?} {:?}", self.state, now); + qtrace!("[{self}] process_output {:?} {now:?}", self.state); match (&self.state, self.role) { (State::Init, Role::Client) => { @@ -1185,7 +1177,7 @@ impl Connection { } fn handle_retry(&mut self, packet: &PublicPacket, now: Instant) -> Res<()> { - qinfo!([self], "received Retry"); + qinfo!("[{self}] received Retry"); if matches!(self.address_validation, AddressValidationInfo::Retry { .. }) { self.stats.borrow_mut().pkt_dropped("Extra Retry"); return Ok(()); @@ -1217,10 +1209,8 @@ impl Connection { let retry_scid = ConnectionId::from(packet.scid()); qinfo!( - [self], - "Valid Retry received, token={} scid={}", - hex(packet.token()), - retry_scid + "[{self}] Valid Retry received, token={} scid={retry_scid}", + hex(packet.token()) ); let lost_packets = self.loss_recovery.retry(&path, now); @@ -1240,7 +1230,7 @@ impl Connection { fn discard_keys(&mut self, space: PacketNumberSpace, now: Instant) { if self.crypto.discard(space) { - qdebug!([self], "Drop packet number space {}", space); + qdebug!("[{self}] Drop packet number space {space}"); if let Some(path) = self.paths.primary() { self.loss_recovery.discard(&path, space, now); } @@ -1268,7 +1258,7 @@ impl Connection { if first && self.is_stateless_reset(path, d) { // Failing to process a packet in a datagram might // indicate that there is a stateless reset present. - qdebug!([self], "Stateless reset: {}", hex(&d[d.len() - 16..])); + qdebug!("[{self}] Stateless reset: {}", hex(&d[d.len() - 16..])); self.state_signaling.reset(); self.set_state( State::Draining { @@ -1286,10 +1276,10 @@ impl Connection { /// Process any saved datagrams that might be available for processing. fn process_saved(&mut self, now: Instant) { while let Some(cspace) = self.saved_datagrams.available() { - qdebug!([self], "process saved for space {:?}", cspace); + qdebug!("[{self}] process saved for space {cspace:?}"); debug_assert!(self.crypto.states.rx_hp(self.version, cspace).is_some()); for saved in self.saved_datagrams.take_saved() { - qtrace!([self], "input saved @{:?}: {:?}", saved.t, saved.d); + qtrace!("[{self}] input saved @{:?}: {:?}", saved.t, saved.d); self.input(saved.d, saved.t, now); } } @@ -1322,7 +1312,7 @@ impl Connection { if let Some(version) = self.conn_params.get_versions().preferred(supported) { assert_ne!(self.version, version); - qinfo!([self], "Version negotiation: trying {:?}", version); + qinfo!("[{self}] Version negotiation: trying {version:?}"); let path = self.paths.primary().ok_or(Error::NoAvailablePath)?; let local_addr = path.borrow().local_address(); let remote_addr = path.borrow().remote_address(); @@ -1352,7 +1342,7 @@ impl Connection { ); Ok(()) } else { - qinfo!([self], "Version negotiation: failed with {:?}", supported); + qinfo!("[{self}] Version negotiation: failed with {supported:?}"); // This error goes straight to closed. self.set_state( State::Closed(CloseReason::Transport(Error::VersionNegotiation)), @@ -1400,8 +1390,7 @@ impl Connection { return Ok(PreprocessResult::Next); } qinfo!( - [self], - "Received valid Initial packet with scid {:?} dcid {:?}", + "[{self}] Received valid Initial packet with scid {:?} dcid {:?}", packet.scid(), packet.dcid() ); @@ -1553,10 +1542,11 @@ impl Connection { self.conn_params.get_cc_algorithm(), self.conn_params.pacing_enabled(), now, + &mut self.stats.borrow_mut(), ); path.borrow_mut().add_received(d.len()); let res = self.input_path(&path, d, received); - self.capture_error(Some(path), now, 0, res).ok(); + _ = self.capture_error(Some(path), now, 0, res); } fn input_path( @@ -1568,7 +1558,7 @@ impl Connection { let mut slc = d.as_ref(); let mut dcid = None; - qtrace!([self], "{} input {}", path.borrow(), hex(&d)); + qtrace!("[{self}] {} input {}", path.borrow(), hex(&d)); let pto = path.borrow().rtt().pto(self.confirmed()); // Handle each packet in the datagram. @@ -1578,8 +1568,8 @@ impl Connection { match PublicPacket::decode(slc, self.cid_manager.decoder().as_ref()) { Ok((packet, remainder)) => (packet, remainder), Err(e) => { - qinfo!([self], "Garbage packet: {}", e); - qtrace!([self], "Garbage packet contents: {}", hex(slc)); + qinfo!("[{self}] Garbage packet: {e}"); + qtrace!("[{self}] Garbage packet contents: {}", hex(slc)); self.stats.borrow_mut().pkt_dropped("Garbage packet"); break; } @@ -1590,7 +1580,7 @@ impl Connection { PreprocessResult::End => return Ok(()), } - qtrace!([self], "Received unverified packet {:?}", packet); + qtrace!("[{self}] Received unverified packet {packet:?}"); match packet.decrypt(&mut self.crypto.states, now + pto) { Ok(payload) => { @@ -1621,7 +1611,7 @@ impl Connection { let space = PacketNumberSpace::from(payload.packet_type()); if let Some(space) = self.acks.get_mut(space) { if space.is_duplicate(payload.pn()) { - qdebug!("Duplicate packet {}-{}", space, payload.pn()); + qdebug!("Duplicate packet {space}-{}", payload.pn()); self.stats.borrow_mut().dups_rx += 1; } else { match self.process_packet(path, &payload, now) { @@ -1636,9 +1626,7 @@ impl Connection { } } else { qdebug!( - [self], - "Received packet {} for untracked space {}", - space, + "[{self}] Received packet {space} for untracked space {}", payload.pn() ); return Err(Error::ProtocolViolation); @@ -1698,7 +1686,7 @@ impl Connection { // Get the next packet number we'll send, for ACK verification. // TODO: Once PR #2118 lands, this can move to `input_frame`. For now, it needs to be here, - // because we can drop packet number spaces as we parse throught the packet, and if an ACK + // because we can drop packet number spaces as we parse through the packet, and if an ACK // frame follows a CRYPTO frame that makes us drop a space, we need to know this // packet number to verify the ACK against. let next_pn = self @@ -1738,8 +1726,7 @@ impl Connection { space.set_received(now, packet.pn(), ack_eliciting) } else { qdebug!( - [self], - "processed a {:?} packet without tracking it", + "[{self}] processed a {:?} packet without tracking it", packet.packet_type(), ); // This was a valid packet that caused the same packet number to be @@ -1796,11 +1783,11 @@ impl Connection { .make_permanent(path, None, ConnectionIdEntry::empty_remote(), now); Ok(()) } else { - qtrace!([self], "Unable to make path permanent: {}", path.borrow()); + qtrace!("[{self}] Unable to make path permanent: {}", path.borrow()); Err(Error::InvalidMigration) } } else { - qtrace!([self], "Unable to make path permanent: {}", path.borrow()); + qtrace!("[{self}] Unable to make path permanent: {}", path.borrow()); Err(Error::InvalidMigration) } } else { @@ -1820,13 +1807,13 @@ impl Connection { self.setup_handshake_path(path, now); } else { // Otherwise try to get a usable connection ID. - mem::drop(self.ensure_permanent(path, now)); + drop(self.ensure_permanent(path, now)); } } } fn start_handshake(&mut self, path: &PathRef, packet: &PublicPacket, now: Instant) { - qtrace!([self], "starting handshake"); + qtrace!("[{self}] starting handshake"); debug_assert_eq!(packet.packet_type(), PacketType::Initial); self.remote_initial_source_cid = Some(ConnectionId::from(packet.scid())); @@ -1837,17 +1824,17 @@ impl Connection { self.setup_handshake_path(path, now); self.zero_rtt_state = if self.crypto.enable_0rtt(self.version, self.role) == Ok(true) { - qdebug!([self], "Accepted 0-RTT"); + qdebug!("[{self}] Accepted 0-RTT"); ZeroRttState::AcceptedServer } else { - qtrace!([self], "Rejected 0-RTT"); + qtrace!("[{self}] Rejected 0-RTT"); ZeroRttState::Rejected }; // The server knows the final version if it has remote transport parameters. self.tps.borrow().remote.is_some() } else { - qdebug!([self], "Changing to use Server CID={}", packet.scid()); + qdebug!("[{self}] Changing to use Server CID={}", packet.scid()); debug_assert!(path.borrow().is_primary()); path.borrow_mut().set_remote_cid(packet.scid()); @@ -1924,11 +1911,11 @@ impl Connection { self.conn_params.get_cc_algorithm(), self.conn_params.pacing_enabled(), now, + &mut self.stats.borrow_mut(), ); self.ensure_permanent(&path, now)?; qinfo!( - [self], - "Migrate to {} probe {}", + "[{self}] Migrate to {} probe {}", path.borrow(), if force { "now" } else { "after" } ); @@ -1946,7 +1933,7 @@ impl Connection { self.conn_params.get_preferred_address(), PreferredAddressConfig::Disabled ) { - qdebug!([self], "Preferred address is disabled"); + qdebug!("[{self}] Preferred address is disabled"); None } else { self.tps.borrow_mut().remote().get_preferred_address() @@ -1974,18 +1961,18 @@ impl Connection { // Ignore preferred address that move to loopback from non-loopback. // `migrate` doesn't enforce this rule. if !prev.ip().is_loopback() && remote.ip().is_loopback() { - qwarn!([self], "Ignoring a move to a loopback address: {}", remote); + qwarn!("[{self}] Ignoring a move to a loopback address: {remote}"); return Ok(()); } if self.migrate(None, Some(remote), false, now).is_err() { - qwarn!([self], "Ignoring bad preferred address: {}", remote); + qwarn!("[{self}] Ignoring bad preferred address: {remote}"); } } else { - qwarn!([self], "Unable to migrate to a different address family"); + qwarn!("[{self}] Unable to migrate to a different address family"); } } else { - qdebug!([self], "No preferred address to migrate to"); + qdebug!("[{self}] No preferred address to migrate to"); } Ok(()) } @@ -2009,15 +1996,14 @@ impl Connection { .handle_migration(path, d.source(), now, &mut self.stats.borrow_mut()); } else { qinfo!( - [self], - "{} Peer migrated, but no connection ID available", + "[{self}] {} Peer migrated, but no connection ID available", path.borrow() ); } } fn output(&mut self, now: Instant) -> SendOption { - qtrace!([self], "output {:?}", now); + qtrace!("[{self}] output {now:?}"); let res = match &self.state { State::Init | State::WaitInitial @@ -2041,7 +2027,7 @@ impl Connection { // a packet on a new path, we avoid sending (and the privacy risk) rather // than reuse a connection ID. let res = if path.borrow().is_temporary() { - qerror!([self], "Attempting to close with a temporary path"); + qerror!("[{self}] Attempting to close with a temporary path"); Err(Error::InternalError) } else { self.output_path(&path, now, Some(&details)) @@ -2069,8 +2055,7 @@ impl Connection { PacketBuilder::short(encoder, tx.key_phase(), path.remote_cid()) } else { qdebug!( - "Building {:?} dcid {:?} scid {:?}", - pt, + "Building {pt:?} dcid {:?} scid {:?}", path.remote_cid(), path.local_cid(), ); @@ -2096,7 +2081,7 @@ impl Connection { let pn = tx.next_pn(); let unacked_range = largest_acknowledged.map_or_else(|| pn + 1, |la| (pn - la) << 1); // Count how many bytes in this range are non-zero. - let pn_len = mem::size_of::() + let pn_len = std::mem::size_of::() - usize::try_from(unacked_range.leading_zeros() / 8).unwrap(); assert!( pn_len > 0, @@ -2175,6 +2160,7 @@ impl Connection { let frame_stats = &mut stats.frame_tx; self.crypto.write_frame( PacketNumberSpace::ApplicationData, + self.conn_params.sni_slicing_enabled(), builder, tokens, frame_stats, @@ -2290,7 +2276,7 @@ impl Connection { } if profile.ack_only(space) { - // If we are CC limited we can only send acks! + // If we are CC limited we can only send ACKs! return (tokens, false, false); } @@ -2309,7 +2295,13 @@ impl Connection { self.write_appdata_frames(builder, &mut tokens); } else { let stats = &mut self.stats.borrow_mut().frame_tx; - self.crypto.write_frame(space, builder, &mut tokens, stats); + self.crypto.write_frame( + space, + self.conn_params.sni_slicing_enabled(), + builder, + &mut tokens, + stats, + ); } } @@ -2384,7 +2376,7 @@ impl Connection { // Determine how we are sending packets (PTO, etc..). let profile = self.loss_recovery.send_profile(&path.borrow(), now); - qdebug!([self], "output_path send_profile {:?}", profile); + qdebug!("[{self}] output_path send_profile {profile:?}"); // Frames for different epochs must go in different packets, but then these // packets can go in a single datagram @@ -2514,7 +2506,7 @@ impl Connection { } if encoder.is_empty() { - qdebug!("TX blocked, profile={:?}", profile); + qdebug!("TX blocked, profile={profile:?}"); Ok(SendOption::No(profile.paced())) } else { // Perform additional padding for Initial packets as necessary. @@ -2522,8 +2514,7 @@ impl Connection { if let Some(mut initial) = initial_sent.take() { if needs_padding { qdebug!( - [self], - "pad Initial from {} to PLPMTU {}", + "[{self}] pad Initial from {} to PLPMTU {}", packets.len(), profile.limit() ); @@ -2549,7 +2540,7 @@ impl Connection { let la = self .loss_recovery .largest_acknowledged_pn(PacketNumberSpace::ApplicationData); - qinfo!([self], "Initiating key update"); + qinfo!("[{self}] Initiating key update"); self.crypto.states.initiate_key_update(la) } else { Err(Error::KeyUpdateBlocked) @@ -2563,7 +2554,7 @@ impl Connection { } fn client_start(&mut self, now: Instant) -> Res<()> { - qdebug!([self], "client_start"); + qdebug!("[{self}] client_start"); debug_assert_eq!(self.role, Role::Client); if let Some(path) = self.paths.primary() { qlog::client_connection_started(&self.qlog, &path, now); @@ -2577,7 +2568,7 @@ impl Connection { self.handshake(now, self.version, PacketNumberSpace::Initial, None)?; self.set_state(State::WaitInitial, now); self.zero_rtt_state = if self.crypto.enable_0rtt(self.version, self.role)? { - qdebug!([self], "Enabled 0-RTT"); + qdebug!("[{self}] Enabled 0-RTT"); ZeroRttState::Sending } else { ZeroRttState::Init @@ -2689,8 +2680,7 @@ impl Connection { != tp.map(ConnectionIdRef::from) { qwarn!( - [self], - "ISCID test failed: self cid {:?} != tp cid {:?}", + "[{self}] ISCID test failed: self cid {:?} != tp cid {:?}", self.remote_initial_source_cid, tp.map(hex), ); @@ -2706,8 +2696,7 @@ impl Connection { != tp.map(ConnectionIdRef::from) { qwarn!( - [self], - "ODCID test failed: self cid {:?} != tp cid {:?}", + "[{self}] ODCID test failed: self cid {:?} != tp cid {:?}", self.original_destination_cid, tp.map(hex), ); @@ -2725,9 +2714,7 @@ impl Connection { }; if expected != tp.map(ConnectionIdRef::from) { qwarn!( - [self], - "RSCID test failed. self cid {:?} != tp cid {:?}", - expected, + "[{self}] RSCID test failed. self cid {expected:?} != tp cid {:?}", tp.map(hex), ); return Err(Error::ProtocolViolation); @@ -2745,11 +2732,8 @@ impl Connection { // We're checking that these match our expectations. if let Some((current, other)) = remote_tps.get_versions() { qtrace!( - [self], - "validate_versions: current={:x} chosen={:x} other={:x?}", + "[{self}] validate_versions: current={:x} chosen={current:x} other={other:x?}", self.version.wire_version(), - current, - other, ); if self.role == Role::Server { // 1. A server acts on transport parameters, with validation @@ -2758,7 +2742,7 @@ impl Connection { // was provided. Ok(()) } else if self.version().wire_version() != current { - qinfo!([self], "validate_versions: current version mismatch"); + qinfo!("[{self}] validate_versions: current version mismatch"); Err(Error::VersionNegotiation) } else if self .conn_params @@ -2783,12 +2767,12 @@ impl Connection { { Ok(()) } else { - qinfo!([self], "validate_versions: failed"); + qinfo!("[{self}] validate_versions: failed"); Err(Error::VersionNegotiation) } } } else if self.version != Version::Version1 && !self.version.is_draft() { - qinfo!([self], "validate_versions: missing extension"); + qinfo!("[{self}] validate_versions: missing extension"); Err(Error::VersionNegotiation) } else { Ok(()) @@ -2797,7 +2781,7 @@ impl Connection { fn confirm_version(&mut self, v: Version) { if self.version != v { - qdebug!([self], "Compatible upgrade {:?} ==> {:?}", self.version, v); + qdebug!("[{self}] Compatible upgrade {:?} ==> {v:?}", self.version); } self.crypto.confirm_version(v); self.version = v; @@ -2829,7 +2813,7 @@ impl Connection { space: PacketNumberSpace, data: Option<&[u8]>, ) -> Res<()> { - qtrace!([self], "Handshake space={} data={:0x?}", space, data); + qtrace!("[{self}] Handshake space={space} data={data:0x?}"); let was_authentication_pending = *self.crypto.tls.state() == HandshakeState::AuthenticationPending; @@ -2884,7 +2868,7 @@ impl Connection { .ok_or(Error::InternalError)? .borrow_mut() .pmtud_mut() - .start(); + .start(now, &mut self.stats.borrow_mut()); } Ok(()) } @@ -2900,7 +2884,7 @@ impl Connection { now: Instant, ) -> Res<()> { if !frame.is_allowed(packet_type) { - qinfo!("frame not allowed: {:?} {:?}", frame, packet_type); + qinfo!("frame not allowed: {frame:?} {packet_type:?}"); return Err(Error::ProtocolViolation); } let space = PacketNumberSpace::from(packet_type); @@ -2932,7 +2916,7 @@ impl Connection { // (If we ever start using non-contiguous packet numbers, we need to check all the // packet numbers in the ACKed ranges.) if largest_acknowledged >= next_pn { - qwarn!("Largest ACKed {} was never sent", largest_acknowledged); + qwarn!("Largest ACKed {largest_acknowledged} was never sent"); return Err(Error::AckedUnsentPacket); } @@ -2942,10 +2926,7 @@ impl Connection { } Frame::Crypto { offset, data } => { qtrace!( - [self], - "Crypto frame on space={} offset={}, data={:0x?}", - space, - offset, + "[{self}] Crypto frame on space={space} offset={offset}, data={:0x?}", &data ); self.stats.borrow_mut().frame_rx.crypto += 1; @@ -2953,7 +2934,7 @@ impl Connection { if self.crypto.streams.data_ready(space) { let mut buf = Vec::new(); let read = self.crypto.streams.read_to_end(space, &mut buf); - qdebug!("Read {:?} bytes", read); + qdebug!("Read {read:?} bytes"); self.handshake(now, packet_version, space, Some(&buf))?; self.create_resumption_token(now); } else { @@ -2986,7 +2967,7 @@ impl Connection { self.paths .retire_cids(retire_prior, &mut self.connection_ids); if self.connection_ids.len() >= LOCAL_ACTIVE_CID_LIMIT { - qinfo!([self], "received too many connection IDs"); + qinfo!("[{self}] received too many connection IDs"); return Err(Error::ConnectionIdLimitExceeded); } } @@ -3018,11 +2999,7 @@ impl Connection { } => { self.stats.borrow_mut().frame_rx.connection_close += 1; qinfo!( - [self], - "ConnectionClose received. Error code: {:?} frame type {:x} reason {}", - error_code, - frame_type, - reason_phrase + "[{self}] ConnectionClose received. Error code: {error_code:?} frame type {frame_type:x} reason {reason_phrase}" ); let (detail, frame_type) = if let CloseError::Application(_) = error_code { // Use a transport error here because we want to send @@ -3088,7 +3065,7 @@ impl Connection { fn handle_lost_packets(&mut self, lost_packets: &[SentPacket]) { for lost in lost_packets { for token in lost.tokens() { - qdebug!([self], "Lost: {:?}", token); + qdebug!("[{self}] Lost: {token:?}"); match token { RecoveryToken::Ack(ack_token) => { // If we lost an ACK frame during the handshake, send another one. @@ -3130,14 +3107,14 @@ impl Connection { &mut self, space: PacketNumberSpace, ack_ranges: R, - ack_ecn: Option, + ack_ecn: Option, ack_delay: u64, now: Instant, ) where R: IntoIterator> + Debug, R::IntoIter: ExactSizeIterator, { - qdebug!([self], "Rx ACK space={}, ranges={:?}", space, ack_ranges); + qdebug!("[{self}] Rx ACK space={space}, ranges={ack_ranges:?}"); let Some(path) = self.paths.primary() else { return; @@ -3192,7 +3169,7 @@ impl Connection { if !matches!(self.zero_rtt_state, ZeroRttState::Sending) { return; } - qdebug!([self], "0-RTT rejected"); + qdebug!("[{self}] 0-RTT rejected"); self.resend_0rtt(now); self.streams.zero_rtt_rejected(); self.crypto.states.discard_0rtt_keys(); @@ -3200,9 +3177,9 @@ impl Connection { } fn set_connected(&mut self, now: Instant) -> Res<()> { - qdebug!([self], "TLS connection complete"); + qdebug!("[{self}] TLS connection complete"); if self.crypto.tls.info().map(SecretAgentInfo::alpn).is_none() { - qwarn!([self], "No ALPN. Closing connection."); + qwarn!("[{self}] No ALPN, closing connection"); // 120 = no_application_protocol return Err(Error::CryptoAlert(120)); } @@ -3248,13 +3225,13 @@ impl Connection { self.state_signaling.handshake_done(); self.set_confirmed(now)?; } - qinfo!([self], "Connection established"); + qinfo!("[{self}] Connection established"); Ok(()) } fn set_state(&mut self, state: State, now: Instant) { if state > self.state { - qdebug!([self], "State change from {:?} -> {:?}", self.state, state); + qdebug!("[{self}] State change from {:?} -> {state:?}", self.state); self.state = state.clone(); if self.state.closed() { self.streams.clear_streams(); @@ -3277,8 +3254,8 @@ impl Connection { /// /// # Errors /// - /// `ConnectionState` if the connecton stat does not allow to create streams. - /// `StreamLimitError` if we are limiied by server's stream concurence. + /// `ConnectionState` if the connection stat does not allow to create streams. + /// `StreamLimitError` if we are limited by server's stream concurrence. pub fn stream_create(&mut self, st: StreamType) -> Res { // Can't make streams while closing, otherwise rely on the stream limits. match self.state { @@ -3380,8 +3357,7 @@ impl Connection { if let Ok(val) = val { debug_assert!( val == 0 || val == data.len(), - "Unexpected value {} when trying to send {} bytes atomically", - val, + "Unexpected value {val} when trying to send {} bytes atomically", data.len() ); } @@ -3547,7 +3523,7 @@ impl Connection { /// # Errors /// /// The function returns `TooMuchData` if the supply buffer is bigger than - /// the allowed remote datagram size. The funcion does not check if the + /// the allowed remote datagram size. The function does not check if the /// datagram can fit into a packet (i.e. MTU limit). This is checked during /// creation of an actual packet and the datagram will be dropped if it does /// not fit into the packet. The app is encourage to use `max_datagram_size` @@ -3591,7 +3567,7 @@ impl ::std::fmt::Display for Connection { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{:?} ", self.role)?; if let Some(cid) = self.odcid() { - std::fmt::Display::fmt(&cid, f) + fmt::Display::fmt(&cid, f) } else { write!(f, "...") } diff --git a/third_party/rust/neqo-transport/src/connection/params.rs b/third_party/rust/neqo-transport/src/connection/params.rs index fb176d904e67..3b25b6e23499 100644 --- a/third_party/rust/neqo-transport/src/connection/params.rs +++ b/third_party/rust/neqo-transport/src/connection/params.rs @@ -41,7 +41,7 @@ pub enum PreferredAddressConfig { Address(PreferredAddress), } -/// `ConnectionParameters` use for setting intitial value for QUIC parameters. +/// `ConnectionParameters` use for setting initial value for QUIC parameters. /// This collects configuration like initial limits, protocol version, and /// congestion control algorithm. #[allow(clippy::struct_excessive_bools)] // We need that many, sorry. @@ -83,13 +83,15 @@ pub struct ConnectionParameters { pacing: bool, /// Whether the connection performs PLPMTUD. pmtud: bool, + /// Whether the connection should use SNI slicing. + sni_slicing: bool, } impl Default for ConnectionParameters { fn default() -> Self { Self { versions: VersionConfig::default(), - cc_algorithm: CongestionControlAlgorithm::NewReno, + cc_algorithm: CongestionControlAlgorithm::Cubic, max_data: LOCAL_MAX_DATA, max_stream_data_bidi_remote: u64::try_from(RECV_BUFFER_SIZE).unwrap(), max_stream_data_bidi_local: u64::try_from(RECV_BUFFER_SIZE).unwrap(), @@ -107,6 +109,7 @@ impl Default for ConnectionParameters { disable_migration: false, pacing: true, pmtud: false, + sni_slicing: true, } } } @@ -189,7 +192,7 @@ impl ConnectionParameters { (StreamType::BiDi, false) => self.max_stream_data_bidi_local, (StreamType::BiDi, true) => self.max_stream_data_bidi_remote, (StreamType::UniDi, false) => { - panic!("Can't get receive limit on a stream that can only be sent.") + panic!("Can't get receive limit on a stream that can only be sent") } (StreamType::UniDi, true) => self.max_stream_data_uni, } @@ -212,7 +215,7 @@ impl ConnectionParameters { self.max_stream_data_bidi_remote = v; } (StreamType::UniDi, false) => { - panic!("Can't set receive limit on a stream that can only be sent.") + panic!("Can't set receive limit on a stream that can only be sent") } (StreamType::UniDi, true) => { self.max_stream_data_uni = v; @@ -367,6 +370,17 @@ impl ConnectionParameters { self } + #[must_use] + pub const fn sni_slicing_enabled(&self) -> bool { + self.sni_slicing + } + + #[must_use] + pub const fn sni_slicing(mut self, sni_slicing: bool) -> Self { + self.sni_slicing = sni_slicing; + self + } + /// # Errors /// When a connection ID cannot be obtained. /// # Panics diff --git a/third_party/rust/neqo-transport/src/connection/state.rs b/third_party/rust/neqo-transport/src/connection/state.rs index d5193b794240..2404f8d377f9 100644 --- a/third_party/rust/neqo-transport/src/connection/state.rs +++ b/third_party/rust/neqo-transport/src/connection/state.rs @@ -222,13 +222,11 @@ impl StateSignaling { } pub fn write_done(&mut self, builder: &mut PacketBuilder) -> Option { - if matches!(self, Self::HandshakeDone) && builder.remaining() >= 1 { + (matches!(self, Self::HandshakeDone) && builder.remaining() >= 1).then(|| { *self = Self::Idle; builder.encode_varint(FRAME_TYPE_HANDSHAKE_DONE); - Some(RecoveryToken::HandshakeDone) - } else { - None - } + RecoveryToken::HandshakeDone + }) } pub fn close( diff --git a/third_party/rust/neqo-transport/src/connection/tests/ackrate.rs b/third_party/rust/neqo-transport/src/connection/tests/ackrate.rs index 8d7a560d2b9c..b1bded087e2c 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/ackrate.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/ackrate.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{mem, time::Duration}; +use std::time::Duration; use test_fixture::{assertions, DEFAULT_ADDR_V4}; @@ -94,7 +94,7 @@ fn ack_rate_persistent_congestion() { let stream = client.stream_create(StreamType::UniDi).unwrap(); let (dgrams, mut now) = fill_cwnd(&mut client, stream, now); now += RTT / 2; - mem::drop(ack_bytes(&mut server, stream, dgrams, now)); + drop(ack_bytes(&mut server, stream, dgrams, now)); let now = induce_persistent_congestion(&mut client, &mut server, stream, now); diff --git a/third_party/rust/neqo-transport/src/connection/tests/cc.rs b/third_party/rust/neqo-transport/src/connection/tests/cc.rs index 09bcefb7a4c7..b1d2509f27fe 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/cc.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/cc.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{mem, time::Duration}; +use std::time::Duration; use neqo_common::{qdebug, qinfo, Datagram, IpTosEcn}; @@ -19,8 +19,7 @@ use crate::{ recovery::{ACK_ONLY_SIZE_LIMIT, PACKET_THRESHOLD}, sender::PACING_BURST_SIZE, stream_id::StreamType, - tracking::DEFAULT_ACK_PACKET_TOLERANCE, - ConnectionParameters, + CongestionControlAlgorithm, ConnectionParameters, }; #[test] @@ -211,12 +210,11 @@ fn single_packet_on_recovery() { assert!(dgram.is_some()); } -#[test] /// Verify that CC moves out of recovery period when packet sent after start /// of recovery period is acked. -fn cc_cong_avoidance_recovery_period_to_cong_avoidance() { - let mut client = default_client(); - let mut server = default_server(); +fn cc_cong_avoidance_recovery_period_to_cong_avoidance(cc_algorithm: CongestionControlAlgorithm) { + let mut client = new_client(ConnectionParameters::default().cc_algorithm(cc_algorithm)); + let mut server = new_server(ConnectionParameters::default().cc_algorithm(cc_algorithm)); let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT); // Create stream 0 @@ -233,60 +231,45 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() { now += DEFAULT_RTT / 2; let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now); + let cwnd_before_loss = cwnd(&client); + // Client: Process ack now += DEFAULT_RTT / 2; client.process_input(s_ack, now); + let cwnd_after_loss = cwnd(&client); + // Should be in CARP now. now += DEFAULT_RTT / 2; + assert!(cwnd_before_loss > cwnd_after_loss); qinfo!("moving to congestion avoidance {}", cwnd(&client)); - // Now make sure that we increase congestion window according to the - // accurate byte counting version of congestion avoidance. - // Check over several increases to be sure. - let mut expected_cwnd = cwnd(&client); - // Fill cwnd. - let (mut c_tx_dgrams, next_now) = fill_cwnd(&mut client, stream_id, now); - now = next_now; - for i in 0..5 { - qinfo!("iteration {}", i); + for i in 0..6 { + qinfo!("iteration {i}"); - let c_tx_size: usize = c_tx_dgrams.iter().map(Datagram::len).sum(); + let (c_tx_dgrams, next_now) = fill_cwnd(&mut client, stream_id, now); qinfo!( "client sending {} bytes into cwnd of {}", - c_tx_size, + c_tx_dgrams.iter().map(Datagram::len).sum::(), cwnd(&client) ); - assert_eq!(c_tx_size, expected_cwnd); - - // As acks arrive we will continue filling cwnd and save all packets - // from this cycle will be stored in next_c_tx_dgrams. - let mut next_c_tx_dgrams: Vec = Vec::new(); - - // Until we process all the packets, the congestion window remains the same. - // Note that we need the client to process ACK frames in stages, so split the - // datagrams into two, ensuring that we allow for an ACK for each batch. - let most = c_tx_dgrams.len() - usize::try_from(DEFAULT_ACK_PACKET_TOLERANCE).unwrap() - 1; - let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams.drain(..most), now); - assert_eq!(cwnd(&client), expected_cwnd); - client.process_input(s_ack, now); - // make sure to fill cwnd again. - let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now); now = next_now; - next_c_tx_dgrams.append(&mut new_pkts); let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now); - assert_eq!(cwnd(&client), expected_cwnd); client.process_input(s_ack, now); - // make sure to fill cwnd again. - let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now); - now = next_now; - next_c_tx_dgrams.append(&mut new_pkts); - - expected_cwnd += client.plpmtu(); - assert_eq!(cwnd(&client), expected_cwnd); - c_tx_dgrams = next_c_tx_dgrams; } + + assert!(cwnd_before_loss < cwnd(&client)); +} + +#[test] +fn cc_cong_avoidance_recovery_period_to_cong_avoidance_new_reno() { + cc_cong_avoidance_recovery_period_to_cong_avoidance(CongestionControlAlgorithm::NewReno); +} + +#[test] +fn cc_cong_avoidance_recovery_period_to_cong_avoidance_cubic() { + cc_cong_avoidance_recovery_period_to_cong_avoidance(CongestionControlAlgorithm::Cubic); } #[test] @@ -304,7 +287,7 @@ fn cc_slow_start_to_persistent_congestion_no_acks() { // Server: Receive and generate ack now += DEFAULT_RTT / 2; - mem::drop(ack_bytes(&mut server, stream, c_tx_dgrams, now)); + drop(ack_bytes(&mut server, stream, c_tx_dgrams, now)); // ACK lost. induce_persistent_congestion(&mut client, &mut server, stream, now); @@ -355,7 +338,7 @@ fn cc_persistent_congestion_to_slow_start() { // Server: Receive and generate ack now += Duration::from_millis(10); - mem::drop(ack_bytes(&mut server, stream, c_tx_dgrams, now)); + drop(ack_bytes(&mut server, stream, c_tx_dgrams, now)); // ACK lost. @@ -398,7 +381,7 @@ fn ack_are_not_cc() { // The server hasn't received any of these packets yet, the server // won't ACK, but if it sends an ack-eliciting packet instead. - qdebug!([server], "Sending ack-eliciting"); + qdebug!("[{server}] Sending ack-eliciting"); let other_stream = server.stream_create(StreamType::BiDi).unwrap(); assert_eq!(other_stream, 1); server.stream_send(other_stream, b"dropped").unwrap(); @@ -412,10 +395,10 @@ fn ack_are_not_cc() { assert!(ack_eliciting_packet.is_some()); // The client can ack the server packet even if cc windows is full. - qdebug!([client], "Process ack-eliciting"); + qdebug!("[{client}] Process ack-eliciting"); let ack_pkt = client.process(ack_eliciting_packet, now).dgram(); assert!(ack_pkt.is_some()); - qdebug!([server], "Handle ACK"); + qdebug!("[{server}] Handle ACK"); let prev_ack_count = server.stats().frame_rx.ack; server.process_input(ack_pkt.unwrap(), now); assert_eq!(server.stats().frame_rx.ack, prev_ack_count + 1); diff --git a/third_party/rust/neqo-transport/src/connection/tests/datagram.rs b/third_party/rust/neqo-transport/src/connection/tests/datagram.rs index 7fb03aba155e..b80a348bca43 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/datagram.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/datagram.rs @@ -6,7 +6,7 @@ use std::{cell::RefCell, rc::Rc}; -use neqo_common::event::Provider; +use neqo_common::event::Provider as _; use static_assertions::const_assert; use test_fixture::now; diff --git a/third_party/rust/neqo-transport/src/connection/tests/ecn.rs b/third_party/rust/neqo-transport/src/connection/tests/ecn.rs index 3b5bd5bc1975..8704d5b9ab8d 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/ecn.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/ecn.rs @@ -19,7 +19,7 @@ use crate::{ new_server, send_and_receive, send_something, send_something_with_modifier, send_with_modifier_and_receive, DEFAULT_RTT, }, - ecn::ECN_TEST_COUNT, + ecn, path::MAX_PATH_PROBES, ConnectionId, ConnectionParameters, StreamType, }; @@ -89,7 +89,7 @@ fn handshake_delay_with_ecn_blackhole() { assert_eq!( (finish - start).as_millis() / DEFAULT_RTT.as_millis(), 15, - "expected 6 RTT for client to detect blackhole, 6 RTT for server to detect blackhole and 3 RTT for handshake to be confirmed.", + "expected 6 RTT for client to detect blackhole, 6 RTT for server to detect blackhole and 3 RTT for handshake to be confirmed", ); } @@ -143,19 +143,23 @@ fn stats() { let mut server = default_server(); connect_force_idle(&mut client, &mut server); - for _ in 0..ECN_TEST_COUNT { + for _ in 0..ecn::TEST_COUNT { let ack = send_and_receive(&mut client, &mut server, now); client.process_input(ack.unwrap(), now); } - for _ in 0..ECN_TEST_COUNT { + for _ in 0..ecn::TEST_COUNT { let ack = send_and_receive(&mut server, &mut client, now); server.process_input(ack.unwrap(), now); } for stats in [client.stats(), server.stats()] { - assert_eq!(stats.ecn_paths_capable, 1); - assert_eq!(stats.ecn_paths_not_capable, 0); + for (outcome, count) in stats.ecn_path_validation.iter() { + match outcome { + ecn::ValidationOutcome::Capable => assert_eq!(*count, 1), + ecn::ValidationOutcome::NotCapable(_) => assert_eq!(*count, 0), + } + } for codepoint in [IpTosEcn::Ect1, IpTosEcn::Ce] { assert_eq!(stats.ecn_tx[codepoint], 0); @@ -178,7 +182,7 @@ fn disables_on_loss() { let client_pkt = send_something(&mut client, now); assert_ecn_enabled(client_pkt.tos()); - for _ in 0..ECN_TEST_COUNT { + for _ in 0..ecn::TEST_COUNT { send_something(&mut client, now); } @@ -194,7 +198,7 @@ fn disables_on_remark() { let mut server = default_server(); connect_force_idle(&mut client, &mut server); - for _ in 0..ECN_TEST_COUNT { + for _ in 0..ecn::TEST_COUNT { if let Some(ack) = send_with_modifier_and_receive(&mut client, &mut server, now, remark()) { client.process_input(ack, now); } @@ -348,22 +352,28 @@ pub fn migration_with_modifiers( #[test] fn ecn_migration_zero_burst_all_cases() { - for orig_path_mod in &[noop(), bleach(), remark(), ce()] { - for new_path_mod in &[noop(), bleach(), remark(), ce(), drop()] { + for orig_path_mod in [noop(), bleach(), remark(), ce()] { + for (new_path_mod_name, new_path_mod) in [ + ("noop", noop()), + ("bleach", bleach()), + ("remark", remark()), + ("ce", ce()), + ("drop", drop()), + ] { let (before, after, migrated) = - migration_with_modifiers(*orig_path_mod, *new_path_mod, 0); + migration_with_modifiers(orig_path_mod, new_path_mod, 0); // Too few packets sent before and after migration to conclude ECN validation. assert_ecn_enabled(before); assert_ecn_enabled(after); // Migration succeeds except if the new path drops ECN. - assert!(*new_path_mod == drop() || migrated); + assert!(new_path_mod_name == "drop" || migrated); } } } #[test] fn ecn_migration_noop_bleach_data() { - let (before, after, migrated) = migration_with_modifiers(noop(), bleach(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(noop(), bleach(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration. assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching. assert!(migrated); @@ -371,7 +381,7 @@ fn ecn_migration_noop_bleach_data() { #[test] fn ecn_migration_noop_remark_data() { - let (before, after, migrated) = migration_with_modifiers(noop(), remark(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(noop(), remark(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration. assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. assert!(migrated); @@ -379,7 +389,7 @@ fn ecn_migration_noop_remark_data() { #[test] fn ecn_migration_noop_ce_data() { - let (before, after, migrated) = migration_with_modifiers(noop(), ce(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(noop(), ce(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration. assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. assert!(migrated); @@ -387,7 +397,7 @@ fn ecn_migration_noop_ce_data() { #[test] fn ecn_migration_noop_drop_data() { - let (before, after, migrated) = migration_with_modifiers(noop(), drop(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(noop(), drop(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration. assert_ecn_enabled(after); // Migration failed, ECN on original path is still validated. assert!(!migrated); @@ -395,7 +405,7 @@ fn ecn_migration_noop_drop_data() { #[test] fn ecn_migration_bleach_noop_data() { - let (before, after, migrated) = migration_with_modifiers(bleach(), noop(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(bleach(), noop(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. assert_ecn_enabled(after); // ECN validation concludes after migration. assert!(migrated); @@ -403,7 +413,7 @@ fn ecn_migration_bleach_noop_data() { #[test] fn ecn_migration_bleach_bleach_data() { - let (before, after, migrated) = migration_with_modifiers(bleach(), bleach(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(bleach(), bleach(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching. assert!(migrated); @@ -411,7 +421,7 @@ fn ecn_migration_bleach_bleach_data() { #[test] fn ecn_migration_bleach_remark_data() { - let (before, after, migrated) = migration_with_modifiers(bleach(), remark(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(bleach(), remark(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. assert!(migrated); @@ -419,7 +429,7 @@ fn ecn_migration_bleach_remark_data() { #[test] fn ecn_migration_bleach_ce_data() { - let (before, after, migrated) = migration_with_modifiers(bleach(), ce(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(bleach(), ce(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. assert!(migrated); @@ -427,7 +437,7 @@ fn ecn_migration_bleach_ce_data() { #[test] fn ecn_migration_bleach_drop_data() { - let (before, after, migrated) = migration_with_modifiers(bleach(), drop(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(bleach(), drop(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to bleaching. // Migration failed, ECN on original path is still disabled. assert_ecn_disabled(after); @@ -436,7 +446,7 @@ fn ecn_migration_bleach_drop_data() { #[test] fn ecn_migration_remark_noop_data() { - let (before, after, migrated) = migration_with_modifiers(remark(), noop(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(remark(), noop(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. assert_ecn_enabled(after); // ECN validation succeeds after migration. assert!(migrated); @@ -444,7 +454,7 @@ fn ecn_migration_remark_noop_data() { #[test] fn ecn_migration_remark_bleach_data() { - let (before, after, migrated) = migration_with_modifiers(remark(), bleach(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(remark(), bleach(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching. assert!(migrated); @@ -452,7 +462,7 @@ fn ecn_migration_remark_bleach_data() { #[test] fn ecn_migration_remark_remark_data() { - let (before, after, migrated) = migration_with_modifiers(remark(), remark(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(remark(), remark(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. assert!(migrated); @@ -460,7 +470,7 @@ fn ecn_migration_remark_remark_data() { #[test] fn ecn_migration_remark_ce_data() { - let (before, after, migrated) = migration_with_modifiers(remark(), ce(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(remark(), ce(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. assert!(migrated); @@ -468,7 +478,7 @@ fn ecn_migration_remark_ce_data() { #[test] fn ecn_migration_remark_drop_data() { - let (before, after, migrated) = migration_with_modifiers(remark(), drop(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(remark(), drop(), ecn::TEST_COUNT); assert_ecn_disabled(before); // ECN validation fails before migration due to remarking. assert_ecn_disabled(after); // Migration failed, ECN on original path is still disabled. assert!(!migrated); @@ -476,7 +486,7 @@ fn ecn_migration_remark_drop_data() { #[test] fn ecn_migration_ce_noop_data() { - let (before, after, migrated) = migration_with_modifiers(ce(), noop(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(ce(), noop(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. assert_ecn_enabled(after); // ECN validation concludes after migration. assert!(migrated); @@ -484,7 +494,7 @@ fn ecn_migration_ce_noop_data() { #[test] fn ecn_migration_ce_bleach_data() { - let (before, after, migrated) = migration_with_modifiers(ce(), bleach(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(ce(), bleach(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. assert_ecn_disabled(after); // ECN validation fails after migration due to bleaching assert!(migrated); @@ -492,7 +502,7 @@ fn ecn_migration_ce_bleach_data() { #[test] fn ecn_migration_ce_remark_data() { - let (before, after, migrated) = migration_with_modifiers(ce(), remark(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(ce(), remark(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. assert_ecn_disabled(after); // ECN validation fails after migration due to remarking. assert!(migrated); @@ -500,7 +510,7 @@ fn ecn_migration_ce_remark_data() { #[test] fn ecn_migration_ce_ce_data() { - let (before, after, migrated) = migration_with_modifiers(ce(), ce(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(ce(), ce(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. assert_ecn_enabled(after); // ECN validation concludes after migration, despite all CE marks. assert!(migrated); @@ -508,7 +518,7 @@ fn ecn_migration_ce_ce_data() { #[test] fn ecn_migration_ce_drop_data() { - let (before, after, migrated) = migration_with_modifiers(ce(), drop(), ECN_TEST_COUNT); + let (before, after, migrated) = migration_with_modifiers(ce(), drop(), ecn::TEST_COUNT); assert_ecn_enabled(before); // ECN validation concludes before migration, despite all CE marks. // Migration failed, ECN on original path is still enabled. assert_ecn_enabled(after); diff --git a/third_party/rust/neqo-transport/src/connection/tests/handshake.rs b/third_party/rust/neqo-transport/src/connection/tests/handshake.rs index 79a19b445e16..c9ff3a5f413d 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/handshake.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/handshake.rs @@ -6,13 +6,12 @@ use std::{ cell::RefCell, - mem, net::{IpAddr, Ipv6Addr, SocketAddr}, rc::Rc, time::Duration, }; -use neqo_common::{event::Provider, qdebug, Datagram}; +use neqo_common::{event::Provider as _, qdebug, Datagram}; use neqo_crypto::{ constants::TLS_CHACHA20_POLY1305_SHA256, generate_ech_keys, AuthenticationStatus, }; @@ -251,8 +250,8 @@ fn crypto_frame_split() { // after the first or second server packet. assert!(client3.as_dgram_ref().is_some() ^ client4.as_dgram_ref().is_some()); - mem::drop(server.process(client3.dgram(), now())); - mem::drop(server.process(client4.dgram(), now())); + drop(server.process(client3.dgram(), now())); + drop(server.process(client4.dgram(), now())); assert_eq!(*client.state(), State::Connected); assert_eq!(*server.state(), State::Confirmed); @@ -371,7 +370,7 @@ fn reorder_05rtt_with_0rtt() { // Send ClientHello and some 0-RTT. let c1 = send_something(&mut client, now); - assertions::assert_coalesced_0rtt(&c1[..]); + assert_coalesced_0rtt(&c1[..]); // Drop the 0-RTT from the coalesced datagram, so that the server // acknowledges the next 0-RTT packet. let (c1, _) = split_datagram(&c1); @@ -379,7 +378,7 @@ fn reorder_05rtt_with_0rtt() { // Handle the first packet and send 0.5-RTT in response. Drop the response. now += RTT / 2; - mem::drop(server.process(Some(c1), now).dgram().unwrap()); + drop(server.process(Some(c1), now).dgram().unwrap()); // The gap in 0-RTT will result in this 0.5 RTT containing an ACK. server.process_input(c2, now); let s2 = send_something(&mut server, now); @@ -452,7 +451,7 @@ fn coalesce_05rtt() { // packet until authentication completes though. So it saves it. now += RTT / 2; assert_eq!(client.stats().dropped_rx, 0); - mem::drop(client.process(s2, now).dgram()); + drop(client.process(s2, now).dgram()); // This packet will contain an ACK, but we can ignore it. assert_eq!(client.stats().dropped_rx, 0); assert_eq!(client.stats().packets_rx, 3); @@ -473,7 +472,7 @@ fn coalesce_05rtt() { assert!(s3.is_some()); assert_eq!(*server.state(), State::Confirmed); now += RTT / 2; - mem::drop(client.process(s3, now).dgram()); + drop(client.process(s3, now).dgram()); assert_eq!(*client.state(), State::Confirmed); assert_eq!(client.stats().dropped_rx, 0); // No dropped packets. @@ -861,7 +860,7 @@ fn drop_handshake_packet_from_wrong_address() { let (s_in, s_hs) = split_datagram(&out.dgram().unwrap()); // Pass the initial packet. - mem::drop(client.process(Some(s_in), now()).dgram()); + drop(client.process(Some(s_in), now()).dgram()); let p = s_hs.unwrap(); let dgram = Datagram::new( @@ -1199,7 +1198,7 @@ fn client_initial_retransmits_identical() { assert_eq!( client.stats().frame_tx, FrameStats { - crypto: i, + crypto: 2 * i, ..Default::default() } ); @@ -1218,7 +1217,7 @@ fn server_initial_retransmits_identical() { // Force the server to retransmit its Initial packet a number of times and make sure the // retranmissions are identical to the original. Also, verify the PTO durations. let mut server = default_server(); - let mut total_ptos: Duration = Duration::from_secs(0); + let mut total_ptos = Duration::from_secs(0); for i in 1..=3 { let si = server.process(ci.take(), now).dgram().unwrap(); assert_eq!(si.len(), server.plpmtu()); diff --git a/third_party/rust/neqo-transport/src/connection/tests/idle.rs b/third_party/rust/neqo-transport/src/connection/tests/idle.rs index deb4312dca89..38f657b89bab 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/idle.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/idle.rs @@ -4,12 +4,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{ - mem, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; -use neqo_common::{qtrace, Encoder}; +use neqo_common::{qtrace, qwarn, Encoder}; use test_fixture::{now, split_datagram}; use super::{ @@ -44,10 +41,10 @@ fn test_idle_timeout(client: &mut Connection, server: &mut Connection, timeout: assert_eq!(res, Output::Callback(timeout)); // Still connected after timeout-1 seconds. Idle timer not reset - mem::drop(client.process_output(now + timeout.checked_sub(Duration::from_secs(1)).unwrap())); + drop(client.process_output(now + timeout.checked_sub(Duration::from_secs(1)).unwrap())); assert!(matches!(client.state(), State::Confirmed)); - mem::drop(client.process_output(now + timeout)); + drop(client.process_output(now + timeout)); // Not connected after timeout. assert!(matches!(client.state(), State::Closed(_))); @@ -220,10 +217,10 @@ fn idle_send_packet2() { // First transmission at t=GAP. now += GAP; - mem::drop(send_something(&mut client, now)); + drop(send_something(&mut client, now)); // Second transmission at t=2*GAP. - mem::drop(send_something(&mut client, now + GAP)); + drop(send_something(&mut client, now + GAP)); assert!((GAP * 2 + DELTA) < default_timeout()); // Still connected just before GAP + default_timeout(). @@ -266,16 +263,16 @@ fn idle_recv_packet() { assert_eq!(server.stream_send(stream, b"world").unwrap(), 5); let out = server.process_output(now); assert_ne!(out.as_dgram_ref(), None); - mem::drop(client.process(out.dgram(), now)); + drop(client.process(out.dgram(), now)); assert!(matches!(client.state(), State::Confirmed)); // Add a little less than the idle timeout and we're still connected. now += default_timeout() - FUDGE; - mem::drop(client.process_output(now)); + drop(client.process_output(now)); assert!(matches!(client.state(), State::Confirmed)); now += FUDGE; - mem::drop(client.process_output(now)); + drop(client.process_output(now)); assert!(matches!(client.state(), State::Closed(_))); } @@ -303,13 +300,14 @@ fn idle_caching() { let dgram = client.process_output(middle).dgram(); // Get the server to send its first probe and throw that away. - mem::drop(server.process_output(middle).dgram()); + drop(server.process_output(middle).dgram()); // Now let the server process the RTX'ed client Initial. This causes the server // to send CRYPTO frames again, so manually extract and discard those. server.process_input(dgram.unwrap(), middle); let mut tokens = Vec::new(); server.crypto.streams.write_frame( PacketNumberSpace::Initial, + server.conn_params.sni_slicing_enabled(), &mut builder, &mut tokens, &mut FrameStats::default(), @@ -318,6 +316,7 @@ fn idle_caching() { tokens.clear(); server.crypto.streams.write_frame( PacketNumberSpace::Initial, + server.conn_params.sni_slicing_enabled(), &mut builder, &mut tokens, &mut FrameStats::default(), @@ -338,8 +337,8 @@ fn idle_caching() { // Now let the server Initial through, with the CRYPTO frame. let dgram = server.process_output(end).dgram(); let (initial, _) = split_datagram(&dgram.unwrap()); - neqo_common::qwarn!("client ingests initial, finally"); - mem::drop(client.process(Some(initial), end)); + qwarn!("client ingests initial, finally"); + drop(client.process(Some(initial), end)); maybe_authenticate(&mut client); let dgram = client.process_output(end).dgram(); let dgram = server.process(dgram, end).dgram(); @@ -359,7 +358,7 @@ fn create_stream_idle_rtt( ) -> (Instant, StreamId) { let check_idle = |endpoint: &mut Connection, now: Instant| { let delay = endpoint.process_output(now).callback(); - qtrace!([endpoint], "idle timeout {:?}", delay); + qtrace!("[{endpoint}] idle timeout {delay:?}"); if rtt < default_timeout() / 4 { assert_eq!(default_timeout(), delay); } else { @@ -474,7 +473,7 @@ fn keep_alive_lost() { assert!(client.process(out, now).dgram().is_none()); // TODO: if we run server.process with current value of now, the server will - // return some small timeout for the recovry although it does not have + // return some small timeout for the recovery although it does not have // any outstanding data. Therefore we call it after AT_LEAST_PTO. now += AT_LEAST_PTO; assert_idle(&mut server, now, keep_alive_timeout() - AT_LEAST_PTO); @@ -640,7 +639,7 @@ fn keep_alive_large_rtt() { for endpoint in &mut [client, server] { endpoint.stream_keep_alive(stream, true).unwrap(); let delay = endpoint.process_output(now).callback(); - qtrace!([endpoint], "new delay {:?}", delay); + qtrace!("[{endpoint}] new delay {delay:?}"); assert!(delay > keep_alive_timeout()); assert!(delay > rtt); } @@ -662,7 +661,7 @@ fn keep_alive_uni() { server.stream_keep_alive(stream, true).unwrap(); } -/// Test a keep-alive ping is send if there are outstading ack-eliciting packets and that +/// Test a keep-alive ping is send if there are outstanding ack-eliciting packets and that /// the connection is closed after the idle timeout passes. #[test] fn keep_alive_with_ack_eliciting_packet_lost() { @@ -672,7 +671,7 @@ fn keep_alive_with_ack_eliciting_packet_lost() { // + 2pto) After handshake all packets will be lost. The following steps will happen after // the handshake: // - data will be sent on a stream that is marked for keep-alive, (at start time) - // - PTO timer will trigger first, and the data will be retransmited toghether with a PING, (at + // - PTO timer will trigger first, and the data will be retransmitted together with a PING, (at // the start time + pto) // - keep-alive timer will trigger and a keep-alive PING will be sent, (at the start time + // IDLE_TIMEOUT / 2) diff --git a/third_party/rust/neqo-transport/src/connection/tests/keys.rs b/third_party/rust/neqo-transport/src/connection/tests/keys.rs index 59bbc2f24cbb..d8686b794390 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/keys.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/keys.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; - use neqo_common::{qdebug, Datagram}; use test_fixture::now; @@ -30,7 +28,7 @@ fn check_discarded( dups: usize, ) { // Make sure to flush any saved datagrams before doing this. - mem::drop(peer.process_output(now())); + drop(peer.process_output(now())); let before = peer.stats(); let out = peer.process(Some(pkt.clone()), now()); @@ -145,7 +143,7 @@ fn key_update_client() { let dgram = client.process_output(now).dgram(); assert!(dgram.is_some()); // Drop this packet. assert_eq!(client.get_epochs(), (Some(4), Some(3))); - mem::drop(server.process_output(now)); + drop(server.process_output(now)); assert_eq!(server.get_epochs(), (Some(4), Some(4))); // Even though the server has updated, it hasn't received an ACK yet. @@ -170,7 +168,7 @@ fn key_update_client() { assert_update_blocked(&mut server); now += AT_LEAST_PTO; - mem::drop(client.process_output(now)); + drop(client.process_output(now)); assert_eq!(client.get_epochs(), (Some(4), Some(4))); } @@ -186,7 +184,7 @@ fn key_update_consecutive() { // Server sends something. // Send twice and drop the first to induce an ACK from the client. - mem::drop(send_something(&mut server, now)); // Drop this. + drop(send_something(&mut server, now)); // Drop this. // Another packet from the server will cause the client to ACK and update keys. let dgram = send_and_receive(&mut server, &mut client, now); @@ -198,7 +196,7 @@ fn key_update_consecutive() { assert_eq!(server.get_epochs(), (Some(4), Some(3))); // Now move the server temporarily into the future so that it // rotates the keys. The client stays in the present. - mem::drop(server.process_output(now + AT_LEAST_PTO)); + drop(server.process_output(now + AT_LEAST_PTO)); assert_eq!(server.get_epochs(), (Some(4), Some(4))); } else { panic!("server should have a timer set"); @@ -304,7 +302,7 @@ fn automatic_update_write_keys() { connect_force_idle(&mut client, &mut server); overwrite_invocations(UPDATE_WRITE_KEYS_AT); - mem::drop(send_something(&mut client, now())); + drop(send_something(&mut client, now())); assert_eq!(client.get_epochs(), (Some(4), Some(3))); } @@ -316,10 +314,10 @@ fn automatic_update_write_keys_later() { overwrite_invocations(UPDATE_WRITE_KEYS_AT + 2); // No update after the first. - mem::drop(send_something(&mut client, now())); + drop(send_something(&mut client, now())); assert_eq!(client.get_epochs(), (Some(3), Some(3))); // The second will update though. - mem::drop(send_something(&mut client, now())); + drop(send_something(&mut client, now())); assert_eq!(client.get_epochs(), (Some(4), Some(3))); } diff --git a/third_party/rust/neqo-transport/src/connection/tests/migration.rs b/third_party/rust/neqo-transport/src/connection/tests/migration.rs index 9e05c9d289ef..949ed961349e 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/migration.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/migration.rs @@ -6,7 +6,6 @@ use std::{ cell::RefCell, - mem, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, rc::Rc, time::{Duration, Instant}, @@ -35,7 +34,7 @@ use crate::{ pmtud::Pmtud, stats::FrameStats, tparams::{self, PreferredAddress, TransportParameter}, - CloseReason, ConnectionId, ConnectionIdDecoder, ConnectionIdGenerator, ConnectionIdRef, + CloseReason, ConnectionId, ConnectionIdDecoder as _, ConnectionIdGenerator, ConnectionIdRef, ConnectionParameters, EmptyConnectionIdGenerator, Error, MIN_INITIAL_PACKET_SIZE, }; @@ -168,8 +167,7 @@ fn rebind( .borrow() .local_cid() .unwrap() - .len() - == 0; + .is_empty(); let mut total_delay = Duration::new(0, 0); loop { let before = server.stats().frame_tx; @@ -1229,7 +1227,7 @@ fn error_on_new_path_with_no_connection_id() { // See issue #1697. We had a crash when the client had a temporary path and // process_output is called. let closing_frames = client.stats().frame_tx.connection_close; - mem::drop(client.process_output(now())); + drop(client.process_output(now())); assert!(matches!( client.state(), State::Closing { diff --git a/third_party/rust/neqo-transport/src/connection/tests/mod.rs b/third_party/rust/neqo-transport/src/connection/tests/mod.rs index e897b7082b63..415cedc04507 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/mod.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/mod.rs @@ -14,7 +14,7 @@ use std::{ }; use enum_map::enum_map; -use neqo_common::{event::Provider, qdebug, qtrace, Datagram, Decoder, Role}; +use neqo_common::{event::Provider as _, qdebug, qtrace, Datagram, Decoder, Role}; use neqo_crypto::{random, AllowZeroRtt, AuthenticationStatus, ResumptionToken}; use test_fixture::{fixture_init, new_neqo_qlog, now, DEFAULT_ADDR}; @@ -180,7 +180,7 @@ pub fn rttvar_after_n_updates(n: usize, rtt: Duration) -> Duration { /// This inserts a PING frame into packets. struct PingWriter {} -impl crate::connection::test_internal::FrameWriter for PingWriter { +impl test_internal::FrameWriter for PingWriter { fn write_frames(&mut self, builder: &mut PacketBuilder) { builder.encode_varint(FRAME_TYPE_PING); } @@ -346,7 +346,7 @@ fn connect_rtt_idle_with_modifier( // Drain events from both as well. _ = client.events().count(); _ = server.events().count(); - qtrace!("----- connected and idle with RTT {:?}", rtt); + qtrace!("----- connected and idle with RTT {rtt:?}"); now } @@ -370,7 +370,7 @@ fn fill_stream(c: &mut Connection, stream: StreamId) { const BLOCK_SIZE: usize = 4_096; loop { let bytes_sent = c.stream_send(stream, &[0x42; BLOCK_SIZE]).unwrap(); - qtrace!("fill_cwnd wrote {} bytes", bytes_sent); + qtrace!("fill_cwnd wrote {bytes_sent} bytes"); if bytes_sent < BLOCK_SIZE { break; } @@ -391,9 +391,8 @@ fn fill_cwnd(c: &mut Connection, stream: StreamId, mut now: Instant) -> (Vec { @@ -465,14 +464,14 @@ where let mut srv_buf = [0; 4_096]; let in_dgrams = in_dgrams.into_iter(); - qdebug!([dest], "ack_bytes {} datagrams", in_dgrams.len()); + qdebug!("[{dest}] ack_bytes {} datagrams", in_dgrams.len()); for dgram in in_dgrams { dest.process_input(dgram, now); } loop { let (bytes_read, _fin) = dest.stream_recv(stream, &mut srv_buf).unwrap(); - qtrace!([dest], "ack_bytes read {} bytes", bytes_read); + qtrace!("[{dest}] ack_bytes read {bytes_read} bytes"); if bytes_read == 0 { break; } @@ -502,13 +501,13 @@ fn induce_persistent_congestion( ) -> Instant { // Note: wait some arbitrary time that should be longer than pto // timer. This is rather brittle. - qtrace!([client], "induce_persistent_congestion"); + qtrace!("[{client}] induce_persistent_congestion"); now += AT_LEAST_PTO; let mut pto_counts = [0; MAX_PTO_COUNTS]; assert_eq!(client.stats.borrow().pto_counts, pto_counts); - qtrace!([client], "first PTO"); + qtrace!("[{client}] first PTO"); let (c_tx_dgrams, next_now) = fill_cwnd(client, stream, now); now = next_now; assert_eq!(c_tx_dgrams.len(), 2); // Two PTO packets @@ -516,7 +515,7 @@ fn induce_persistent_congestion( pto_counts[0] = 1; assert_eq!(client.stats.borrow().pto_counts, pto_counts); - qtrace!([client], "second PTO"); + qtrace!("[{client}] second PTO"); now += AT_LEAST_PTO * 2; let (c_tx_dgrams, next_now) = fill_cwnd(client, stream, now); now = next_now; @@ -526,7 +525,7 @@ fn induce_persistent_congestion( pto_counts[1] = 1; assert_eq!(client.stats.borrow().pto_counts, pto_counts); - qtrace!([client], "third PTO"); + qtrace!("[{client}] third PTO"); now += AT_LEAST_PTO * 4; let (c_tx_dgrams, next_now) = fill_cwnd(client, stream, now); now = next_now; @@ -591,7 +590,7 @@ fn send_something_paced_with_modifier( let stream_id = sender.stream_create(StreamType::UniDi).unwrap(); assert!(sender.stream_send(stream_id, DEFAULT_STREAM_DATA).is_ok()); assert!(sender.stream_close_send(stream_id).is_ok()); - qdebug!([sender], "send_something on {}", stream_id); + qdebug!("[{sender}] send_something on {stream_id}"); let dgram = match sender.process_output(now) { Output::Callback(t) => { assert!(allow_pacing, "send_something: unexpected delay"); @@ -690,6 +689,7 @@ fn assert_path_challenge_min_len(c: &Connection, d: &Datagram, now: Instant) { c.conn_params.get_cc_algorithm(), c.conn_params.pacing_enabled(), now, + &mut c.stats.borrow_mut(), ); if path.borrow().amplification_limit() < path.borrow().plpmtu() { // If the amplification limit is less than the PLPMTU, then the path @@ -698,9 +698,8 @@ fn assert_path_challenge_min_len(c: &Connection, d: &Datagram, now: Instant) { } assert!( d.len() >= MIN_INITIAL_PACKET_SIZE, - "{} < {}", - d.len(), - MIN_INITIAL_PACKET_SIZE + "{} < {MIN_INITIAL_PACKET_SIZE}", + d.len() ); } diff --git a/third_party/rust/neqo-transport/src/connection/tests/priority.rs b/third_party/rust/neqo-transport/src/connection/tests/priority.rs index 3a19a188307a..e770d08f318d 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/priority.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/priority.rs @@ -4,9 +4,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{cell::RefCell, mem, rc::Rc}; +use std::{cell::RefCell, rc::Rc}; -use neqo_common::event::Provider; +use neqo_common::event::Provider as _; use test_fixture::now; use super::{ @@ -208,7 +208,7 @@ fn critical() { let now = now(); // Rather than connect, send stream data in 0.5-RTT. - // That allows this to test that critical streams pre-empt most frame types. + // That allows this to test that critical streams preempt most frame types. let dgram = client.process_output(now).dgram(); let dgram = server.process(dgram, now).dgram(); client.process_input(dgram.unwrap(), now); @@ -243,7 +243,7 @@ fn critical() { // Critical beats everything but HANDSHAKE_DONE. let stats_before = server.stats().frame_tx; - mem::drop(fill_cwnd(&mut server, id, now)); + drop(fill_cwnd(&mut server, id, now)); let stats_after = server.stats().frame_tx; assert_eq!(stats_after.crypto, stats_before.crypto); assert_eq!(stats_after.streams_blocked, 0); @@ -259,7 +259,7 @@ fn important() { let now = now(); // Rather than connect, send stream data in 0.5-RTT. - // That allows this to test that important streams pre-empt most frame types. + // That allows this to test that important streams preempt most frame types. let dgram = client.process_output(now).dgram(); let dgram = server.process(dgram, now).dgram(); client.process_input(dgram.unwrap(), now); @@ -295,7 +295,7 @@ fn important() { // Important beats everything but flow control. let stats_before = server.stats().frame_tx; - mem::drop(fill_cwnd(&mut server, id, now)); + drop(fill_cwnd(&mut server, id, now)); let stats_after = server.stats().frame_tx; assert_eq!(stats_after.crypto, stats_before.crypto); assert_eq!(stats_after.streams_blocked, 1); @@ -312,7 +312,7 @@ fn high_normal() { let now = now(); // Rather than connect, send stream data in 0.5-RTT. - // That allows this to test that important streams pre-empt most frame types. + // That allows this to test that important streams preempt most frame types. let dgram = client.process_output(now).dgram(); let dgram = server.process(dgram, now).dgram(); client.process_input(dgram.unwrap(), now); @@ -350,7 +350,7 @@ fn high_normal() { // but they beat CRYPTO/NEW_TOKEN. let stats_before = server.stats().frame_tx; server.send_ticket(now, &[]).unwrap(); - mem::drop(fill_cwnd(&mut server, id, now)); + drop(fill_cwnd(&mut server, id, now)); let stats_after = server.stats().frame_tx; assert_eq!(stats_after.crypto, stats_before.crypto); assert_eq!(stats_after.streams_blocked, 1); @@ -387,7 +387,7 @@ fn low() { // The resulting CRYPTO frame beats out the stream data. let stats_before = server.stats().frame_tx; server.send_ticket(now, &vec![0; server.plpmtu()]).unwrap(); - mem::drop(server.process_output(now)); + drop(server.process_output(now)); let stats_after = server.stats().frame_tx; assert_eq!(stats_after.crypto, stats_before.crypto + 1); assert_eq!(stats_after.stream, stats_before.stream); @@ -396,7 +396,7 @@ fn low() { // it is very hard to ensure that the STREAM frame won't also fit. // However, we can ensure that the next packet doesn't consist of just STREAM. let stats_before = server.stats().frame_tx; - mem::drop(server.process_output(now)); + drop(server.process_output(now)); let stats_after = server.stats().frame_tx; assert_eq!(stats_after.crypto, stats_before.crypto + 1); assert_eq!(stats_after.new_token, 1); diff --git a/third_party/rust/neqo-transport/src/connection/tests/recovery.rs b/third_party/rust/neqo-transport/src/connection/tests/recovery.rs index f3c319bdecff..dcaabccbdfba 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/recovery.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/recovery.rs @@ -4,10 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{ - mem, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; use neqo_common::qdebug; use neqo_crypto::AuthenticationStatus; @@ -346,7 +343,7 @@ fn pto_handshake_frames() { let pkt = client.process(pkt.dgram(), now); now += Duration::from_millis(10); - mem::drop(server.process(pkt.dgram(), now)); + drop(server.process(pkt.dgram(), now)); now += Duration::from_millis(10); client.authenticated(AuthenticationStatus::Ok, now); @@ -443,7 +440,7 @@ fn loss_recovery_crash() { let now = now(); // The server sends something, but we will drop this. - mem::drop(send_something(&mut server, now)); + drop(send_something(&mut server, now)); // Then send something again, but let it through. let ack = send_and_receive(&mut server, &mut client, now); @@ -459,7 +456,7 @@ fn loss_recovery_crash() { assert!(dgram.is_some()); // This crashes. - mem::drop(send_something(&mut server, now + AT_LEAST_PTO)); + drop(send_something(&mut server, now + AT_LEAST_PTO)); } // If we receive packets after the PTO timer has fired, we won't clear @@ -474,7 +471,7 @@ fn ack_after_pto() { let mut now = now(); // The client sends and is forced into a PTO. - mem::drop(send_something(&mut client, now)); + drop(send_something(&mut client, now)); // Jump forward to the PTO and drain the PTO packets. now += AT_LEAST_PTO; @@ -490,7 +487,7 @@ fn ack_after_pto() { // delivery is just the thing. // Note: The server can't ACK anything here, but none of what // the client has sent so far has been transferred. - mem::drop(send_something(&mut server, now)); + drop(send_something(&mut server, now)); let dgram = send_something(&mut server, now); // The client is now after a PTO, but if it receives something @@ -646,7 +643,7 @@ fn trickle(sender: &mut Connection, receiver: &mut Connection, mut count: usize, let id = sender.stream_create(StreamType::UniDi).unwrap(); let mut maybe_ack = None; while count > 0 { - qdebug!("trickle: remaining={}", count); + qdebug!("trickle: remaining={count}"); assert_eq!(sender.stream_send(id, &[9]).unwrap(), 1); let dgram = sender.process(maybe_ack, now).dgram(); diff --git a/third_party/rust/neqo-transport/src/connection/tests/resumption.rs b/third_party/rust/neqo-transport/src/connection/tests/resumption.rs index 50b469b7f88b..7b976712fe72 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/resumption.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/resumption.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{cell::RefCell, mem, rc::Rc, time::Duration}; +use std::{cell::RefCell, rc::Rc, time::Duration}; use neqo_common::{Datagram, Decoder, Role}; use neqo_crypto::AuthenticationStatus; @@ -249,19 +249,19 @@ fn two_tickets_on_timer() { // We need to wait for release_resumption_token_timer to expire. The timer will be // set to 3 * PTO let mut now = now() + 3 * client.pto(); - mem::drop(client.process_output(now)); + drop(client.process_output(now)); let mut recv_tokens = get_tokens(&mut client); assert_eq!(recv_tokens.len(), 1); let token1 = recv_tokens.pop().unwrap(); // Wai for anottheer 3 * PTO to get the nex okeen. now += 3 * client.pto(); - mem::drop(client.process_output(now)); + drop(client.process_output(now)); let mut recv_tokens = get_tokens(&mut client); assert_eq!(recv_tokens.len(), 1); let token2 = recv_tokens.pop().unwrap(); // Wait for 3 * PTO, but now there are no more tokens. now += 3 * client.pto(); - mem::drop(client.process_output(now)); + drop(client.process_output(now)); assert_eq!(get_tokens(&mut client).len(), 0); assert_ne!(token1.as_ref(), token2.as_ref()); @@ -343,7 +343,7 @@ fn resume_after_packet() { let token = exchange_ticket(&mut client, &mut server, now()); let mut client = default_client(); - mem::drop(client.process_output(now()).dgram().unwrap()); + drop(client.process_output(now()).dgram().unwrap()); assert_eq!( client.enable_resumption(now(), token).unwrap_err(), Error::ConnectionState diff --git a/third_party/rust/neqo-transport/src/connection/tests/stream.rs b/third_party/rust/neqo-transport/src/connection/tests/stream.rs index aa2b1003c928..2cb47b08c26c 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/stream.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/stream.rs @@ -4,28 +4,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{cmp::max, collections::HashMap, mem}; +use std::{cmp::max, collections::HashMap}; -use neqo_common::{event::Provider, qdebug}; +use neqo_common::{event::Provider as _, qdebug}; use test_fixture::now; use super::{ super::State, assert_error, connect, connect_force_idle, default_client, default_server, - maybe_authenticate, new_client, new_server, send_something, DEFAULT_STREAM_DATA, + maybe_authenticate, new_client, new_server, send_something, send_with_extra, + DEFAULT_STREAM_DATA, }; use crate::{ events::ConnectionEvent, + frame::{ + FRAME_TYPE_MAX_STREAM_DATA, FRAME_TYPE_RESET_STREAM, FRAME_TYPE_STOP_SENDING, + FRAME_TYPE_STREAM_CLIENT_BIDI, FRAME_TYPE_STREAM_DATA_BLOCKED, + }, + packet::PacketBuilder, recv_stream::RECV_BUFFER_SIZE, send_stream::{OrderGroup, SendStreamState, SEND_BUFFER_SIZE}, streams::{SendOrder, StreamOrder}, tparams::{self, TransportParameter}, - CloseReason, - // tracking::DEFAULT_ACK_PACKET_TOLERANCE, - Connection, - ConnectionParameters, - Error, - StreamId, - StreamType, + CloseReason, Connection, ConnectionParameters, Error, StreamId, StreamType, }; #[test] @@ -37,7 +37,7 @@ fn stream_create() { let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); assert!(maybe_authenticate(&mut client)); let out = client.process_output(now()); @@ -47,7 +47,7 @@ fn stream_create() { assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0); assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 4); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); // server now in State::Connected assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 3); assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 7); @@ -116,7 +116,7 @@ fn transfer() { assert!(fin3); } -// tests stream sendorder priorization +// tests stream sendorder prioritization fn sendorder_test(order_of_sendorder: &[Option]) { let mut client = default_client(); let mut server = default_server(); @@ -131,8 +131,8 @@ fn sendorder_test(order_of_sendorder: &[Option]) { streams.push(id); ordered.push((id, *sendorder)); // must be set before sendorder - client.streams.set_fairness(id, true).ok(); - client.streams.set_sendorder(id, *sendorder).ok(); + client.streams.set_fairness(id, true).unwrap(); + client.streams.set_sendorder(id, *sendorder).unwrap(); } // Write some data to all the streams for stream_id in streams { @@ -217,7 +217,7 @@ fn sendorder_4() { ]); } -// Tests stream sendorder priorization +// Tests stream sendorder prioritization // Converts Vecs of u64's into StreamIds fn fairness_test(source: S, number_iterates: usize, truncate_to: usize, result_array: &R) where @@ -306,7 +306,7 @@ fn ordergroup_7() { } #[test] -// Send fin even if a peer closes a reomte bidi send stream before sending any data. +// Send fin even if a peer closes a remote bidi send stream before sending any data. fn report_fin_when_stream_closed_wo_data() { // Note that the two servers in this test will get different anti-replay filters. // That's OK because we aren't testing anti-replay. @@ -318,11 +318,11 @@ fn report_fin_when_stream_closed_wo_data() { let stream_id = client.stream_create(StreamType::BiDi).unwrap(); client.stream_send(stream_id, &[0x00]).unwrap(); let out = client.process_output(now()); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); server.stream_close_send(stream_id).unwrap(); let out = server.process_output(now()); - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. }); assert!(client.events().any(stream_readable)); } @@ -512,7 +512,7 @@ fn do_not_accept_data_after_stop_sending() { let stream_id = client.stream_create(StreamType::BiDi).unwrap(); client.stream_send(stream_id, &[0x00]).unwrap(); let out = client.process_output(now()); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. }); assert!(server.events().any(stream_readable)); @@ -532,13 +532,91 @@ fn do_not_accept_data_after_stop_sending() { let out = server.process(out_second_data_frame.dgram(), now()); assert!(!server.events().any(stream_readable)); - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); assert_eq!( Err(Error::FinalSizeError), client.stream_send(stream_id, &[0x00]) ); } +struct Writer(Vec); + +impl crate::connection::test_internal::FrameWriter for Writer { + fn write_frames(&mut self, builder: &mut PacketBuilder) { + builder.write_varint_frame(&self.0); + } +} + +#[test] +/// Server sends a number of stream-related frames for a client-initiated stream that is not yet +/// created. This should cause the client to close the connection. +fn illegal_stream_related_frames() { + fn test_with_illegal_frame(frame: &[u64]) { + let mut client = default_client(); + let mut server = default_server(); + connect(&mut client, &mut server); + let dgram = send_with_extra(&mut server, Writer(frame.to_vec()), now()); + client.process_input(dgram, now()); + assert!(client.state().closed()); + } + + // 0 = Client-Initiated, Bidirectional; 2 = Client-Initiated, Unidirectional + for stream_id in [0, 2] { + for frame_type in [ + FRAME_TYPE_RESET_STREAM, + FRAME_TYPE_STOP_SENDING, + FRAME_TYPE_MAX_STREAM_DATA, + FRAME_TYPE_STREAM_DATA_BLOCKED, + FRAME_TYPE_STREAM_CLIENT_BIDI, + ] { + // The slice contains an extra 0 that is only needed for a RESET_STREAM frame. + // It's ignored for the other frame types as PADDING. + test_with_illegal_frame(&[frame_type, stream_id, 0, 0]); + } + } +} + +#[test] +/// Regression . +fn legal_out_of_order_frame_on_remote_initiated_closed_stream() { + const REQUEST: &[u8] = b"ping"; + let mut client = default_client(); + let mut server = default_server(); + connect(&mut client, &mut server); + + // Client sends request and closes stream. + let stream_id = client.stream_create(StreamType::BiDi).unwrap(); + _ = client.stream_send(stream_id, REQUEST).unwrap(); + client.stream_close_send(stream_id).unwrap(); + let dgram = client.process_output(now()).dgram(); + + // Server reads request and closes stream. + server.process_input(dgram.unwrap(), now()); + let mut buf = [0; REQUEST.len()]; + server.stream_recv(stream_id, &mut buf).unwrap(); + server.stream_close_send(stream_id).unwrap(); + let dgram = server.process_output(now()).dgram(); + client.process_input(dgram.unwrap(), now()); + + // Client ACKs server's close stream, thus server forgetting about stream. + let dgram = send_something(&mut client, now()); + let dgram = server.process(Some(dgram), now()).dgram(); + client.process_input(dgram.unwrap(), now()); + + // Deliver an out-of-order `FRAME_TYPE_MAX_STREAM_DATA` on forgotten stream. + let dgram = send_with_extra( + &mut client, + Writer(vec![FRAME_TYPE_MAX_STREAM_DATA, stream_id.as_u64(), 0, 0]), + now(), + ); + server.process_input(dgram, now()); + + assert!( + !server.state().closed(), + "expect server to ignore out-of-order frame on forgotten stream" + ); +} + #[test] // Server sends stop_sending, the client simultaneous sends reset. fn simultaneous_stop_sending_and_reset() { @@ -582,6 +660,92 @@ fn simultaneous_stop_sending_and_reset() { ); } +#[test] +/// Make a stream data or control frame arrive after the stream has been used and cleared. +fn late_stream_related_frames() { + fn late_stream_related_frame(frame_type: u64) { + let mut client = default_client(); + let mut server = default_server(); + connect(&mut client, &mut server); + + // Client creates a stream and sends some data. + let stream_id = client.stream_create(StreamType::BiDi).unwrap(); + client.stream_send(stream_id, &[0x00]).unwrap(); + let out = client.process_output(now()); + _ = server.process(out.dgram(), now()).dgram(); + + // Make the server generate a packet containing the test frame. + let before = server.stats().frame_tx; + match frame_type { + FRAME_TYPE_RESET_STREAM => { + server.stream_reset_send(stream_id, 0).unwrap(); + } + FRAME_TYPE_STOP_SENDING => { + server.stream_stop_sending(stream_id, 0).unwrap(); + } + FRAME_TYPE_STREAM_CLIENT_BIDI => { + server.stream_send(stream_id, &[0x00]).unwrap(); + server.stream_close_send(stream_id).unwrap(); + } + FRAME_TYPE_MAX_STREAM_DATA => { + server + .streams + .get_recv_stream_mut(stream_id) + .unwrap() + .set_stream_max_data(u32::MAX.into()); + } + FRAME_TYPE_STREAM_DATA_BLOCKED => { + let internal_stream = server.streams.get_send_stream_mut(stream_id).unwrap(); + if let SendStreamState::Ready { fc, .. } = internal_stream.state() { + fc.blocked(); + } else { + panic!("unexpected stream state"); + } + } + _ => panic!("unexpected frame type"), + } + let tester = server.process_output(now()).dgram(); + let after = server.stats().frame_tx; + match frame_type { + FRAME_TYPE_RESET_STREAM => { + assert_eq!(after.reset_stream, before.reset_stream + 1); + } + FRAME_TYPE_STOP_SENDING => { + assert_eq!(after.stop_sending, before.stop_sending + 1); + } + FRAME_TYPE_STREAM_CLIENT_BIDI => { + assert_eq!(after.stream, before.stream + 1); + } + FRAME_TYPE_MAX_STREAM_DATA => { + assert_eq!(after.max_stream_data, before.max_stream_data + 1); + } + FRAME_TYPE_STREAM_DATA_BLOCKED => { + assert_eq!(after.stream_data_blocked, before.stream_data_blocked + 1); + } + _ => panic!("unexpected frame type"), + } + + // Now clear the streams on the client, and then deliver the test frame. + client.streams.clear_streams(); + let (ss, rs) = client.streams.obtain_stream(stream_id).unwrap(); + assert!(ss.is_none() && rs.is_none()); + _ = client.process(tester, now()).dgram(); + + // Make sure this worked, i.e., the connection didn't close. + assert_eq!(*client.state(), State::Confirmed); + } + + for frame_type in [ + FRAME_TYPE_RESET_STREAM, + FRAME_TYPE_STOP_SENDING, + FRAME_TYPE_MAX_STREAM_DATA, + FRAME_TYPE_STREAM_DATA_BLOCKED, + FRAME_TYPE_STREAM_CLIENT_BIDI, + ] { + late_stream_related_frame(frame_type); + } +} + #[test] fn client_fin_reorder() { let mut client = default_client(); @@ -632,7 +796,7 @@ fn after_fin_is_read_conn_events_for_stream_should_be_removed() { let out = server.process_output(now()).dgram(); assert!(out.is_some()); - mem::drop(client.process(out, now())); + drop(client.process(out, now())); // read from the stream before checking connection events. let mut buf = vec![0; 4000]; @@ -657,9 +821,9 @@ fn after_stream_stop_sending_is_called_conn_events_for_stream_should_be_removed( let out = server.process_output(now()).dgram(); assert!(out.is_some()); - mem::drop(client.process(out, now())); + drop(client.process(out, now())); - // send stop seending. + // send stop sending. client .stream_stop_sending(id, Error::NoError.code()) .unwrap(); @@ -791,7 +955,7 @@ fn no_dupdata_readable_events() { let stream_id = client.stream_create(StreamType::BiDi).unwrap(); client.stream_send(stream_id, &[0x00]).unwrap(); let out = client.process_output(now()); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); // We have a data_readable event. let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. }); @@ -801,7 +965,7 @@ fn no_dupdata_readable_events() { // therefore there should not be a new DataReadable event. client.stream_send(stream_id, &[0x00]).unwrap(); let out_second_data_frame = client.process_output(now()); - mem::drop(server.process(out_second_data_frame.dgram(), now())); + drop(server.process(out_second_data_frame.dgram(), now())); assert!(!server.events().any(stream_readable)); // One more frame with a fin will not produce a new DataReadable event, because the @@ -809,7 +973,7 @@ fn no_dupdata_readable_events() { client.stream_send(stream_id, &[0x00]).unwrap(); client.stream_close_send(stream_id).unwrap(); let out_third_data_frame = client.process_output(now()); - mem::drop(server.process(out_third_data_frame.dgram(), now())); + drop(server.process(out_third_data_frame.dgram(), now())); assert!(!server.events().any(stream_readable)); } @@ -823,7 +987,7 @@ fn no_dupdata_readable_events_empty_last_frame() { let stream_id = client.stream_create(StreamType::BiDi).unwrap(); client.stream_send(stream_id, &[0x00]).unwrap(); let out = client.process_output(now()); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); // We have a data_readable event. let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. }); @@ -833,7 +997,7 @@ fn no_dupdata_readable_events_empty_last_frame() { // the previous stream data has not been read yet. client.stream_close_send(stream_id).unwrap(); let out_second_data_frame = client.process_output(now()); - mem::drop(server.process(out_second_data_frame.dgram(), now())); + drop(server.process(out_second_data_frame.dgram(), now())); assert!(!server.events().any(stream_readable)); } @@ -855,7 +1019,7 @@ fn change_flow_control(stream_type: StreamType, new_fc: u64) { // Send the stream to the client. let out = server.process_output(now()); - mem::drop(client.process(out.dgram(), now())); + drop(client.process(out.dgram(), now())); // change max_stream_data for stream_id. client.set_stream_max_data(stream_id, new_fc).unwrap(); @@ -877,7 +1041,7 @@ fn change_flow_control(stream_type: StreamType, new_fc: u64) { // Exchange packets so that client gets all data. let out4 = client.process(out3.dgram(), now()); let out5 = server.process(out4.dgram(), now()); - mem::drop(client.process(out5.dgram(), now())); + drop(client.process(out5.dgram(), now())); // read all data by client let mut buf = [0x0; 10000]; @@ -885,7 +1049,7 @@ fn change_flow_control(stream_type: StreamType, new_fc: u64) { assert_eq!(u64::try_from(read).unwrap(), max(RECV_BUFFER_START, new_fc)); let out4 = client.process_output(now()); - mem::drop(server.process(out4.dgram(), now())); + drop(server.process(out4.dgram(), now())); let written3 = server.stream_send(stream_id, &[0x0; 10000]).unwrap(); assert_eq!(u64::try_from(written3).unwrap(), new_fc); @@ -1117,7 +1281,7 @@ fn connect_w_different_limit(bidi_limit: u64, unidi_limit: u64) { let out = server.process(out.dgram(), now()); let out = client.process(out.dgram(), now()); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); assert!(maybe_authenticate(&mut client)); diff --git a/third_party/rust/neqo-transport/src/connection/tests/vn.rs b/third_party/rust/neqo-transport/src/connection/tests/vn.rs index 6a2f5a35829a..2c9d5a5a829e 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/vn.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/vn.rs @@ -4,9 +4,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{mem, time::Duration}; +use std::time::Duration; -use neqo_common::{event::Provider, Decoder, Encoder}; +use neqo_common::{event::Provider as _, Decoder, Encoder}; use test_fixture::{assertions, datagram, now}; use super::{ @@ -27,11 +27,11 @@ const INITIAL_PTO: Duration = Duration::from_millis(300); fn unknown_version() { let mut client = default_client(); // Start the handshake. - mem::drop(client.process_output(now()).dgram()); + drop(client.process_output(now()).dgram()); let mut unknown_version_packet = vec![0x80, 0x1a, 0x1a, 0x1a, 0x1a]; unknown_version_packet.resize(MIN_INITIAL_PACKET_SIZE, 0x0); - mem::drop(client.process(Some(datagram(unknown_version_packet)), now())); + drop(client.process(Some(datagram(unknown_version_packet)), now())); assert_eq!(1, client.stats().dropped_rx); } @@ -251,7 +251,7 @@ fn compatible_upgrade_large_initial() { assert_eq!(server.version(), Version::Version2); // Only handshake padding is "dropped". assert_eq!(client.stats().dropped_rx, 1); - assert_eq!(server.stats().dropped_rx, 1); + assert!(matches!(server.stats().dropped_rx, 1 | 2)); } /// A server that supports versions 1 and 2 might prefer version 1 and that's OK. diff --git a/third_party/rust/neqo-transport/src/connection/tests/zerortt.rs b/third_party/rust/neqo-transport/src/connection/tests/zerortt.rs index 1370e3f659d2..80929e5f725a 100644 --- a/third_party/rust/neqo-transport/src/connection/tests/zerortt.rs +++ b/third_party/rust/neqo-transport/src/connection/tests/zerortt.rs @@ -6,7 +6,7 @@ use std::{cell::RefCell, rc::Rc, time::Duration}; -use neqo_common::{event::Provider, qdebug}; +use neqo_common::{event::Provider as _, qdebug}; use neqo_crypto::{AllowZeroRtt, AntiReplay}; use test_fixture::{assertions, now}; diff --git a/third_party/rust/neqo-transport/src/crypto.rs b/third_party/rust/neqo-transport/src/crypto.rs index 9cf5a6389004..ee0547a549e6 100644 --- a/third_party/rust/neqo-transport/src/crypto.rs +++ b/third_party/rust/neqo-transport/src/crypto.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(clippy::module_name_repetitions)] + use std::{ cell::RefCell, cmp::{max, min}, @@ -30,6 +32,7 @@ use crate::{ recovery::RecoveryToken, recv_stream::RxStreamOrderer, send_stream::TxBuffer, + shuffle::find_sni, stats::FrameStats, tparams::{TpZeroRttChecker, TransportParameters, TransportParametersHandler}, tracking::PacketNumberSpace, @@ -109,7 +112,8 @@ impl Crypto { agent.disable_end_of_early_data()?; let extension = match version { Version::Version2 | Version::Version1 => 0x39, - Version::Draft29 | Version::Draft30 | Version::Draft31 | Version::Draft32 => 0xffa5, + #[cfg(feature = "draft-29")] + Version::Draft29 => 0xffa5, }; agent.extension_handler(extension, tphandler)?; Ok(Self { @@ -188,7 +192,7 @@ impl Crypto { data: Option<&[u8]>, ) -> Res<&HandshakeState> { let input = data.map(|d| { - qtrace!("Handshake record received {:0x?} ", d); + qtrace!("Handshake record received {d:0x?} "); let epoch = match space { PacketNumberSpace::Initial => TLS_EPOCH_INITIAL, PacketNumberSpace::Handshake => TLS_EPOCH_HANDSHAKE, @@ -209,7 +213,7 @@ impl Crypto { } Err(CryptoError::EchRetry(v)) => Err(Error::EchRetry(v)), Err(e) => { - qinfo!("Handshake failed {:?}", e); + qinfo!("Handshake failed {e:?}"); Err(self .tls .alert() @@ -263,7 +267,7 @@ impl Crypto { } fn install_handshake_keys(&mut self) -> Res { - qtrace!([self], "Attempt to install handshake keys"); + qtrace!("[{self}] Attempt to install handshake keys"); let Some(write_secret) = self.tls.write_secret(TLS_EPOCH_HANDSHAKE) else { // No keys is fine. return Ok(false); @@ -279,15 +283,15 @@ impl Crypto { .ok_or(Error::InternalError)?; self.states .set_handshake_keys(self.version, &write_secret, &read_secret, cipher)?; - qdebug!([self], "Handshake keys installed"); + qdebug!("[{self}] Handshake keys installed"); Ok(true) } fn maybe_install_application_write_key(&mut self, version: Version) -> Res<()> { - qtrace!([self], "Attempt to install application write key"); + qtrace!("[{self}] Attempt to install application write key"); if let Some(secret) = self.tls.write_secret(TLS_EPOCH_APPLICATION_DATA) { self.states.set_application_write_key(version, &secret)?; - qdebug!([self], "Application write key installed"); + qdebug!("[{self}] Application write key installed"); } Ok(()) } @@ -303,7 +307,7 @@ impl Crypto { .ok_or(Error::InternalError)?; self.states .set_application_read_key(version, &read_secret, expire_0rtt)?; - qdebug!([self], "application read keys installed"); + qdebug!("[{self}] application read keys installed"); Ok(()) } @@ -313,7 +317,7 @@ impl Crypto { if r.ct != TLS_CT_HANDSHAKE { return Err(Error::ProtocolViolation); } - qtrace!([self], "Adding CRYPTO data {:?}", r); + qtrace!("[{self}] Adding CRYPTO data {r:?}"); self.streams .send(PacketNumberSpace::from(r.epoch), &r.data)?; } @@ -323,11 +327,13 @@ impl Crypto { pub fn write_frame( &mut self, space: PacketNumberSpace, + sni_slicing: bool, builder: &mut PacketBuilder, tokens: &mut Vec, stats: &mut FrameStats, ) { - self.streams.write_frame(space, builder, tokens, stats); + self.streams + .write_frame(space, sni_slicing, builder, tokens, stats); } pub fn acked(&mut self, token: &CryptoRecoveryToken) { @@ -385,7 +391,7 @@ impl Crypto { ResumptionToken::new(enc.into(), t.expiration_time()) }) } else { - unreachable!("It is a server."); + unreachable!("It is a server"); } } @@ -393,7 +399,7 @@ impl Crypto { if let Agent::Client(c) = &self.tls { c.has_resumption_token() } else { - unreachable!("It is a server."); + unreachable!("It is a server"); } } } @@ -446,13 +452,7 @@ impl CryptoDxState { secret: &SymKey, cipher: Cipher, ) -> Res { - qdebug!( - "Making {:?} {} CryptoDxState, v={:?} cipher={}", - direction, - epoch, - version, - cipher, - ); + qdebug!("Making {direction:?} {epoch} CryptoDxState, v={version:?} cipher={cipher}",); let hplabel = String::from(version.label_prefix()) + "hp"; Ok(Self { version, @@ -473,7 +473,7 @@ impl CryptoDxState { label: &str, dcid: &[u8], ) -> Res { - qtrace!("new_initial {:?} {}", version, ConnectionIdRef::from(dcid)); + qtrace!("new_initial {version:?} {}", ConnectionIdRef::from(dcid)); let salt = version.initial_salt(); let cipher = TLS_AES_128_GCM_SHA256; let initial_secret = hkdf::extract( @@ -512,7 +512,7 @@ impl CryptoDxState { #[cfg(test)] OVERWRITE_INVOCATIONS.with(|v| { if let Some(i) = v.borrow_mut().take() { - neqo_common::qwarn!("Setting {:?} invocations to {}", self.direction, i); + log::warn!("Setting {:?} invocations to {}", self.direction, i); self.invocations = i; } }); @@ -580,11 +580,9 @@ impl CryptoDxState { Ok(()) } else if prev.used_pn.end > self.used_pn.start { qdebug!( - [self], - "Found packet with too new packet number {} > {}, compared to {}", + "[{self}] Found packet with too new packet number {} > {}, compared to {prev}", self.used_pn.start, prev.used_pn.end, - prev, ); Err(Error::PacketNumberOverlap) } else { @@ -599,9 +597,7 @@ impl CryptoDxState { pub fn used(&mut self, pn: PacketNumber) -> Res<()> { if pn < self.min_pn { qdebug!( - [self], - "Found packet with too old packet number: {} < {}", - pn, + "[{self}] Found packet with too old packet number: {pn} < {}", self.min_pn ); return Err(Error::PacketNumberOverlap); @@ -631,7 +627,7 @@ impl CryptoDxState { pub fn compute_mask(&self, sample: &[u8]) -> Res<[u8; HpKey::SAMPLE_SIZE]> { let mask = self.hpkey.mask(sample)?; - qtrace!([self], "HP sample={} mask={}", hex(sample), hex(mask)); + qtrace!("[{self}] HP sample={} mask={}", hex(sample), hex(mask)); Ok(mask) } @@ -643,9 +639,7 @@ impl CryptoDxState { pub fn encrypt(&mut self, pn: PacketNumber, hdr: &[u8], body: &[u8]) -> Res> { debug_assert_eq!(self.direction, CryptoDxDirection::Write); qtrace!( - [self], - "encrypt pn={} hdr={} body={}", - pn, + "[{self}] encrypt pn={pn} hdr={} body={}", hex(hdr), hex(body) ); @@ -665,7 +659,7 @@ impl CryptoDxState { let mut out = vec![0; size]; let res = self.aead.encrypt(pn, hdr, body, &mut out)?; - qtrace!([self], "encrypt ct={}", hex(res)); + qtrace!("[{self}] encrypt ct={}", hex(res)); debug_assert_eq!(pn, self.next_pn()); self.used(pn)?; Ok(res.to_vec()) @@ -679,9 +673,7 @@ impl CryptoDxState { pub fn decrypt(&mut self, pn: PacketNumber, hdr: &[u8], body: &[u8]) -> Res> { debug_assert_eq!(self.direction, CryptoDxDirection::Read); qtrace!( - [self], - "decrypt pn={} hdr={} body={}", - pn, + "[{self}] decrypt pn={pn} hdr={} body={}", hex(hdr), hex(body) ); @@ -728,8 +720,8 @@ pub struct CryptoState { impl Index for CryptoState { type Output = CryptoDxState; - fn index(&self, dir: CryptoDxDirection) -> &Self::Output { - match dir { + fn index(&self, index: CryptoDxDirection) -> &Self::Output { + match index { CryptoDxDirection::Read => &self.rx, CryptoDxDirection::Write => &self.tx, } @@ -737,8 +729,8 @@ impl Index for CryptoState { } impl IndexMut for CryptoState { - fn index_mut(&mut self, dir: CryptoDxDirection) -> &mut Self::Output { - match dir { + fn index_mut(&mut self, index: CryptoDxDirection) -> &mut Self::Output { + match index { CryptoDxDirection::Read => &mut self.rx, CryptoDxDirection::Write => &mut self.tx, } @@ -960,10 +952,7 @@ impl CryptoStates { for v in versions { qdebug!( - [self], - "Creating initial cipher state v={:?}, role={:?} dcid={}", - v, - role, + "[{self}] Creating initial cipher state v={v:?}, role={role:?} dcid={}", hex(dcid) ); @@ -973,8 +962,7 @@ impl CryptoStates { }; if let Some(prev) = self.initials.get(v) { qinfo!( - [self], - "Continue packet numbers for initial after retry (write is {:?})", + "[{self}] Continue packet numbers for initial after retry (write is {:?})", prev.rx.used_pn, ); initial.tx.continuation(&prev.tx)?; @@ -1022,7 +1010,7 @@ impl CryptoStates { secret: &SymKey, cipher: Cipher, ) -> Res<()> { - qtrace!([self], "install 0-RTT keys"); + qtrace!("[{self}] install 0-RTT keys"); self.zero_rtt = Some(CryptoDxState::new( version, dir, @@ -1047,7 +1035,7 @@ impl CryptoStates { } pub fn discard_0rtt_keys(&mut self) { - qtrace!([self], "discard 0-RTT keys"); + qtrace!("[{self}] discard 0-RTT keys"); assert!( self.app_read.is_none(), "Can't discard 0-RTT after setting application keys" @@ -1129,11 +1117,11 @@ impl CryptoStates { if self.maybe_update_write()? { Ok(()) } else { - qdebug!([self], "Write keys already updated"); + qdebug!("[{self}] Write keys already updated"); Err(Error::KeyUpdateBlocked) } } else { - qdebug!([self], "Waiting for ACK or blocked on read key timer"); + qdebug!("[{self}] Waiting for ACK or blocked on read key timer"); Err(Error::KeyUpdateBlocked) } } @@ -1147,7 +1135,7 @@ impl CryptoStates { let write = &self.app_write.as_ref().ok_or(Error::InternalError)?; let read = &self.app_read.as_ref().ok_or(Error::InternalError)?; if write.epoch() == read.epoch() { - qdebug!([self], "Update write keys to epoch={}", write.epoch() + 1); + qdebug!("[{self}] Update write keys to epoch={}", write.epoch() + 1); self.app_write = Some(write.next()?); Ok(true) } else { @@ -1161,7 +1149,7 @@ impl CryptoStates { pub fn auto_update(&mut self) -> Res<()> { if let Some(app_write) = self.app_write.as_ref() { if app_write.dx.should_update() { - qinfo!([self], "Initiating automatic key update"); + qinfo!("[{self}] Initiating automatic key update"); if !self.maybe_update_write()? { return Err(Error::KeysExhausted); } @@ -1181,7 +1169,7 @@ impl CryptoStates { /// we want to ensure that we can continue to receive any delayed /// packets that use the old keys. So we just set a timer. pub fn key_update_received(&mut self, expiration: Instant) -> Res<()> { - qtrace!([self], "Key update received"); + qtrace!("[{self}] Key update received"); // If we received a key update, then we assume that the peer has // acknowledged a packet we sent in this epoch. It's OK to do that // because they aren't allowed to update without first having received @@ -1211,10 +1199,10 @@ impl CryptoStates { // If enough time has passed, then install new keys and clear the timer. if now >= expiry { if self.has_0rtt_read() { - qtrace!([self], "Discarding 0-RTT keys"); + qtrace!("[{self}] Discarding 0-RTT keys"); self.zero_rtt = None; } else { - qtrace!([self], "Rotating read keys"); + qtrace!("[{self}] Rotating read keys"); mem::swap(&mut self.app_read, &mut self.app_read_next); self.app_read_next = Some(self.app_read.as_ref().ok_or(Error::InternalError)?.next()?); @@ -1239,7 +1227,7 @@ impl CryptoStates { pub fn check_pn_overlap(&mut self) -> Res<()> { // We only need to do the check while we are waiting for read keys to be updated. if self.read_update_time.is_some() { - qtrace!([self], "Checking for PN overlap"); + qtrace!("[{self}] Checking for PN overlap"); let next_dx = &mut self.app_read_next.as_mut().ok_or(Error::InternalError)?.dx; next_dx.continuation(&self.app_read.as_ref().ok_or(Error::InternalError)?.dx)?; } @@ -1489,17 +1477,21 @@ impl CryptoStreams { pub fn write_frame( &mut self, space: PacketNumberSpace, + sni_slicing: bool, builder: &mut PacketBuilder, tokens: &mut Vec, stats: &mut FrameStats, ) { - let cs = self.get_mut(space).unwrap(); - if let Some((offset, data)) = cs.tx.next_bytes() { + fn write_chunk( + offset: u64, + data: &[u8], + builder: &mut PacketBuilder, + ) -> Option<(u64, usize)> { let mut header_len = 1 + Encoder::varint_len(offset) + 1; // Don't bother if there isn't room for the header and some data. if builder.remaining() < header_len + 1 { - return; + return None; } // Calculate length of data based on the minimum of: // - available data @@ -1512,16 +1504,38 @@ impl CryptoStreams { builder.encode_varint(crate::frame::FRAME_TYPE_CRYPTO); builder.encode_varint(offset); builder.encode_vvec(&data[..length]); + Some((offset, length)) + } - cs.tx.mark_as_sent(offset, length); - - qdebug!("CRYPTO for {} offset={}, len={}", space, offset, length); - tokens.push(RecoveryToken::Crypto(CryptoRecoveryToken { - space, - offset, - length, - })); - stats.crypto += 1; + let cs = self.get_mut(space).unwrap(); + if let Some((offset, data)) = cs.tx.next_bytes() { + let written = if sni_slicing && offset == 0 { + if let Some(sni) = find_sni(data) { + // Cut the crypto data in two at the midpoint of the SNI and swap the chunks. + let mid = sni.start + (sni.end - sni.start) / 2; + let (left, right) = data.split_at(mid); + [ + write_chunk(offset + mid as u64, right, builder), + write_chunk(offset, left, builder), + ] + } else { + // No SNI found, write the entire data. + [write_chunk(offset, data, builder), None] + } + } else { + // Not at the start of the crypto stream, write the entire data. + [write_chunk(offset, data, builder), None] + }; + for (offset, length) in written.into_iter().flatten() { + cs.tx.mark_as_sent(offset, length); + qdebug!("CRYPTO for {space} offset={offset}, len={length}"); + tokens.push(RecoveryToken::Crypto(CryptoRecoveryToken { + space, + offset, + length, + })); + stats.crypto += 1; + } } } } diff --git a/third_party/rust/neqo-transport/src/ecn.rs b/third_party/rust/neqo-transport/src/ecn.rs index 97d68fb6c1c3..f23cb4e9dd19 100644 --- a/third_party/rust/neqo-transport/src/ecn.rs +++ b/third_party/rust/neqo-transport/src/ecn.rs @@ -6,7 +6,7 @@ use std::ops::{AddAssign, Deref, DerefMut, Sub}; -use enum_map::EnumMap; +use enum_map::{Enum, EnumMap}; use neqo_common::{qdebug, qinfo, qwarn, IpTosEcn}; use crate::{ @@ -16,18 +16,18 @@ use crate::{ }; /// The number of packets to use for testing a path for ECN capability. -pub const ECN_TEST_COUNT: usize = 10; +pub(crate) const TEST_COUNT: usize = 10; /// The number of packets to use for testing a path for ECN capability when exchanging -/// Initials during the handshake. This is a lower number than [`ECN_TEST_COUNT`] to avoid -/// unnecessarily delaying the handshake; we would otherwise double the PTO [`ECN_TEST_COUNT`] +/// Initials during the handshake. This is a lower number than [`TEST_COUNT`] to avoid +/// unnecessarily delaying the handshake; we would otherwise double the PTO [`TEST_COUNT`] /// times. -const ECN_TEST_COUNT_INITIAL_PHASE: usize = 3; +const TEST_COUNT_INITIAL_PHASE: usize = 3; /// The state information related to testing a path for ECN capability. /// See RFC9000, Appendix A.4. #[derive(Debug, PartialEq, Clone, Copy)] -enum EcnValidationState { +enum ValidationState { /// The path is currently being tested for ECN capability, with the number of probes sent so /// far on the path during the ECN validation. Testing { @@ -37,12 +37,12 @@ enum EcnValidationState { /// The validation test has concluded but the path's ECN capability is not yet known. Unknown, /// The path is known to **not** be ECN capable. - Failed, + Failed(ValidationError), /// The path is known to be ECN capable. Capable, } -impl Default for EcnValidationState { +impl Default for ValidationState { fn default() -> Self { Self::Testing { probes_sent: 0, @@ -51,26 +51,28 @@ impl Default for EcnValidationState { } } -impl EcnValidationState { +impl ValidationState { fn set(&mut self, new: Self, stats: &mut Stats) { let old = std::mem::replace(self, new); match old { Self::Testing { .. } | Self::Unknown => {} - Self::Failed => debug_assert!(false, "Failed is a terminal state"), - Self::Capable => stats.ecn_paths_capable -= 1, + Self::Failed(_) => debug_assert!(false, "Failed is a terminal state"), + Self::Capable => stats.ecn_path_validation[ValidationOutcome::Capable] -= 1, } match new { Self::Testing { .. } | Self::Unknown => {} - Self::Failed => stats.ecn_paths_not_capable += 1, - Self::Capable => stats.ecn_paths_capable += 1, + Self::Failed(error) => { + stats.ecn_path_validation[ValidationOutcome::NotCapable(error)] += 1; + } + Self::Capable => stats.ecn_path_validation[ValidationOutcome::Capable] += 1, } } } /// The counts for different ECN marks. /// -/// Note: [`EcnCount`] is used both for outgoing UDP datagrams, returned by +/// Note: [`Count`] is used both for outgoing UDP datagrams, returned by /// remote through QUIC ACKs and for incoming UDP datagrams, read from IP TOS /// header. In the former case, given that QUIC ACKs only carry /// [`IpTosEcn::Ect0`], [`IpTosEcn::Ect1`] and [`IpTosEcn::Ce`], but never @@ -78,9 +80,9 @@ impl EcnValidationState { /// /// See also . #[derive(PartialEq, Eq, Debug, Clone, Copy, Default)] -pub struct EcnCount(EnumMap); +pub struct Count(EnumMap); -impl Deref for EcnCount { +impl Deref for Count { type Target = EnumMap; fn deref(&self) -> &Self::Target { @@ -88,105 +90,137 @@ impl Deref for EcnCount { } } -impl DerefMut for EcnCount { +impl DerefMut for Count { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl EcnCount { +impl Count { + #[must_use] pub const fn new(not_ect: u64, ect0: u64, ect1: u64, ce: u64) -> Self { // Yes, the enum array order is different from the argument order. Self(EnumMap::from_array([not_ect, ect1, ect0, ce])) } /// Whether any of the ECN counts are non-zero. + #[must_use] pub fn is_some(&self) -> bool { self[IpTosEcn::Ect0] > 0 || self[IpTosEcn::Ect1] > 0 || self[IpTosEcn::Ce] > 0 } } -impl Sub for EcnCount { +impl Sub for Count { type Output = Self; /// Subtract the ECN counts in `other` from `self`. - fn sub(self, other: Self) -> Self { + fn sub(self, rhs: Self) -> Self { let mut diff = Self::default(); for (ecn, count) in &mut *diff { - *count = self[ecn].saturating_sub(other[ecn]); + *count = self[ecn].saturating_sub(rhs[ecn]); } diff } } -impl AddAssign for EcnCount { - fn add_assign(&mut self, ecn: IpTosEcn) { - self[ecn] += 1; +impl AddAssign for Count { + fn add_assign(&mut self, rhs: IpTosEcn) { + self[rhs] += 1; } } +#[derive(PartialEq, Eq, Debug, Clone, Copy, Default)] +pub struct ValidationCount(EnumMap); + +impl Deref for ValidationCount { + type Target = EnumMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for ValidationCount { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[derive(Debug, Clone, Copy, Enum, PartialEq, Eq)] +pub enum ValidationError { + BlackHole, + Bleaching, + ReceivedUnsentECT1, +} + +#[derive(Debug, Clone, Copy, Enum, PartialEq, Eq)] +pub enum ValidationOutcome { + Capable, + NotCapable(ValidationError), +} + #[derive(Debug, Default)] -pub struct EcnInfo { +pub(crate) struct Info { /// The current state of ECN validation on this path. - state: EcnValidationState, + state: ValidationState, /// The largest ACK seen so far. largest_acked: PacketNumber, /// The ECN counts from the last ACK frame that increased `largest_acked`. - baseline: EcnCount, + baseline: Count, } -impl EcnInfo { +impl Info { /// Set the baseline (= the ECN counts from the last ACK Frame). - pub fn set_baseline(&mut self, baseline: EcnCount) { + pub(crate) fn set_baseline(&mut self, baseline: Count) { self.baseline = baseline; } /// Expose the current baseline. - pub const fn baseline(&self) -> EcnCount { + pub(crate) const fn baseline(&self) -> Count { self.baseline } /// Count the number of packets sent out on this path during ECN validation. - /// Exit ECN validation if the number of packets sent exceeds `ECN_TEST_COUNT`. + /// Exit ECN validation if the number of packets sent exceeds `TEST_COUNT`. /// We do not implement the part of the RFC that says to exit ECN validation if the time since /// the start of ECN validation exceeds 3 * PTO, since this seems to happen much too quickly. - pub fn on_packet_sent(&mut self, stats: &mut Stats) { - if let EcnValidationState::Testing { probes_sent, .. } = &mut self.state { + pub(crate) fn on_packet_sent(&mut self, stats: &mut Stats) { + if let ValidationState::Testing { probes_sent, .. } = &mut self.state { *probes_sent += 1; - qdebug!("ECN probing: sent {} probes", probes_sent); - if *probes_sent == ECN_TEST_COUNT { - qdebug!("ECN probing concluded with {} probes sent", probes_sent); - self.state.set(EcnValidationState::Unknown, stats); + qdebug!("ECN probing: sent {probes_sent} probes"); + if *probes_sent == TEST_COUNT { + qdebug!("ECN probing concluded with {probes_sent} probes sent"); + self.state.set(ValidationState::Unknown, stats); } } } /// Disable ECN. - pub fn disable_ecn(&mut self, stats: &mut Stats) { - self.state.set(EcnValidationState::Failed, stats); + pub(crate) fn disable_ecn(&mut self, stats: &mut Stats, reason: ValidationError) { + self.state.set(ValidationState::Failed(reason), stats); } /// Process ECN counts from an ACK frame. /// /// Returns whether ECN counts contain new valid ECN CE marks. - pub fn on_packets_acked( + pub(crate) fn on_packets_acked( &mut self, acked_packets: &[SentPacket], - ack_ecn: Option, + ack_ecn: Option, stats: &mut Stats, ) -> bool { let prev_baseline = self.baseline; self.validate_ack_ecn_and_update(acked_packets, ack_ecn, stats); - matches!(self.state, EcnValidationState::Capable) + matches!(self.state, ValidationState::Capable) && (self.baseline - prev_baseline)[IpTosEcn::Ce] > 0 } - pub fn on_packets_lost(&mut self, lost_packets: &[SentPacket], stats: &mut Stats) { - if let EcnValidationState::Testing { + pub(crate) fn on_packets_lost(&mut self, lost_packets: &[SentPacket], stats: &mut Stats) { + if let ValidationState::Testing { probes_sent, initial_probes_lost: probes_lost, } = &mut self.state @@ -197,21 +231,20 @@ impl EcnInfo { .count(); // If we have lost all initial probes a bunch of times, we can conclude that the path // is not ECN capable and likely drops all ECN marked packets. - if probes_sent == probes_lost && *probes_lost == ECN_TEST_COUNT_INITIAL_PHASE { + if probes_sent == probes_lost && *probes_lost == TEST_COUNT_INITIAL_PHASE { qdebug!( - "ECN validation failed, all {} initial marked packets were lost", - probes_lost + "ECN validation failed, all {probes_lost} initial marked packets were lost" ); - self.disable_ecn(stats); + self.disable_ecn(stats, ValidationError::BlackHole); } } } /// After the ECN validation test has ended, check if the path is ECN capable. - pub fn validate_ack_ecn_and_update( + pub(crate) fn validate_ack_ecn_and_update( &mut self, acked_packets: &[SentPacket], - ack_ecn: Option, + ack_ecn: Option, stats: &mut Stats, ) { // RFC 9000, Appendix A.4: @@ -220,8 +253,8 @@ impl EcnInfo { // > (see Section 13.4.2.1) causes the ECN state for the path to become "capable", unless // > no marked packet has been acknowledged. match self.state { - EcnValidationState::Testing { .. } | EcnValidationState::Failed => return, - EcnValidationState::Unknown | EcnValidationState::Capable => {} + ValidationState::Testing { .. } | ValidationState::Failed(_) => return, + ValidationState::Unknown | ValidationState::Capable => {} } // RFC 9000, Section 13.4.2.1: @@ -245,7 +278,7 @@ impl EcnInfo { // > corresponding ECN counts are not present in the ACK frame. let Some(ack_ecn) = ack_ecn else { qwarn!("ECN validation failed, no ECN counts in ACK frame"); - self.disable_ecn(stats); + self.disable_ecn(stats, ValidationError::Bleaching); return; }; @@ -262,24 +295,22 @@ impl EcnInfo { .unwrap(); if newly_acked_sent_with_ect0 == 0 { qwarn!("ECN validation failed, no ECT(0) packets were newly acked"); - self.disable_ecn(stats); + self.disable_ecn(stats, ValidationError::Bleaching); return; } let ecn_diff = ack_ecn - self.baseline; let sum_inc = ecn_diff[IpTosEcn::Ect0] + ecn_diff[IpTosEcn::Ce]; if sum_inc < newly_acked_sent_with_ect0 { qwarn!( - "ECN validation failed, ACK counted {} new marks, but {} of newly acked packets were sent with ECT(0)", - sum_inc, - newly_acked_sent_with_ect0 + "ECN validation failed, ACK counted {sum_inc} new marks, but {newly_acked_sent_with_ect0} of newly acked packets were sent with ECT(0)" ); - self.disable_ecn(stats); + self.disable_ecn(stats, ValidationError::Bleaching); } else if ecn_diff[IpTosEcn::Ect1] > 0 { qwarn!("ECN validation failed, ACK counted ECT(1) marks that were never sent"); - self.disable_ecn(stats); - } else if self.state != EcnValidationState::Capable { + self.disable_ecn(stats, ValidationError::ReceivedUnsentECT1); + } else if self.state != ValidationState::Capable { qinfo!("ECN validation succeeded, path is capable"); - self.state.set(EcnValidationState::Capable, stats); + self.state.set(ValidationState::Capable, stats); } self.baseline = ack_ecn; stats.ecn_tx = ack_ecn; @@ -287,10 +318,10 @@ impl EcnInfo { } /// The ECN mark to use for packets sent on this path. - pub const fn ecn_mark(&self) -> IpTosEcn { + pub(crate) const fn ecn_mark(&self) -> IpTosEcn { match self.state { - EcnValidationState::Testing { .. } | EcnValidationState::Capable => IpTosEcn::Ect0, - EcnValidationState::Failed | EcnValidationState::Unknown => IpTosEcn::NotEct, + ValidationState::Testing { .. } | ValidationState::Capable => IpTosEcn::Ect0, + ValidationState::Failed(_) | ValidationState::Unknown => IpTosEcn::NotEct, } } } diff --git a/third_party/rust/neqo-transport/src/events.rs b/third_party/rust/neqo-transport/src/events.rs index 68ef0d679858..ca7f57bf5dad 100644 --- a/third_party/rust/neqo-transport/src/events.rs +++ b/third_party/rust/neqo-transport/src/events.rs @@ -254,7 +254,7 @@ impl EventProvider for ConnectionEvents { #[cfg(test)] mod tests { - use neqo_common::event::Provider; + use neqo_common::event::Provider as _; use crate::{CloseReason, ConnectionEvent, ConnectionEvents, Error, State, StreamId}; diff --git a/third_party/rust/neqo-transport/src/fc.rs b/third_party/rust/neqo-transport/src/fc.rs index acc4d6582d65..b670350682c4 100644 --- a/third_party/rust/neqo-transport/src/fc.rs +++ b/third_party/rust/neqo-transport/src/fc.rs @@ -68,13 +68,11 @@ where /// control if the change was an increase and `None` otherwise. pub fn update(&mut self, limit: u64) -> Option { debug_assert!(limit < u64::MAX); - if limit > self.limit { + (limit > self.limit).then(|| { self.limit = limit; self.blocked_frame = false; - Some(self.available()) - } else { - None - } + self.available() + }) } /// Consume flow control. @@ -326,9 +324,8 @@ impl ReceiverFlowControl<()> { pub fn consume(&mut self, count: u64) -> Res<()> { if self.consumed + count > self.max_allowed { qtrace!( - "Session RX window exceeded: consumed:{} new:{} limit:{}", + "Session RX window exceeded: consumed:{} new:{count} limit:{}", self.consumed, - count, self.max_allowed ); return Err(Error::FlowControlError); @@ -383,7 +380,7 @@ impl ReceiverFlowControl { } if consumed > self.max_allowed { - qtrace!("Stream RX window exceeded: {}", consumed); + qtrace!("Stream RX window exceeded: {consumed}"); return Err(Error::FlowControlError); } let new_consumed = consumed - self.consumed; @@ -502,8 +499,8 @@ impl RemoteStreamLimits { impl Index for RemoteStreamLimits { type Output = RemoteStreamLimit; - fn index(&self, idx: StreamType) -> &Self::Output { - match idx { + fn index(&self, index: StreamType) -> &Self::Output { + match index { StreamType::BiDi => &self.bidirectional, StreamType::UniDi => &self.unidirectional, } @@ -511,8 +508,8 @@ impl Index for RemoteStreamLimits { } impl IndexMut for RemoteStreamLimits { - fn index_mut(&mut self, idx: StreamType) -> &mut Self::Output { - match idx { + fn index_mut(&mut self, index: StreamType) -> &mut Self::Output { + match index { StreamType::BiDi => &mut self.bidirectional, StreamType::UniDi => &mut self.unidirectional, } @@ -557,8 +554,8 @@ impl LocalStreamLimits { impl Index for LocalStreamLimits { type Output = SenderFlowControl; - fn index(&self, idx: StreamType) -> &Self::Output { - match idx { + fn index(&self, index: StreamType) -> &Self::Output { + match index { StreamType::BiDi => &self.bidirectional, StreamType::UniDi => &self.unidirectional, } @@ -566,8 +563,8 @@ impl Index for LocalStreamLimits { } impl IndexMut for LocalStreamLimits { - fn index_mut(&mut self, idx: StreamType) -> &mut Self::Output { - match idx { + fn index_mut(&mut self, index: StreamType) -> &mut Self::Output { + match index { StreamType::BiDi => &mut self.bidirectional, StreamType::UniDi => &mut self.unidirectional, } diff --git a/third_party/rust/neqo-transport/src/frame.rs b/third_party/rust/neqo-transport/src/frame.rs index af933a345560..1a54277c08a3 100644 --- a/third_party/rust/neqo-transport/src/frame.rs +++ b/third_party/rust/neqo-transport/src/frame.rs @@ -12,7 +12,7 @@ use neqo_common::{qtrace, Decoder, Encoder}; use crate::{ cid::MAX_CONNECTION_ID_LEN, - ecn::EcnCount, + ecn, packet::PacketType, stream_id::{StreamId, StreamType}, AppError, CloseReason, Error, Res, TransportError, @@ -30,6 +30,8 @@ pub const FRAME_TYPE_STOP_SENDING: FrameType = 0x5; pub const FRAME_TYPE_CRYPTO: FrameType = 0x6; pub const FRAME_TYPE_NEW_TOKEN: FrameType = 0x7; const FRAME_TYPE_STREAM: FrameType = 0x8; +#[cfg(test)] +pub const FRAME_TYPE_STREAM_CLIENT_BIDI: FrameType = FRAME_TYPE_STREAM; const FRAME_TYPE_STREAM_MAX: FrameType = 0xf; pub const FRAME_TYPE_MAX_DATA: FrameType = 0x10; pub const FRAME_TYPE_MAX_STREAM_DATA: FrameType = 0x11; @@ -117,7 +119,7 @@ pub enum Frame<'a> { ack_delay: u64, first_ack_range: u64, ack_ranges: Vec, - ecn_count: Option, + ecn_count: Option, }, ResetStream { stream_id: StreamId, @@ -368,7 +370,7 @@ impl<'a> Frame<'a> { pub fn dump(&self) -> String { match self { Self::Crypto { offset, data } => { - format!("Crypto {{ offset: {}, len: {} }}", offset, data.len()) + format!("Crypto {{ offset: {offset}, len: {} }}", data.len()) } Self::Stream { stream_id, @@ -377,12 +379,10 @@ impl<'a> Frame<'a> { data, fin, } => format!( - "Stream {{ stream_id: {}, offset: {}, len: {}{}, fin: {} }}", + "Stream {{ stream_id: {}, offset: {offset}, len: {}{}, fin: {fin} }}", stream_id.as_u64(), - offset, if *fill { ">>" } else { "" }, data.len(), - fin, ), Self::Padding(length) => format!("Padding {{ len: {length} }}"), Self::Datagram { data, .. } => format!("Datagram {{ len: {} }}", data.len()), @@ -449,11 +449,11 @@ impl<'a> Frame<'a> { } // Now check for the values for ACK_ECN. - let ecn_count = if ecn { - Some(EcnCount::new(0, dv(dec)?, dv(dec)?, dv(dec)?)) - } else { - None - }; + let ecn_count = ecn + .then(|| -> Res { + Ok(ecn::Count::new(0, dv(dec)?, dv(dec)?, dv(dec)?)) + }) + .transpose()?; Ok(Frame::Ack { largest_acknowledged: la, @@ -629,7 +629,7 @@ impl<'a> Frame<'a> { return Err(Error::FrameEncodingError); } let delay = dv(dec)?; - let ignore_order = match d(dec.decode_uint(1))? { + let ignore_order = match d(dec.decode_uint::())? { 0 => false, 1 => true, _ => return Err(Error::FrameEncodingError), @@ -663,7 +663,7 @@ mod tests { use crate::{ cid::MAX_CONNECTION_ID_LEN, - ecn::EcnCount, + ecn::Count, frame::{AckRange, Frame, FRAME_TYPE_ACK}, CloseError, Error, StreamId, StreamType, }; @@ -708,7 +708,7 @@ mod tests { assert_eq!(Frame::decode(&mut dec).unwrap_err(), Error::NoMoreData); // Try to parse ACK_ECN with ECN values - let ecn_count = Some(EcnCount::new(0, 1, 2, 3)); + let ecn_count = Some(Count::new(0, 1, 2, 3)); let fe = Frame::Ack { largest_acknowledged: 0x1234, ack_delay: 0x1235, diff --git a/third_party/rust/neqo-transport/src/lib.rs b/third_party/rust/neqo-transport/src/lib.rs index 2507da988a53..d157f0430070 100644 --- a/third_party/rust/neqo-transport/src/lib.rs +++ b/third_party/rust/neqo-transport/src/lib.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(clippy::module_name_repetitions)] // This lint doesn't work here. - use neqo_common::qwarn; use neqo_crypto::Error as CryptoError; @@ -15,7 +13,7 @@ mod cc; mod cid; mod connection; mod crypto; -mod ecn; +pub mod ecn; mod events; mod fc; #[cfg(fuzzing)] @@ -46,6 +44,7 @@ pub mod send_stream; mod send_stream; mod sender; pub mod server; +mod shuffle; mod stats; pub mod stream_id; pub mod streams; @@ -70,6 +69,7 @@ pub use self::{ quic_datagrams::DatagramTracking, recv_stream::{RecvStreamStats, RECV_BUFFER_SIZE}, send_stream::{SendStreamStats, SEND_BUFFER_SIZE}, + shuffle::find_sni, stats::Stats, stream_id::{StreamId, StreamType}, version::Version, @@ -84,7 +84,7 @@ const ERROR_AEAD_LIMIT_REACHED: TransportError = 15; pub enum Error { NoError, // Each time this error is returned a different parameter is supplied. - // This will be used to distinguish each occurance of this error. + // This will be used to distinguish each occurrence of this error. InternalError, ConnectionRefused, FlowControlError, @@ -177,7 +177,7 @@ impl Error { impl From for Error { fn from(err: CryptoError) -> Self { - qwarn!("Crypto operation failed {:?}", err); + qwarn!("Crypto operation failed {err:?}"); match err { CryptoError::EchRetry(config) => Self::EchRetry(config), _ => Self::CryptoError(err), @@ -250,4 +250,4 @@ impl From for CloseReason { } } -pub type Res = std::result::Result; +pub type Res = Result; diff --git a/third_party/rust/neqo-transport/src/pace.rs b/third_party/rust/neqo-transport/src/pace.rs index 642a656da251..3670fe1d6ff2 100644 --- a/third_party/rust/neqo-transport/src/pace.rs +++ b/third_party/rust/neqo-transport/src/pace.rs @@ -76,7 +76,7 @@ impl Pacer { /// the current time is). pub fn next(&self, rtt: Duration, cwnd: usize) -> Instant { if self.c >= self.p { - qtrace!([self], "next {cwnd}/{rtt:?} no wait = {:?}", self.t); + qtrace!("[{self}] next {cwnd}/{rtt:?} no wait = {:?}", self.t); return self.t; } @@ -89,12 +89,12 @@ impl Pacer { // If the increment is below the timer granularity, send immediately. if w < GRANULARITY { - qtrace!([self], "next {cwnd}/{rtt:?} below granularity ({w:?})",); + qtrace!("[{self}] next {cwnd}/{rtt:?} below granularity ({w:?})",); return self.t; } let nxt = self.t + w; - qtrace!([self], "next {cwnd}/{rtt:?} wait {w:?} = {nxt:?}"); + qtrace!("[{self}] next {cwnd}/{rtt:?} wait {w:?} = {nxt:?}"); nxt } @@ -108,7 +108,7 @@ impl Pacer { return; } - qtrace!([self], "spend {} over {}, {:?}", count, cwnd, rtt); + qtrace!("[{self}] spend {count} over {cwnd}, {rtt:?}"); // Increase the capacity by: // `(now - self.t) * PACER_SPEEDUP * cwnd / rtt` // That is, the elapsed fraction of the RTT times rate that data is added. @@ -188,7 +188,7 @@ mod tests { assert_eq!( p.next(SHORT_RTT, CWND), n, - "Expect packet to be sent immediately, instead of being paced below timer granularity." + "Expect packet to be sent immediately, instead of being paced below timer granularity" ); } } diff --git a/third_party/rust/neqo-transport/src/packet/mod.rs b/third_party/rust/neqo-transport/src/packet/mod.rs index 8f7ace63f1a2..0c11a4a86961 100644 --- a/third_party/rust/neqo-transport/src/packet/mod.rs +++ b/third_party/rust/neqo-transport/src/packet/mod.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(clippy::module_name_repetitions)] + // Encoding and decoding packets off the wire. use std::{ cmp::min, @@ -202,7 +204,8 @@ impl PacketBuilder { + scid.as_ref().map_or(0, |d| d.as_ref().len()) < limit - encoder.len() { - encoder.encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC | pt.to_byte(version) << 4); + encoder + .encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC | (pt.to_byte(version) << 4)); encoder.encode_uint(4, version.wire_version()); encoder.encode_vec(1, dcid.take().as_ref().map_or(&[], AsRef::as_ref)); encoder.encode_vec(1, scid.take().as_ref().map_or(&[], AsRef::as_ref)); @@ -610,7 +613,7 @@ impl<'a> PublicPacket<'a> { #[allow(clippy::similar_names)] pub fn decode(data: &'a [u8], dcid_decoder: &dyn ConnectionIdDecoder) -> Res<(Self, &'a [u8])> { let mut decoder = Decoder::new(data); - let first = Self::opt(decoder.decode_byte())?; + let first = Self::opt(decoder.decode_uint::())?; if first & 0x80 == PACKET_BIT_SHORT { // Conveniently, this also guarantees that there is enough space @@ -638,7 +641,7 @@ impl<'a> PublicPacket<'a> { } // Generic long header. - let version = WireVersion::try_from(Self::opt(decoder.decode_uint(4))?)?; + let version = Self::opt(decoder.decode_uint())?; let dcid = ConnectionIdRef::from(Self::opt(decoder.decode_vec(1))?); let scid = ConnectionIdRef::from(Self::opt(decoder.decode_vec(1))?); @@ -856,7 +859,7 @@ impl<'a> PublicPacket<'a> { // fail is if the cryptographic module is bad or the packet is // too small (which is public information). let (key_phase, pn, header, body) = self.decrypt_header(rx)?; - qtrace!([rx], "decoded header: {:?}", header); + qtrace!("[{rx}] decoded header: {header:?}"); let Some(rx) = crypto.rx(version, cspace, key_phase) else { return Err(Error::DecryptError); }; @@ -877,7 +880,7 @@ impl<'a> PublicPacket<'a> { } else if crypto.rx_pending(cspace) { Err(Error::KeysPending(cspace)) } else { - qtrace!("keys for {:?} already discarded", cspace); + qtrace!("keys for {cspace:?} already discarded"); Err(Error::KeysDiscarded(cspace)) } } @@ -893,7 +896,7 @@ impl<'a> PublicPacket<'a> { let mut decoder = Decoder::new(&self.data[self.header_len..]); let mut res = Vec::new(); while decoder.remaining() > 0 { - let version = WireVersion::try_from(Self::opt(decoder.decode_uint(4))?)?; + let version = Self::opt(decoder.decode_uint::())?; res.push(version); } Ok(res) @@ -1278,24 +1281,6 @@ mod tests { 0x8a, 0xa4, 0x57, 0x5e, 0x1e, 0x49, ]; - const SAMPLE_RETRY_30: &[u8] = &[ - 0xff, 0xff, 0x00, 0x00, 0x1e, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2d, 0x3e, 0x04, 0x5d, 0x6d, 0x39, 0x20, 0x67, 0x89, 0x94, - 0x37, 0x10, 0x8c, 0xe0, 0x0a, 0x61, - ]; - - const SAMPLE_RETRY_31: &[u8] = &[ - 0xff, 0xff, 0x00, 0x00, 0x1f, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xc7, 0x0c, 0xe5, 0xde, 0x43, 0x0b, 0x4b, 0xdb, 0x7d, 0xf1, - 0xa3, 0x83, 0x3a, 0x75, 0xf9, 0x86, - ]; - - const SAMPLE_RETRY_32: &[u8] = &[ - 0xff, 0xff, 0x00, 0x00, 0x20, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x59, 0x75, 0x65, 0x19, 0xdd, 0x6c, 0xc8, 0x5b, 0xd9, 0x0e, - 0x33, 0xa9, 0x34, 0xd2, 0xff, 0x85, - ]; - const RETRY_TOKEN: &[u8] = b"token"; fn build_retry_single(version: Version, sample_retry: &[u8]) { @@ -1337,21 +1322,6 @@ mod tests { build_retry_single(Version::Draft29, SAMPLE_RETRY_29); } - #[test] - fn build_retry_30() { - build_retry_single(Version::Draft30, SAMPLE_RETRY_30); - } - - #[test] - fn build_retry_31() { - build_retry_single(Version::Draft31, SAMPLE_RETRY_31); - } - - #[test] - fn build_retry_32() { - build_retry_single(Version::Draft32, SAMPLE_RETRY_32); - } - #[test] fn build_retry_multiple() { // Run the build_retry test a few times. @@ -1361,9 +1331,6 @@ mod tests { build_retry_v2(); build_retry_v1(); build_retry_29(); - build_retry_30(); - build_retry_31(); - build_retry_32(); } } @@ -1394,21 +1361,6 @@ mod tests { decode_retry(Version::Draft29, SAMPLE_RETRY_29); } - #[test] - fn decode_retry_30() { - decode_retry(Version::Draft30, SAMPLE_RETRY_30); - } - - #[test] - fn decode_retry_31() { - decode_retry(Version::Draft31, SAMPLE_RETRY_31); - } - - #[test] - fn decode_retry_32() { - decode_retry(Version::Draft32, SAMPLE_RETRY_32); - } - /// Check some packets that are clearly not valid Retry packets. #[test] fn invalid_retry() { @@ -1445,8 +1397,7 @@ mod tests { const SAMPLE_VN: &[u8] = &[ 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x6b, 0x33, 0x43, 0xcf, 0x00, 0x00, 0x00, - 0x01, 0xff, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x1e, 0xff, 0x00, - 0x00, 0x1d, 0x0a, 0x0a, 0x0a, 0x0a, + 0x01, 0xff, 0x00, 0x00, 0x1d, 0x0a, 0x0a, 0x0a, 0x0a, ]; #[test] @@ -1560,7 +1511,7 @@ mod tests { fn decode_too_short() { neqo_crypto::init().unwrap(); let res = PublicPacket::decode( - &[179, 255, 0, 0, 32, 0, 0], + &[179, 255, 0, 0, 29, 0, 0], &EmptyConnectionIdGenerator::default(), ); assert!(res.is_err()); diff --git a/third_party/rust/neqo-transport/src/packet/retry.rs b/third_party/rust/neqo-transport/src/packet/retry.rs index 20381765be35..741b28c7f5f1 100644 --- a/third_party/rust/neqo-transport/src/packet/retry.rs +++ b/third_party/rust/neqo-transport/src/packet/retry.rs @@ -25,6 +25,7 @@ fn make_aead(version: Version) -> Aead { ) .unwrap() } +#[cfg(feature = "draft-29")] thread_local!(static RETRY_AEAD_29: RefCell = RefCell::new(make_aead(Version::Draft29))); thread_local!(static RETRY_AEAD_V1: RefCell = RefCell::new(make_aead(Version::Version1))); thread_local!(static RETRY_AEAD_V2: RefCell = RefCell::new(make_aead(Version::Version2))); @@ -37,11 +38,12 @@ where match version { Version::Version2 => &RETRY_AEAD_V2, Version::Version1 => &RETRY_AEAD_V1, - Version::Draft29 | Version::Draft30 | Version::Draft31 | Version::Draft32 => &RETRY_AEAD_29, + #[cfg(feature = "draft-29")] + Version::Draft29 => &RETRY_AEAD_29, } .try_with(|aead| f(&aead.borrow())) .map_err(|e| { - qerror!("Unable to access Retry AEAD: {:?}", e); + qerror!("Unable to access Retry AEAD: {e:?}"); Error::InternalError })? } diff --git a/third_party/rust/neqo-transport/src/path.rs b/third_party/rust/neqo-transport/src/path.rs index 7d0aaf62a6fc..6a1fa738a876 100644 --- a/third_party/rust/neqo-transport/src/path.rs +++ b/third_party/rust/neqo-transport/src/path.rs @@ -9,20 +9,21 @@ use std::{ cell::RefCell, fmt::{self, Display}, - mem, net::SocketAddr, rc::Rc, time::{Duration, Instant}, }; -use neqo_common::{hex, qdebug, qinfo, qlog::NeqoQlog, qtrace, Datagram, Encoder, IpTos, IpTosEcn}; +use neqo_common::{ + hex, qdebug, qinfo, qlog::NeqoQlog, qtrace, qwarn, Datagram, Encoder, IpTos, IpTosEcn, +}; use neqo_crypto::random; use crate::{ ackrate::{AckRate, PeerAckDelay}, cc::CongestionControlAlgorithm, cid::{ConnectionId, ConnectionIdRef, ConnectionIdStore, RemoteConnectionIdEntry}, - ecn::{EcnCount, EcnInfo}, + ecn, frame::{FRAME_TYPE_PATH_CHALLENGE, FRAME_TYPE_PATH_RESPONSE, FRAME_TYPE_RETIRE_CONNECTION_ID}, packet::PacketBuilder, pmtud::Pmtud, @@ -79,18 +80,14 @@ impl Paths { cc: CongestionControlAlgorithm, pacing: bool, now: Instant, + stats: &mut Stats, ) -> PathRef { self.paths .iter() - .find_map(|p| { - if p.borrow().received_on(local, remote) { - Some(Rc::clone(p)) - } else { - None - } - }) + .find_map(|p| p.borrow().received_on(local, remote).then(|| Rc::clone(p))) .unwrap_or_else(|| { - let mut p = Path::temporary(local, remote, cc, pacing, self.qlog.clone(), now); + let mut p = + Path::temporary(local, remote, cc, pacing, self.qlog.clone(), now, stats); if let Some(primary) = self.primary.as_ref() { p.prime_rtt(primary.borrow().rtt()); } @@ -143,15 +140,15 @@ impl Paths { .is_some_and(|target| Rc::ptr_eq(target, &removed)) { qinfo!( - [path.borrow()], - "The migration target path had to be removed" + "[{}] The migration target path had to be removed", + path.borrow() ); self.migration_target = None; } debug_assert_eq!(Rc::strong_count(&removed), 1); } - qdebug!([path.borrow()], "Make permanent"); + qdebug!("[{}] Make permanent", path.borrow()); path.borrow_mut().make_permanent(local_cid, remote_cid); self.paths.push(Rc::clone(path)); if self.primary.is_none() { @@ -164,7 +161,7 @@ impl Paths { /// to a migration from a peer, in which case the old path needs to be probed. #[must_use] fn select_primary(&mut self, path: &PathRef, now: Instant) -> Option { - qdebug!([path.borrow()], "set as primary path"); + qdebug!("[{}] set as primary path", path.borrow()); let old_path = self.primary.replace(Rc::clone(path)).inspect(|old| { old.borrow_mut().set_primary(false, now); }); @@ -174,7 +171,7 @@ impl Paths { .paths .iter() .enumerate() - .find_map(|(i, p)| if Rc::ptr_eq(p, path) { Some(i) } else { None }) + .find_map(|(i, p)| Rc::ptr_eq(p, path).then_some(i)) .expect("migration target should be permanent"); self.paths.swap(0, idx); @@ -196,13 +193,13 @@ impl Paths { ) -> bool { debug_assert!(!self.is_temporary(path)); let baseline = self.primary().map_or_else( - || EcnInfo::default().baseline(), + || ecn::Info::default().baseline(), |p| p.borrow().ecn_info.baseline(), ); path.borrow_mut().set_ecn_baseline(baseline); if force || path.borrow().is_valid() { path.borrow_mut().set_valid(now); - mem::drop(self.select_primary(path, now)); + drop(self.select_primary(path, now)); self.migration_target = None; } else { self.migration_target = Some(Rc::clone(path)); @@ -223,7 +220,7 @@ impl Paths { if p.borrow_mut().process_timeout(now, pto, stats) { true } else { - qdebug!([p.borrow()], "Retiring path"); + qdebug!("[{}] Retiring path", p.borrow()); if p.borrow().is_primary() { primary_failed = true; } @@ -244,8 +241,8 @@ impl Paths { { // Need a clone as `fallback` is borrowed from `self`. let path = Rc::clone(fallback); - qinfo!([path.borrow()], "Failing over after primary path failed"); - mem::drop(self.select_primary(&path, now)); + qinfo!("[{}] Failing over after primary path failed", path.borrow()); + drop(self.select_primary(&path, now)); true } else { false @@ -253,7 +250,9 @@ impl Paths { } else { // See if the PMTUD raise timer wants to fire. if let Some(path) = self.primary() { - path.borrow_mut().pmtud_mut().maybe_fire_raise_timer(now); + path.borrow_mut() + .pmtud_mut() + .maybe_fire_raise_timer(now, stats); } true } @@ -300,13 +299,7 @@ impl Paths { pub fn select_path(&self) -> Option { self.paths .iter() - .find_map(|p| { - if p.borrow().has_probe() { - Some(Rc::clone(p)) - } else { - None - } - }) + .find_map(|p| p.borrow().has_probe().then(|| Rc::clone(p))) .or_else(|| self.primary.clone()) } @@ -326,7 +319,7 @@ impl Paths { .is_some_and(|target| Rc::ptr_eq(target, p)) { let primary = self.migration_target.take(); - mem::drop(self.select_primary(&primary.unwrap(), now)); + drop(self.select_primary(&primary.unwrap(), now)); return true; } break; @@ -364,8 +357,7 @@ impl Paths { .is_some_and(|target| Rc::ptr_eq(target, p)) { qinfo!( - [path], - "NEW_CONNECTION_ID with Retire Prior To forced migration to fail" + "[{path}] NEW_CONNECTION_ID with Retire Prior To forced migration to fail" ); *migration_target = None; } @@ -424,7 +416,7 @@ impl Paths { #[cfg(test)] pub fn rtt(&self) -> Duration { // Rather than have this fail when there is no active path, - // make a new RTT esimate and interrogate that. + // make a new RTT estimate and interrogate that. // That is more expensive, but it should be rare and breaking encapsulation // is worse, especially as this is only used in tests. self.primary().map_or_else( @@ -513,7 +505,7 @@ pub struct Path { /// The number of bytes sent on this path. sent_bytes: usize, /// The ECN-related state for this path (see RFC9000, Section 13.4 and Appendix A.4) - ecn_info: EcnInfo, + ecn_info: ecn::Info, /// For logging of events. qlog: NeqoQlog, } @@ -528,8 +520,20 @@ impl Path { pacing: bool, qlog: NeqoQlog, now: Instant, + stats: &mut Stats, ) -> Self { - let mut sender = PacketSender::new(cc, pacing, Pmtud::new(remote.ip()), now); + let iface_mtu = match mtu::interface_and_mtu(remote.ip()) { + Ok((name, mtu)) => { + qdebug!("Outbound interface {name} has MTU {mtu}"); + stats.pmtud_iface_mtu = mtu; + Some(mtu) + } + Err(e) => { + qwarn!("Failed to determine outbound interface: {e}"); + None + } + }; + let mut sender = PacketSender::new(cc, pacing, Pmtud::new(remote.ip(), iface_mtu), now); sender.set_qlog(qlog.clone()); Self { local, @@ -544,12 +548,12 @@ impl Path { sender, received_bytes: 0, sent_bytes: 0, - ecn_info: EcnInfo::default(), + ecn_info: ecn::Info::default(), qlog, } } - pub fn set_ecn_baseline(&mut self, baseline: EcnCount) { + pub fn set_ecn_baseline(&mut self, baseline: ecn::Count) { self.ecn_info.set_baseline(baseline); } @@ -595,7 +599,7 @@ impl Path { /// Set whether this path is primary. pub(crate) fn set_primary(&mut self, primary: bool, now: Instant) { - qtrace!([self], "Make primary {}", primary); + qtrace!("[{self}] Make primary {primary}"); debug_assert!(self.remote_cid.is_some()); self.primary = primary; if !primary { @@ -606,7 +610,7 @@ impl Path { /// Set the current path as valid. This updates the time that the path was /// last validated and cancels any path validation. pub fn set_valid(&mut self, now: Instant) { - qdebug!([self], "Path validated {:?}", now); + qdebug!("[{self}] Path validated {now:?}"); self.state = ProbeState::Valid; self.validated = Some(now); } @@ -670,7 +674,7 @@ impl Path { /// Make a datagram. pub fn datagram>>(&mut self, payload: V, stats: &mut Stats) -> Datagram { - // Make sure to use the TOS value from before calling EcnInfo::on_packet_sent, which may + // Make sure to use the TOS value from before calling ecn::Info::on_packet_sent, which may // update the ECN state and can hence change it - this packet should still be sent // with the current value. let tos = self.tos(); @@ -700,7 +704,7 @@ impl Path { let need_full_probe = !*mtu; self.set_valid(now); if need_full_probe { - qdebug!([self], "Sub-MTU probe successful, reset probe count"); + qdebug!("[{self}] Sub-MTU probe successful, reset probe count"); self.probe(stats); } true @@ -729,18 +733,16 @@ impl Path { self.state = if probe_count >= MAX_PATH_PROBES { if self.ecn_info.ecn_mark() == IpTosEcn::Ect0 { // The path validation failure may be due to ECN blackholing, try again without ECN. - qinfo!( - [self], - "Possible ECN blackhole, disabling ECN and re-probing path" - ); - self.ecn_info.disable_ecn(stats); + qinfo!("[{self}] Possible ECN blackhole, disabling ECN and re-probing path"); + self.ecn_info + .disable_ecn(stats, crate::ecn::ValidationError::BlackHole); ProbeState::ProbeNeeded { probe_count: 0 } } else { - qinfo!([self], "Probing failed"); + qinfo!("[{self}] Probing failed"); ProbeState::Failed } } else { - qdebug!([self], "Initiating probe"); + qdebug!("[{self}] Initiating probe"); ProbeState::ProbeNeeded { probe_count } }; } @@ -762,7 +764,7 @@ impl Path { } // Send PATH_RESPONSE. let resp_sent = if let Some(challenge) = self.challenge.take() { - qtrace!([self], "Responding to path challenge {}", hex(challenge)); + qtrace!("[{self}] Responding to path challenge {}", hex(challenge)); builder.encode_varint(FRAME_TYPE_PATH_RESPONSE); builder.encode(&challenge[..]); @@ -779,7 +781,7 @@ impl Path { // Send PATH_CHALLENGE. if let ProbeState::ProbeNeeded { probe_count } = self.state { - qtrace!([self], "Initiating path challenge {}", probe_count); + qtrace!("[{self}] Initiating path challenge {probe_count}"); let data = random::<8>(); builder.encode_varint(FRAME_TYPE_PATH_CHALLENGE); builder.encode(&data); @@ -931,8 +933,7 @@ impl Path { // Two cases: 1. at the client when handling a Retry and // 2. at the server when disposing the Initial packet number space. qinfo!( - [self], - "discarding a packet without an RTT estimate; guessing RTT={:?}", + "[{self}] discarding a packet without an RTT estimate; guessing RTT={:?}", now - sent.time_sent() ); stats.rtt_init_guess = true; @@ -952,7 +953,7 @@ impl Path { pub fn on_packets_acked( &mut self, acked_pkts: &[SentPacket], - ack_ecn: Option, + ack_ecn: Option, now: Instant, stats: &mut Stats, ) { diff --git a/third_party/rust/neqo-transport/src/pmtud.rs b/third_party/rust/neqo-transport/src/pmtud.rs index 880ef70dfce0..ce983fa8a117 100644 --- a/third_party/rust/neqo-transport/src/pmtud.rs +++ b/third_party/rust/neqo-transport/src/pmtud.rs @@ -46,6 +46,7 @@ pub struct Pmtud { search_table: &'static [usize], header_size: usize, mtu: usize, + iface_mtu: usize, probe_index: usize, probe_count: usize, probe_state: Probe, @@ -71,13 +72,14 @@ impl Pmtud { } #[must_use] - pub const fn new(remote_ip: IpAddr) -> Self { + pub fn new(remote_ip: IpAddr, iface_mtu: Option) -> Self { let search_table = Self::search_table(remote_ip); let probe_index = 0; Self { search_table, header_size: Self::header_size(remote_ip), mtu: search_table[probe_index], + iface_mtu: iface_mtu.unwrap_or(usize::MAX), probe_index, probe_count: 0, probe_state: Probe::NotNeeded, @@ -87,11 +89,11 @@ impl Pmtud { } /// Checks whether the PMTUD raise timer should be fired, and does so if needed. - pub fn maybe_fire_raise_timer(&mut self, now: Instant) { + pub fn maybe_fire_raise_timer(&mut self, now: Instant, stats: &mut Stats) { if self.probe_state == Probe::NotNeeded && self.raise_timer.is_some_and(|t| now >= t) { qdebug!("PMTUD raise timer fired"); self.raise_timer = None; - self.start(); + self.start(now, stats); } } @@ -108,12 +110,6 @@ impl Pmtud { self.probe_state == Probe::Needed } - /// Returns true if a PMTUD probe was sent. - #[must_use] - pub fn probe_sent(&self) -> bool { - self.probe_state == Probe::Sent - } - /// Returns the size of the current PMTUD probe. #[must_use] pub const fn probe_size(&self) -> usize { @@ -160,7 +156,7 @@ impl Pmtud { /// Checks whether a PMTUD probe has been acknowledged, and if so, updates the PMTUD state. /// May also initiate a new probe process for a larger MTU. - pub fn on_packets_acked(&mut self, acked_pkts: &[SentPacket], stats: &mut Stats) { + pub fn on_packets_acked(&mut self, acked_pkts: &[SentPacket], now: Instant, stats: &mut Stats) { // Reset the loss counts for all packets sizes <= the size of the largest ACKed packet. let max_len = acked_pkts.iter().map(SentPacket::len).max().unwrap_or(0); if max_len == 0 { @@ -186,15 +182,17 @@ impl Pmtud { // total number of successful probes. stats.pmtud_ack += acked; self.mtu = self.search_table[self.probe_index]; + stats.pmtud_pmtu = self.mtu; qdebug!("PMTUD probe of size {} succeeded", self.mtu); - self.start(); + self.start(now, stats); } /// Stops the PMTUD process, setting the MTU to the largest successful probe size. - fn stop(&mut self, idx: usize, now: Instant) { + fn stop(&mut self, idx: usize, now: Instant, stats: &mut Stats) { self.probe_state = Probe::NotNeeded; // We don't need to send any more probes self.probe_index = idx; // Index of the last successful probe self.mtu = self.search_table[idx]; // Leading to this MTU + stats.pmtud_pmtu = self.mtu; self.probe_count = 0; // Reset the count self.loss_counts.fill(0); // Reset the loss counts self.raise_timer = Some(now + PMTU_RAISE_TIMER); @@ -271,9 +269,8 @@ impl Pmtud { let last_ok = first_failed - 1; qdebug!( - "Packet of size > {} lost >= {} times", - self.search_table[last_ok], - MAX_PROBES + "Packet of size > {} lost >= {MAX_PROBES} times", + self.search_table[last_ok] ); if self.probe_state == Probe::NotNeeded { // We saw multiple losses of packets <= the current MTU outside of PMTU discovery, @@ -283,27 +280,32 @@ impl Pmtud { // TODO: If we are declaring losses, that means that we're getting packets through. // The size of those will put a floor on the MTU. We're currently conservative and // start from scratch, but we don't strictly need to do that. - self.restart(stats); + self.reset(stats); + qdebug!("PMTUD reset and restarting, PLPMTU is now {}", self.mtu); + self.start(now, stats); } else { // We saw multiple losses of packets > the current MTU during PMTU discovery, so // we're done. - self.stop(last_ok, now); + self.stop(last_ok, now, stats); } } - fn restart(&mut self, stats: &mut Stats) { + /// Resets the PMTUD process, starting from the smallest probe size. + fn reset(&mut self, stats: &mut Stats) { self.probe_index = 0; self.mtu = self.search_table[self.probe_index]; + stats.pmtud_pmtu = self.mtu; self.loss_counts.fill(0); self.raise_timer = None; stats.pmtud_change += 1; - qdebug!("PMTUD restarted, PLPMTU is now {}", self.mtu); - self.start(); } /// Starts the next upward PMTUD probe. - pub fn start(&mut self) { - if self.probe_index < SEARCH_TABLE_LEN - 1 { + pub fn start(&mut self, now: Instant, stats: &mut Stats) { + if self.probe_index < SEARCH_TABLE_LEN - 1 // Not at the end of the search table + // Next size is <= iface MTU + && self.search_table[self.probe_index + 1] <= self.iface_mtu + { self.probe_state = Probe::Needed; // We need to send a probe self.probe_count = 0; // For the first time self.probe_index += 1; // At this size @@ -312,8 +314,8 @@ impl Pmtud { self.search_table[self.probe_index], ); } else { - // If we're at the end of the search table, we're done. - self.probe_state = Probe::NotNeeded; + // If we're at the end of the search table or hit the local interface MTU, we're done. + self.stop(self.probe_index, now, stats); } } @@ -344,8 +346,8 @@ mod tests { Pmtud, Stats, }; - const V4: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); - const V6: IpAddr = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + const V4: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED); + const V6: IpAddr = IpAddr::V6(Ipv6Addr::UNSPECIFIED); fn make_sentpacket(pn: u64, now: Instant, len: usize) -> SentPacket { SentPacket::new( @@ -396,7 +398,7 @@ mod tests { let packet = make_sentpacket(pn, now, encoder.len()); if encoder.len() + Pmtud::header_size(addr) <= mtu { - pmtud.on_packets_acked(&[packet], stats); + pmtud.on_packets_acked(&[packet], now, stats); assert_eq!(stats_before.pmtud_ack + 1, stats.pmtud_ack); } else { pmtud.on_packets_lost(&[packet], stats, now); @@ -407,11 +409,11 @@ mod tests { fn find_pmtu(addr: IpAddr, mtu: usize) { fixture_init(); let now = now(); - let mut pmtud = Pmtud::new(addr); + let mut pmtud = Pmtud::new(addr, Some(mtu)); let mut stats = Stats::default(); let mut prot = CryptoDxState::test_default(); - pmtud.start(); + pmtud.start(now, &mut stats); assert!(pmtud.needs_probe()); while pmtud.needs_probe() { @@ -445,12 +447,12 @@ mod tests { fixture_init(); let now = now(); - let mut pmtud = Pmtud::new(addr); + let mut pmtud = Pmtud::new(addr, Some(mtu)); let mut stats = Stats::default(); let mut prot = CryptoDxState::test_default(); assert!(smaller_mtu >= pmtud.search_table[0]); - pmtud.start(); + pmtud.start(now, &mut stats); assert!(pmtud.needs_probe()); while pmtud.needs_probe() { @@ -458,7 +460,7 @@ mod tests { } assert_mtu(&pmtud, mtu); - qdebug!("Reducing MTU to {}", smaller_mtu); + qdebug!("Reducing MTU to {smaller_mtu}"); // Drop packets > smaller_mtu until we need a probe again. while !pmtud.needs_probe() { let pn = prot.next_pn(); @@ -498,12 +500,12 @@ mod tests { fixture_init(); let now = now(); - let mut pmtud = Pmtud::new(addr); + let mut pmtud = Pmtud::new(addr, Some(larger_mtu)); let mut stats = Stats::default(); let mut prot = CryptoDxState::test_default(); assert!(larger_mtu >= pmtud.search_table[0]); - pmtud.start(); + pmtud.start(now, &mut stats); assert!(pmtud.needs_probe()); while pmtud.needs_probe() { @@ -511,9 +513,9 @@ mod tests { } assert_mtu(&pmtud, mtu); - qdebug!("Increasing MTU to {}", larger_mtu); + qdebug!("Increasing MTU to {larger_mtu}"); let now = now + PMTU_RAISE_TIMER; - pmtud.maybe_fire_raise_timer(now); + pmtud.maybe_fire_raise_timer(now, &mut stats); while pmtud.needs_probe() { pmtud_step(&mut pmtud, &mut stats, &mut prot, addr, larger_mtu, now); } @@ -570,7 +572,7 @@ mod tests { #[test] fn pmtud_on_packets_lost() { let now = now(); - let mut pmtud = Pmtud::new(V4); + let mut pmtud = Pmtud::new(V4, Some(1500)); let mut stats = Stats::default(); // No packets lost, nothing should change. @@ -638,23 +640,23 @@ mod tests { #[test] fn pmtud_on_packets_lost_and_acked() { let now = now(); - let mut pmtud = Pmtud::new(V4); + let mut pmtud = Pmtud::new(V4, Some(1500)); let mut stats = Stats::default(); // A packet of size 100 was ACKed, which is smaller than all probe sizes. // Loss counts should be unchanged. - pmtud.on_packets_acked(&[make_sentpacket(0, now, 100)], &mut stats); + pmtud.on_packets_acked(&[make_sentpacket(0, now, 100)], now, &mut stats); assert_eq!([0; SEARCH_TABLE_LEN], pmtud.loss_counts); // A packet of size 100_000 was ACKed, which is larger than all probe sizes. // Loss counts should be unchanged. - pmtud.on_packets_acked(&[make_sentpacket(0, now, 100_000)], &mut stats); + pmtud.on_packets_acked(&[make_sentpacket(0, now, 100_000)], now, &mut stats); assert_eq!([0; SEARCH_TABLE_LEN], pmtud.loss_counts); pmtud.loss_counts.fill(0); // Reset the loss counts. // No packets ACKed, nothing should change. - pmtud.on_packets_acked(&[], &mut stats); + pmtud.on_packets_acked(&[], now, &mut stats); assert_eq!([0; SEARCH_TABLE_LEN], pmtud.loss_counts); // One packet of size 4000 was lost, which should increase loss counts >= 4000 by one. @@ -663,7 +665,7 @@ mod tests { assert_eq!(expected_lc, pmtud.loss_counts); // Now a packet of size 5000 is ACKed, which should reset all loss counts <= 5000. - pmtud.on_packets_acked(&[make_sentpacket(0, now, 5000)], &mut stats); + pmtud.on_packets_acked(&[make_sentpacket(0, now, 5000)], now, &mut stats); let expected_lc = search_table_zero(&pmtud, &pmtud.loss_counts, 5000); assert_eq!(expected_lc, pmtud.loss_counts); @@ -674,7 +676,7 @@ mod tests { assert_eq!(expected_lc, pmtud.loss_counts); // Now a packet of size 8000 is ACKed, which should reset all loss counts <= 8000. - pmtud.on_packets_acked(&[make_sentpacket(0, now, 8000)], &mut stats); + pmtud.on_packets_acked(&[make_sentpacket(0, now, 8000)], now, &mut stats); let expected_lc = search_table_zero(&pmtud, &pmtud.loss_counts, 8000); assert_eq!(expected_lc, pmtud.loss_counts); diff --git a/third_party/rust/neqo-transport/src/qlog.rs b/third_party/rust/neqo-transport/src/qlog.rs index 07a7db18468f..81060e890b2e 100644 --- a/third_party/rust/neqo-transport/src/qlog.rs +++ b/third_party/rust/neqo-transport/src/qlog.rs @@ -6,8 +6,10 @@ // Functions that handle capturing QLOG traces. +#![allow(clippy::module_name_repetitions)] + use std::{ - ops::{Deref, RangeInclusive}, + ops::{Deref as _, RangeInclusive}, time::{Duration, Instant}, }; @@ -50,11 +52,7 @@ pub fn connection_tparams_set(qlog: &NeqoQlog, tph: &TransportParametersHandler, initial_source_connection_id: None, retry_source_connection_id: None, stateless_reset_token: remote.get_bytes(tparams::STATELESS_RESET_TOKEN).map(hex), - disable_active_migration: if remote.get_empty(tparams::DISABLE_MIGRATION) { - Some(true) - } else { - None - }, + disable_active_migration: remote.get_empty(tparams::DISABLE_MIGRATION).then_some(true), max_idle_timeout: Some(remote.get_integer(tparams::IDLE_TIMEOUT)), max_udp_payload_size: Some(remote.get_integer(tparams::MAX_UDP_PAYLOAD_SIZE) as u32), ack_delay_exponent: Some(remote.get_integer(tparams::ACK_DELAY_EXPONENT) as u16), diff --git a/third_party/rust/neqo-transport/src/quic_datagrams.rs b/third_party/rust/neqo-transport/src/quic_datagrams.rs index 0d1a7dd84337..2f4b9a5de312 100644 --- a/third_party/rust/neqo-transport/src/quic_datagrams.rs +++ b/third_party/rust/neqo-transport/src/quic_datagrams.rs @@ -144,7 +144,7 @@ impl QuicDatagrams { /// # Error /// /// The function returns `TooMuchData` if the supply buffer is bigger than - /// the allowed remote datagram size. The funcion does not check if the + /// the allowed remote datagram size. The function does not check if the /// datagram can fit into a packet (i.e. MTU limit). This is checked during /// creation of an actual packet and the datagram will be dropped if it does /// not fit into the packet. diff --git a/third_party/rust/neqo-transport/src/recovery/mod.rs b/third_party/rust/neqo-transport/src/recovery/mod.rs index 8f89b1cfcd93..e76bd3b42757 100644 --- a/third_party/rust/neqo-transport/src/recovery/mod.rs +++ b/third_party/rust/neqo-transport/src/recovery/mod.rs @@ -6,6 +6,8 @@ // Tracking of sent packets and detecting their loss. +#![allow(clippy::module_name_repetitions)] + #[cfg(feature = "bench")] pub mod sent; #[cfg(not(feature = "bench"))] @@ -14,7 +16,6 @@ mod token; use std::{ cmp::{max, min}, - convert::TryFrom, ops::RangeInclusive, time::{Duration, Instant}, }; @@ -26,7 +27,7 @@ use sent::SentPackets; pub use token::{RecoveryToken, StreamRecoveryToken}; use crate::{ - ecn::EcnCount, + ecn, packet::PacketNumber, path::{Path, PathRef}, qlog::{self, QlogMetric}, @@ -181,12 +182,10 @@ impl LossRecoverySpace { self.sent_packets .iter_mut() .filter_map(|sent| { - if sent.pto() { + sent.pto().then(|| { qtrace!("PTO: marking packet {} lost ", sent.pn()); - Some(&*sent) - } else { - None - } + &*sent + }) }) .take(count) } @@ -323,10 +322,8 @@ impl LossRecoverySpace { self.remove_old_lost(now, cleanup_delay); qtrace!( - "detect lost {}: now={:?} delay={:?}", + "detect lost {}: now={now:?} delay={loss_delay:?}", self.space, - now, - loss_delay, ); self.first_ooo_time = None; @@ -341,17 +338,14 @@ impl LossRecoverySpace { // Packets sent before now - loss_delay are deemed lost. if packet.time_sent() + loss_delay <= now { qtrace!( - "lost={}, time sent {:?} is before lost_delay {:?}", + "lost={}, time sent {:?} is before lost_delay {loss_delay:?}", packet.pn(), - packet.time_sent(), - loss_delay + packet.time_sent() ); } else if largest_acked >= Some(packet.pn() + PACKET_THRESHOLD) { qtrace!( - "lost={}, is >= {} from largest acked {:?}", - packet.pn(), - PACKET_THRESHOLD, - largest_acked + "lost={}, is >= {PACKET_THRESHOLD} from largest acked {largest_acked:?}", + packet.pn() ); } else { if largest_acked.is_some() { @@ -477,13 +471,11 @@ impl PtoState { /// Generate a sending profile, indicating what space it should be from. /// This takes a packet from the supply if one remains, or returns `None`. pub fn send_profile(&mut self, mtu: usize) -> Option { - if self.packets > 0 { + (self.packets > 0).then(|| { // This is a PTO, so ignore the limit. self.packets -= 1; - Some(SendProfile::new_pto(self.space, mtu, self.probe)) - } else { - None - } + SendProfile::new_pto(self.space, mtu, self.probe) + }) } } @@ -551,15 +543,13 @@ impl LossRecovery { pub fn on_packet_sent(&mut self, path: &PathRef, mut sent_packet: SentPacket, now: Instant) { let pn_space = PacketNumberSpace::from(sent_packet.packet_type()); - qtrace!([self], "packet {}-{} sent", pn_space, sent_packet.pn()); + qtrace!("[{self}] packet {pn_space}-{} sent", sent_packet.pn()); if let Some(space) = self.spaces.get_mut(pn_space) { path.borrow_mut().packet_sent(&mut sent_packet, now); space.on_packet_sent(sent_packet); } else { qwarn!( - [self], - "ignoring {}-{} from dropped space", - pn_space, + "[{self}] ignoring {pn_space}-{} from dropped space", sent_packet.pn() ); } @@ -608,7 +598,7 @@ impl LossRecovery { primary_path: &PathRef, pn_space: PacketNumberSpace, acked_ranges: R, - ack_ecn: Option, + ack_ecn: Option, ack_delay: Duration, now: Instant, ) -> (Vec, Vec) @@ -647,9 +637,7 @@ impl LossRecovery { } qdebug!( - [self], - "ACK for {} - largest_acked={}", - pn_space, + "[{self}] ACK for {pn_space} - largest_acked={}", largest_acked_pkt.pn() ); @@ -736,7 +724,7 @@ impl LossRecovery { /// Discard state for a given packet number space. pub fn discard(&mut self, primary_path: &PathRef, space: PacketNumberSpace, now: Instant) { - qdebug!([self], "Reset loss recovery state for {}", space); + qdebug!("[{self}] Reset loss recovery state for {space}"); let mut path = primary_path.borrow_mut(); for p in self.spaces.drop_space(space) { path.discard_packet(&p, now, &mut self.stats.borrow_mut()); @@ -763,12 +751,7 @@ impl LossRecovery { } else { None }; - qtrace!( - [self], - "next_timeout loss={:?} pto={:?}", - loss_time, - pto_time - ); + qtrace!("[{self}] next_timeout loss={loss_time:?} pto={pto_time:?}"); match (loss_time, pto_time) { (Some(loss_time), Some(pto_time)) => Some(min(loss_time, pto_time)), (Some(loss_time), None) => Some(loss_time), @@ -872,7 +855,7 @@ impl LossRecovery { if let Some(t) = self.pto_time(rtt, *pn_space) { allow_probes[*pn_space] = true; if t <= now { - qdebug!([self], "PTO timer fired for {}", pn_space); + qdebug!("[{self}] PTO timer fired for {pn_space}"); let space = self.spaces.get_mut(*pn_space).unwrap(); lost.extend( space @@ -888,13 +871,13 @@ impl LossRecovery { // This has to happen outside the loop. Increasing the PTO count here causes the // pto_time to increase which might cause PTO for later packet number spaces to not fire. if let Some(pn_space) = pto_space { - qtrace!([self], "PTO {}, probing {:?}", pn_space, allow_probes); + qtrace!("[{self}] PTO {pn_space}, probing {allow_probes:?}"); self.fire_pto(pn_space, allow_probes, now); } } pub fn timeout(&mut self, primary_path: &PathRef, now: Instant) -> Vec { - qtrace!([self], "timeout {:?}", now); + qtrace!("[{self}] timeout {now:?}"); let loss_delay = primary_path.borrow().rtt().loss_delay(); let confirmed = self.confirmed(); @@ -928,7 +911,7 @@ impl LossRecovery { /// what the current congestion window is, and what the pacer says. #[allow(clippy::option_if_let_else)] pub fn send_profile(&mut self, path: &Path, now: Instant) -> SendProfile { - qtrace!([self], "get send profile {:?}", now); + qtrace!("[{self}] get send profile {now:?}"); let sender = path.sender(); let mtu = path.plpmtu(); if let Some(profile) = self @@ -971,7 +954,6 @@ impl ::std::fmt::Display for LossRecovery { mod tests { use std::{ cell::RefCell, - convert::TryInto, ops::{Deref, DerefMut, RangeInclusive}, rc::Rc, time::{Duration, Instant}, @@ -986,7 +968,7 @@ mod tests { use crate::{ cc::CongestionControlAlgorithm, cid::{ConnectionId, ConnectionIdEntry}, - ecn::EcnCount, + ecn, packet::{PacketNumber, PacketType}, path::{Path, PathRef}, stats::{Stats, StatsCell}, @@ -1014,7 +996,7 @@ mod tests { &mut self, pn_space: PacketNumberSpace, acked_ranges: Vec>, - ack_ecn: Option, + ack_ecn: Option, ack_delay: Duration, now: Instant, ) -> (Vec, Vec) { @@ -1050,6 +1032,7 @@ mod tests { impl Default for Fixture { fn default() -> Self { const CC: CongestionControlAlgorithm = CongestionControlAlgorithm::NewReno; + let stats = StatsCell::default(); let mut path = Path::temporary( DEFAULT_ADDR, DEFAULT_ADDR, @@ -1057,6 +1040,7 @@ mod tests { true, NeqoQlog::default(), now(), + &mut stats.borrow_mut(), ); path.make_permanent( None, @@ -1065,7 +1049,7 @@ mod tests { path.set_primary(true, now()); path.rtt_mut().set_initial(TEST_RTT); Self { - lr: LossRecovery::new(StatsCell::default(), FAST_PTO_SCALE), + lr: LossRecovery::new(stats, FAST_PTO_SCALE), path: Rc::new(RefCell::new(path)), } } diff --git a/third_party/rust/neqo-transport/src/recovery/sent.rs b/third_party/rust/neqo-transport/src/recovery/sent.rs index 7c461f21b2d3..a9f775599c53 100644 --- a/third_party/rust/neqo-transport/src/recovery/sent.rs +++ b/third_party/rust/neqo-transport/src/recovery/sent.rs @@ -305,7 +305,6 @@ impl SentPackets { mod tests { use std::{ cell::OnceCell, - convert::TryFrom, time::{Duration, Instant}, }; @@ -366,7 +365,7 @@ mod tests { let mut it = store.into_iter(); assert_eq!(idx, it.next().unwrap().pn()); assert!(it.next().is_none()); - std::mem::drop(it); + drop(it); assert_eq!(pkts.len(), 2); } diff --git a/third_party/rust/neqo-transport/src/recv_stream.rs b/third_party/rust/neqo-transport/src/recv_stream.rs index 44e7f8b9a96a..0d84929c4870 100644 --- a/third_party/rust/neqo-transport/src/recv_stream.rs +++ b/third_party/rust/neqo-transport/src/recv_stream.rs @@ -7,6 +7,8 @@ // Building a stream of ordered bytes to give the application from a series of // incoming STREAM frames. +#![allow(clippy::module_name_repetitions)] + use std::{ cell::RefCell, cmp::max, @@ -70,15 +72,13 @@ impl RecvStreams { pub fn keep_alive(&mut self, id: StreamId, k: bool) -> Res<()> { let self_ka = &mut self.keep_alive; let s = self.streams.get_mut(&id).ok_or(Error::InvalidStreamId)?; - s.keep_alive = if k { - Some(self_ka.upgrade().unwrap_or_else(|| { + s.keep_alive = k.then(|| { + self_ka.upgrade().unwrap_or_else(|| { let r = Rc::new(()); *self_ka = Rc::downgrade(&r); r - })) - } else { - None - }; + }) + }); Ok(()) } @@ -132,7 +132,7 @@ impl RxStreamOrderer { /// Only when `u64` values cannot be converted to `usize`, which only /// happens on 32-bit machines that hold far too much data at the same time. pub fn inbound_frame(&mut self, mut new_start: u64, mut new_data: &[u8]) { - qtrace!("Inbound data offset={} len={}", new_start, new_data.len()); + qtrace!("Inbound data offset={new_start} len={}", new_data.len()); // Get entry before where new entry would go, so we can see if we already // have the new bytes. @@ -165,12 +165,7 @@ impl RxStreamOrderer { // Add a range containing only new data // (In-order frames will take this path, with no overlap) let overlap = prev_end.saturating_sub(new_start); - qtrace!( - "New frame {}-{} received, overlap: {}", - new_start, - new_end, - overlap - ); + qtrace!("New frame {new_start}-{new_end} received, overlap: {overlap}"); new_start += overlap; new_data = &new_data[usize::try_from(overlap).unwrap()..]; // If it is small enough, extend the previous buffer. @@ -182,15 +177,11 @@ impl RxStreamOrderer { // NNNN // NNNN // Do nothing - qtrace!( - "Dropping frame with already-received range {}-{}", - new_start, - new_end - ); + qtrace!("Dropping frame with already-received range {new_start}-{new_end}"); return; } } else { - qtrace!("New frame {}-{} received", new_start, new_end); + qtrace!("New frame {new_start}-{new_end} received"); false }; @@ -228,21 +219,14 @@ impl RxStreamOrderer { break; } else if next_end >= new_end { qtrace!( - "New frame {}-{} overlaps with next frame by {}, truncating", - new_start, - new_end, - overlap + "New frame {new_start}-{new_end} overlaps with next frame by {overlap}, truncating" ); let truncate_to = new_data.len() - usize::try_from(overlap).unwrap(); to_add = &new_data[..truncate_to]; break; } qtrace!( - "New frame {}-{} spans entire next frame {}-{}, replacing", - new_start, - new_end, - next_start, - next_end + "New frame {new_start}-{new_end} spans entire next frame {next_start}-{next_end}, replacing" ); to_remove.push(next_start); // Continue, since we may have more overlaps @@ -570,7 +554,7 @@ impl RecvStream { match new_state { // Receiving all data, or receiving or requesting RESET_STREAM - // is cause to stop keep-alives. + // is cause to stop keepalives. RecvStreamState::DataRecvd { .. } | RecvStreamState::AbortReading { .. } | RecvStreamState::ResetRecvd { .. } => { @@ -752,7 +736,6 @@ impl RecvStream { Ok(()) } - /// If we should tell the sender they have more credit, return an offset fn flow_control_retire_data( new_read: u64, fc: &mut ReceiverFlowControl, @@ -1016,7 +999,7 @@ mod tests { fn recv_ranges(ranges: &[Range], available: usize) { const ZEROES: &[u8] = &[0; 100]; - qtrace!("recv_ranges {:?}", ranges); + qtrace!("recv_ranges {ranges:?}"); let mut s = RxStreamOrderer::default(); for r in ranges { @@ -1028,7 +1011,7 @@ mod tests { let mut total_recvd = 0; loop { let recvd = s.read(&mut buf[..]); - qtrace!("recv_ranges read {}", recvd); + qtrace!("recv_ranges read {recvd}"); total_recvd += recvd; if recvd == 0 { assert_eq!(total_recvd, available); @@ -1170,7 +1153,7 @@ mod tests { // Add a chunk s.inbound_frame(0, &[0; 150]); - assert_eq!(s.data_ranges.get(&0).unwrap().len(), 150); + assert_eq!(s.data_ranges[&0].len(), 150); // Read, providing only enough space for the first 100. let mut buf = [0; 100]; let count = s.read(&mut buf[..]); @@ -1181,7 +1164,7 @@ mod tests { // This shouldn't truncate the first frame, as we're already // Reading from it. s.inbound_frame(120, &[0; 60]); - assert_eq!(s.data_ranges.get(&0).unwrap().len(), 180); + assert_eq!(s.data_ranges[&0].len(), 180); // Read second part of first frame and all of the second frame let count = s.read(&mut buf[..]); assert_eq!(count, 80); @@ -1839,7 +1822,7 @@ mod tests { assert_eq!(s.read(&mut buf).unwrap(), (1, false)); check_fc(&fc.borrow(), SW / 4 + 1, SW / 4 + 1); check_fc(s.fc().unwrap(), SW / 4 + 1, SW / 4 + 1); - // Data are retired and the sttream fc will send an update. + // Data are retired and the stream fc will send an update. assert!(!fc.borrow().frame_needed()); assert!(s.fc().unwrap().frame_needed()); diff --git a/third_party/rust/neqo-transport/src/rtt.rs b/third_party/rust/neqo-transport/src/rtt.rs index c18bbd62ec7d..db28777d9161 100644 --- a/third_party/rust/neqo-transport/src/rtt.rs +++ b/third_party/rust/neqo-transport/src/rtt.rs @@ -6,6 +6,8 @@ // Tracking of sent packets and detecting their loss. +#![allow(clippy::module_name_repetitions)] + use std::{ cmp::{max, min}, time::{Duration, Instant}, @@ -74,7 +76,7 @@ impl RttEstimate { } pub fn set_initial(&mut self, rtt: Duration) { - qtrace!("initial RTT={:?}", rtt); + qtrace!("initial RTT={rtt:?}"); if rtt >= GRANULARITY { // Ignore if the value is too small. self.init(rtt); diff --git a/third_party/rust/neqo-transport/src/send_stream.rs b/third_party/rust/neqo-transport/src/send_stream.rs index e05a0efa3feb..915997737a98 100644 --- a/third_party/rust/neqo-transport/src/send_stream.rs +++ b/third_party/rust/neqo-transport/src/send_stream.rs @@ -6,6 +6,8 @@ // Buffering data to send until it is acked. +#![allow(clippy::module_name_repetitions)] + use std::{ cell::RefCell, cmp::{max, min, Ordering}, @@ -405,7 +407,7 @@ impl RangeTracker { fn unmark_range(&mut self, off: u64, len: usize) { if len == 0 { - qdebug!("unmark 0-length range at {}", off); + qdebug!("unmark 0-length range at {off}"); return; } @@ -424,10 +426,7 @@ impl RangeTracker { if *cur_off + *cur_len > off { if *cur_state == RangeState::Acked { qdebug!( - "Attempted to unmark Acked range {}-{} with unmark_range {}-{}", - cur_off, - cur_len, - off, + "Attempted to unmark Acked range {cur_off}-{cur_len} with unmark_range {off}-{}", off + len ); } else { @@ -439,10 +438,7 @@ impl RangeTracker { if *cur_state == RangeState::Acked { qdebug!( - "Attempted to unmark Acked range {}-{} with unmark_range {}-{}", - cur_off, - cur_len, - off, + "Attempted to unmark Acked range {cur_off}-{cur_len} with unmark_range {off}-{}", off + len ); continue; @@ -760,7 +756,7 @@ impl SendStream { tokens: &mut Vec, stats: &mut FrameStats, ) { - qtrace!("write STREAM frames at priority {:?}", priority); + qtrace!("write STREAM frames at priority {priority:?}"); if !self.write_reset_frame(priority, builder, tokens, stats) { self.write_blocked_frame(priority, builder, tokens, stats); self.write_stream_frame(priority, builder, tokens, stats); @@ -882,15 +878,13 @@ impl SendStream { "next_bytes apply retransmission limit at {}", self.retransmission_offset ); - if self.retransmission_offset > offset { + (self.retransmission_offset > offset).then(|| { let len = min( usize::try_from(self.retransmission_offset - offset).unwrap(), slice.len(), ); - Some((offset, &slice[..len])) - } else { - None - } + (offset, &slice[..len]) + }) } else { Some((offset, slice)) } @@ -926,7 +920,7 @@ impl SendStream { fn length_and_fill(data_len: usize, space: usize) -> (usize, bool) { if data_len >= space { // More data than space allows, or an exact fit => fast path. - qtrace!("SendStream::length_and_fill fill {}", space); + qtrace!("SendStream::length_and_fill fill {space}"); return (space, true); } @@ -939,7 +933,7 @@ impl SendStream { // From here we can always fit `data_len`, but we might as well fill // if there is no space for the length field plus another frame. let fill = data_len + length_len + PacketBuilder::MINIMUM_FRAME_SIZE > space; - qtrace!("SendStream::length_and_fill {} fill {}", data_len, fill); + qtrace!("SendStream::length_and_fill {data_len} fill {fill}"); (data_len, fill) } @@ -971,14 +965,14 @@ impl SendStream { 0 }; if overhead > builder.remaining() { - qtrace!([self], "write_frame no space for header"); + qtrace!("[{self}] write_frame no space for header"); return; } let (length, fill) = Self::length_and_fill(data.len(), builder.remaining() - overhead); let fin = final_size.is_some_and(|fs| fs == offset + u64::try_from(length).unwrap()); if length == 0 && !fin { - qtrace!([self], "write_frame no data, no fin"); + qtrace!("[{self}] write_frame no data, no fin"); return; } @@ -1015,7 +1009,7 @@ impl SendStream { | SendStreamState::Send { .. } | SendStreamState::DataSent { .. } | SendStreamState::DataRecvd { .. } => { - qtrace!([self], "Reset acked while in {} state?", self.state.name()); + qtrace!("[{self}] Reset acked while in {} state?", self.state.name()); } SendStreamState::ResetSent { final_retired, @@ -1025,7 +1019,7 @@ impl SendStream { final_retired, final_written, }), - SendStreamState::ResetRecvd { .. } => qtrace!([self], "already in ResetRecvd state"), + SendStreamState::ResetRecvd { .. } => qtrace!("[{self}] already in ResetRecvd state"), }; } @@ -1085,7 +1079,7 @@ impl SendStream { { fc.frame_lost(limit); } else { - qtrace!([self], "Ignoring lost STREAM_DATA_BLOCKED({})", limit); + qtrace!("[{self}] Ignoring lost STREAM_DATA_BLOCKED({limit})"); } } @@ -1154,8 +1148,7 @@ impl SendStream { } } _ => qtrace!( - [self], - "mark_as_acked called from state {}", + "[{self}] mark_as_acked called from state {}", self.state.name() ), } @@ -1168,8 +1161,7 @@ impl SendStream { offset + u64::try_from(len).unwrap(), ); qtrace!( - [self], - "mark_as_lost retransmission offset={}", + "[{self}] mark_as_lost retransmission offset={}", self.retransmission_offset ); if let Some(buf) = self.state.tx_buf_mut() { @@ -1259,7 +1251,7 @@ impl SendStream { fn send_internal(&mut self, buf: &[u8], atomic: bool) -> Res { if buf.is_empty() { - qerror!([self], "zero-length send on stream"); + qerror!("[{self}] zero-length send on stream"); return Err(Error::InvalidInput); } @@ -1323,10 +1315,10 @@ impl SendStream { fin_acked: false, }); } - SendStreamState::DataSent { .. } => qtrace!([self], "already in DataSent state"), - SendStreamState::DataRecvd { .. } => qtrace!([self], "already in DataRecvd state"), - SendStreamState::ResetSent { .. } => qtrace!([self], "already in ResetSent state"), - SendStreamState::ResetRecvd { .. } => qtrace!([self], "already in ResetRecvd state"), + SendStreamState::DataSent { .. } => qtrace!("[{self}] already in DataSent state"), + SendStreamState::DataRecvd { .. } => qtrace!("[{self}] already in DataRecvd state"), + SendStreamState::ResetSent { .. } => qtrace!("[{self}] already in ResetSent state"), + SendStreamState::ResetRecvd { .. } => qtrace!("[{self}] already in ResetRecvd state"), } } @@ -1367,9 +1359,9 @@ impl SendStream { final_written: buffered, }); } - SendStreamState::DataRecvd { .. } => qtrace!([self], "already in DataRecvd state"), - SendStreamState::ResetSent { .. } => qtrace!([self], "already in ResetSent state"), - SendStreamState::ResetRecvd { .. } => qtrace!([self], "already in ResetRecvd state"), + SendStreamState::DataRecvd { .. } => qtrace!("[{self}] already in DataRecvd state"), + SendStreamState::ResetSent { .. } => qtrace!("[{self}] already in ResetSent state"), + SendStreamState::ResetRecvd { .. } => qtrace!("[{self}] already in ResetRecvd state"), }; } @@ -1694,7 +1686,7 @@ impl SendStreams { tokens: &mut Vec, stats: &mut FrameStats, ) { - qtrace!("write STREAM frames at priority {:?}", priority); + qtrace!("write STREAM frames at priority {priority:?}"); // WebTransport data (which is Normal) may have a SendOrder // priority attached. The spec states (6.3 write-chunk 6.1): @@ -1731,7 +1723,7 @@ impl SendStreams { qtrace!("processing streams... unfair:"); for stream in self.map.values_mut() { if !stream.is_fair() { - qtrace!(" {}", stream); + qtrace!(" {stream}"); if !stream.write_frames_with_early_return(priority, builder, tokens, stats) { break; } @@ -1747,7 +1739,7 @@ impl SendStreams { for stream_id in stream_ids { let stream = self.map.get_mut(&stream_id).unwrap(); if let Some(order) = stream.sendorder() { - qtrace!(" {} ({})", stream_id, order); + qtrace!(" {stream_id} ({order})"); } else { qtrace!(" None"); } @@ -1793,7 +1785,7 @@ pub struct SendStreamRecoveryToken { mod tests { use std::{cell::RefCell, collections::VecDeque, num::NonZeroUsize, rc::Rc}; - use neqo_common::{event::Provider, hex_with_len, qtrace, Encoder}; + use neqo_common::{event::Provider as _, hex_with_len, qtrace, Encoder}; use super::SendStreamRecoveryToken; use crate::{ @@ -2943,14 +2935,7 @@ mod tests { fn frame_sent_sid(stream: u64, offset: usize, len: usize, fin: bool, space: usize) -> bool { const BUF: &[u8] = &[0x42; 128]; - qtrace!( - "frame_sent stream={} offset={} len={} fin={}, space={}", - stream, - offset, - len, - fin, - space - ); + qtrace!("frame_sent stream={stream} offset={offset} len={len} fin={fin}, space={space}"); let mut s = stream_with_sent(stream, offset); @@ -3058,7 +3043,7 @@ mod tests { fn stream_frame_at_boundary(data: &[u8]) { fn send_with_extra_capacity(data: &[u8], extra: usize, expect_full: bool) -> Vec { - qtrace!("send_with_extra_capacity {} + {}", data.len(), extra); + qtrace!("send_with_extra_capacity {} + {extra}", data.len()); let mut s = stream_with_sent(0, 0); s.send(data).unwrap(); s.close(); diff --git a/third_party/rust/neqo-transport/src/sender.rs b/third_party/rust/neqo-transport/src/sender.rs index e6075ee32748..62aa0a13cf47 100644 --- a/third_party/rust/neqo-transport/src/sender.rs +++ b/third_party/rust/neqo-transport/src/sender.rs @@ -93,9 +93,8 @@ impl PacketSender { let current_mtu = self.pmtud().plpmtu(); if current_mtu != self.pacer.mtu() { qdebug!( - "PLPMTU changed from {} to {}, updating pacer", - self.pacer.mtu(), - current_mtu + "PLPMTU changed from {} to {current_mtu}, updating pacer", + self.pacer.mtu() ); self.pacer.set_mtu(current_mtu); } @@ -109,7 +108,7 @@ impl PacketSender { stats: &mut Stats, ) { self.cc.on_packets_acked(acked_pkts, rtt_est, now); - self.pmtud_mut().on_packets_acked(acked_pkts, stats); + self.pmtud_mut().on_packets_acked(acked_pkts, now, stats); self.maybe_update_pacer_mtu(); } @@ -161,11 +160,7 @@ impl PacketSender { #[must_use] pub fn next_paced(&self, rtt: Duration) -> Option { // Only pace if there are bytes in flight. - if self.cc.bytes_in_flight() > 0 { - Some(self.pacer.next(rtt, self.cc.cwnd())) - } else { - None - } + (self.cc.bytes_in_flight() > 0).then(|| self.pacer.next(rtt, self.cc.cwnd())) } #[must_use] diff --git a/third_party/rust/neqo-transport/src/server.rs b/third_party/rust/neqo-transport/src/server.rs index 7a4472ae1a47..9f3056a93ec2 100644 --- a/third_party/rust/neqo-transport/src/server.rs +++ b/third_party/rust/neqo-transport/src/server.rs @@ -17,7 +17,8 @@ use std::{ }; use neqo_common::{ - event::Provider, hex, qdebug, qerror, qinfo, qlog::NeqoQlog, qtrace, qwarn, Datagram, Role, + event::Provider as _, hex, qdebug, qerror, qinfo, qlog::NeqoQlog, qtrace, qwarn, Datagram, + IpTos, Role, }; use neqo_crypto::{ encode_ech_config, AntiReplay, Cipher, PrivateKey, PublicKey, ZeroRttCheckResult, @@ -198,7 +199,7 @@ impl Server { dgram: Datagram>, now: Instant, ) -> Output { - qdebug!([self], "Handle initial"); + qdebug!("[{self}] Handle initial"); let res = self .address_validation .borrow() @@ -210,7 +211,7 @@ impl Server { self.accept_connection(initial, dgram, Some(orig_dcid), now) } AddressValidationResult::Validate => { - qinfo!([self], "Send retry for {:?}", initial.dst_cid); + qinfo!("[{self}] Send retry for {:?}", initial.dst_cid); let res = self.address_validation.borrow().generate_retry_token( &initial.dst_cid, @@ -218,7 +219,7 @@ impl Server { now, ); let Ok(token) = res else { - qerror!([self], "unable to generate token, dropping packet"); + qerror!("[{self}] unable to generate token, dropping packet"); return Output::None; }; if let Some(new_dcid) = self.cid_generator.borrow_mut().generate_cid() { @@ -231,20 +232,29 @@ impl Server { ); packet.map_or_else( |_| { - qerror!([self], "unable to encode retry, dropping packet"); + qerror!("[{self}] unable to encode retry, dropping packet"); Output::None }, |p| { + qdebug!( + "[{self}] type={:?} path:{} {}->{} {:?} len {}", + PacketType::Retry, + initial.dst_cid, + dgram.destination(), + dgram.source(), + IpTos::default(), + p.len(), + ); Output::Datagram(Datagram::new( dgram.destination(), dgram.source(), - dgram.tos(), + IpTos::default(), p, )) }, ) } else { - qerror!([self], "no connection ID for retry, dropping packet"); + qerror!("[{self}] no connection ID for retry, dropping packet"); Output::None } } @@ -260,10 +270,10 @@ impl Server { Role::Server, Some("Neqo server qlog".to_string()), Some("Neqo server qlog".to_string()), - odcid, + format!("server-{odcid}"), ) .unwrap_or_else(|e| { - qerror!("failed to create NeqoQlog: {}", e); + qerror!("failed to create NeqoQlog: {e}"); NeqoQlog::disabled() }) }) @@ -277,7 +287,7 @@ impl Server { ) { let zcheck = self.zero_rtt_checker.clone(); if c.server_enable_0rtt(&self.anti_replay, zcheck).is_err() { - qwarn!([self], "Unable to enable 0-RTT"); + qwarn!("[{self}] Unable to enable 0-RTT"); } if let Some(odcid) = &orig_dcid { // There was a retry, so set the connection IDs for. @@ -289,7 +299,7 @@ impl Server { if c.server_enable_ech(cfg.config, &cfg.public_name, &cfg.sk, &cfg.pk) .is_err() { - qwarn!([self], "Unable to enable ECH"); + qwarn!("[{self}] Unable to enable ECH"); } } } @@ -302,8 +312,7 @@ impl Server { now: Instant, ) -> Output { qinfo!( - [self], - "Accept connection {:?}", + "[{self}] Accept connection {:?}", orig_dcid.as_ref().unwrap_or(&initial.dst_cid) ); // The internal connection ID manager that we use is not used directly. @@ -326,7 +335,7 @@ impl Server { out } Err(e) => { - qwarn!([self], "Unable to create connection"); + qwarn!("[{self}] Unable to create connection"); if e == crate::Error::VersionNegotiation { crate::qlog::server_version_information_failed( &self.create_qlog_trace(orig_dcid.unwrap_or(initial.dst_cid).as_cid_ref()), @@ -347,7 +356,7 @@ impl Server { // All packets in the datagram are routed to the same connection. let res = PublicPacket::decode(&dgram[..], self.cid_generator.borrow().as_decoder()); let Ok((packet, _remainder)) = res else { - qtrace!([self], "Discarding {:?}", dgram); + qtrace!("[{self}] Discarding {dgram:?}"); return Output::None; }; @@ -362,7 +371,7 @@ impl Server { if packet.packet_type() == PacketType::Short { // TODO send a stateless reset here. - qtrace!([self], "Short header packet for an unknown connection"); + qtrace!("[{self}] Short header packet for an unknown connection"); return Output::None; } @@ -375,17 +384,26 @@ impl Server { .contains(&packet.version().unwrap())) { if dgram.len() < MIN_INITIAL_PACKET_SIZE { - qdebug!([self], "Unsupported version: too short"); + qdebug!("[{self}] Unsupported version: too short"); return Output::None; } - qdebug!([self], "Unsupported version: {:x}", packet.wire_version()); + qdebug!("[{self}] Unsupported version: {:x}", packet.wire_version()); let vn = PacketBuilder::version_negotiation( &packet.scid()[..], &packet.dcid()[..], packet.wire_version(), self.conn_params.get_versions().all(), ); + qdebug!( + "[{self}] type={:?} path:{} {}->{} {:?} len {}", + PacketType::VersionNegotiation, + packet.dcid(), + dgram.destination(), + dgram.source(), + IpTos::default(), + vn.len(), + ); crate::qlog::server_version_information_failed( &self.create_qlog_trace(packet.dcid()), @@ -397,7 +415,7 @@ impl Server { return Output::Datagram(Datagram::new( dgram.destination(), dgram.source(), - dgram.tos(), + IpTos::default(), vn, )); } @@ -405,7 +423,7 @@ impl Server { match packet.packet_type() { PacketType::Initial => { if dgram.len() < MIN_INITIAL_PACKET_SIZE { - qdebug!([self], "Drop initial: too short"); + qdebug!("[{self}] Drop initial: too short"); return Output::None; } // Copy values from `packet` because they are currently still borrowing from @@ -415,12 +433,12 @@ impl Server { } PacketType::ZeroRtt => { let dcid = ConnectionId::from(packet.dcid()); - qdebug!([self], "Dropping 0-RTT for unknown connection {}", dcid); + qdebug!("[{self}] Dropping 0-RTT for unknown connection {dcid}"); Output::None } PacketType::OtherVersion => unreachable!(), _ => { - qtrace!([self], "Not an initial packet"); + qtrace!("[{self}] Not an initial packet"); Output::None } } diff --git a/third_party/rust/neqo-transport/src/shuffle.rs b/third_party/rust/neqo-transport/src/shuffle.rs new file mode 100644 index 000000000000..fd81190c27ec --- /dev/null +++ b/third_party/rust/neqo-transport/src/shuffle.rs @@ -0,0 +1,137 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Range; + +use neqo_common::{qtrace, Decoder}; + +/// Finds the range where the SNI extension lives, or returns `None`. +#[must_use] +pub fn find_sni(buf: &[u8]) -> Option> { + #[must_use] + fn skip(dec: &mut Decoder, len: usize) -> Option<()> { + if len > dec.remaining() { + return None; + } + dec.skip(len); + Some(()) + } + + #[must_use] + fn skip_vec(dec: &mut Decoder) -> Option<()> + where + T: TryFrom, + usize: TryFrom, + { + let len = dec.decode_uint::()?; + skip(dec, usize::try_from(len).ok()?) + } + + let mut dec = Decoder::from(buf); + + // Return if buf is empty or does not contain a ClientHello (first byte == 1) + if buf.is_empty() || dec.decode_uint::()? != 1 { + return None; + } + skip(&mut dec, 3 + 2 + 32)?; // Skip length, version, random + skip_vec::(&mut dec)?; // Skip session_id + skip_vec::(&mut dec)?; // Skip cipher_suites + skip_vec::(&mut dec)?; // Skip compression_methods + skip(&mut dec, 2)?; + + while dec.remaining() >= 4 { + let ext_type: u16 = dec.decode_uint()?; + let ext_len: u16 = dec.decode_uint()?; + if ext_type == 0 { + // SNI! + let sni_len: u16 = dec.decode_uint()?; + skip(&mut dec, 3)?; // Skip name_type and host_name length + let start = dec.offset(); + let end = start + usize::from(sni_len) - 3; + if end > dec.offset() + dec.remaining() { + return None; + } + qtrace!( + "SNI range {start}..{end}: {:?}", + String::from_utf8_lossy(&buf[start..end]) + ); + return Some(start..end); + } + // Skip extension + skip(&mut dec, ext_len.into())?; + } + None +} + +#[cfg(test)] +mod tests { + const BUF_WITH_SNI: &[u8] = &[ + 0x01, // msg_type == 1 (ClientHello) + 0x00, 0x01, 0xfc, // length (arbitrary) + 0x03, 0x03, // version (TLS 1.2) + 0x0e, 0x2d, 0x03, 0x37, 0xd9, 0x14, 0x2b, 0x32, 0x4e, 0xa8, 0xcf, 0x1f, 0xfa, 0x5b, 0x6c, + 0xeb, 0xdd, 0x10, 0xa6, 0x49, 0x6e, 0xbf, 0xe4, 0x32, 0x3d, 0x0c, 0xe4, 0xbf, 0x90, 0xcf, + 0x08, 0x42, // random + 0x00, // session_id length + 0x00, 0x08, // cipher_suites length + 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0xca, 0xca, // cipher_suites + 0x01, // compression_methods length + 0x00, // compression_methods + 0x01, 0xcb, // extensions length + 0xff, 0x01, 0x00, 0x01, 0x00, // renegiation_info + 0x00, 0x2d, 0x00, 0x03, 0x02, 0x01, 0x87, // psk_exchange_modes + // SNI extension + 0x00, 0x00, // Extension type (SNI) + 0x00, 0x0e, // Extension length + 0x00, 0x0c, // Server Name List length + 0x00, // Name type (host_name) + 0x00, 0x09, // Host name length + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, // server_name: "localhost" + 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, // status_request + ]; + + #[test] + fn find_sni() { + // ClientHello with SNI extension + let range = super::find_sni(BUF_WITH_SNI).unwrap(); + let expected_range = BUF_WITH_SNI.len() - 18..BUF_WITH_SNI.len() - 9; + assert_eq!(range, expected_range); + assert_eq!(&BUF_WITH_SNI[range], b"localhost"); + } + + #[test] + fn find_sni_no_sni() { + // ClientHello without SNI extension + let mut buf = Vec::from(&BUF_WITH_SNI[..BUF_WITH_SNI.len() - 39]); + let len = buf.len(); + assert!(buf[len - 2] == 0x01 && buf[len - 1] == 0xcb); // Check extensions length + // Set extensions length to 0 + buf[len - 2] = 0x00; + buf[len - 1] = 0x00; + assert!(super::find_sni(&buf).is_none()); + } + + #[test] + fn find_sni_invalid_sni() { + // ClientHello with an SNI extension truncated somewhere in the hostname + let truncated = &BUF_WITH_SNI[..BUF_WITH_SNI.len() - 15]; + assert!(super::find_sni(truncated).is_none()); + } + + #[test] + fn find_sni_no_ci() { + // Not a ClientHello (msg_type != 1) + let buf = [0; 1]; + assert!(super::find_sni(&buf).is_none()); + } + + #[test] + fn find_sni_malformed_ci() { + // Buffer starting with `1` but otherwise malformed + let buf = [1; 1]; + assert!(super::find_sni(&buf).is_none()); + } +} diff --git a/third_party/rust/neqo-transport/src/stats.rs b/third_party/rust/neqo-transport/src/stats.rs index a8c35c1c66a6..6d7621bc7d5f 100644 --- a/third_party/rust/neqo-transport/src/stats.rs +++ b/third_party/rust/neqo-transport/src/stats.rs @@ -16,7 +16,7 @@ use std::{ use neqo_common::qwarn; -use crate::{ecn::EcnCount, packet::PacketNumber}; +use crate::{ecn, packet::PacketNumber}; pub const MAX_PTO_COUNTS: usize = 16; @@ -168,6 +168,10 @@ pub struct Stats { pub pmtud_lost: usize, /// Number of times a path MTU changed unexpectedly. pub pmtud_change: usize, + /// MTU of the local interface used for the most recent path. + pub pmtud_iface_mtu: usize, + /// Probed PMTU of the current path. + pub pmtud_pmtu: usize, /// Whether the connection was resumed successfully. pub resumed: bool, @@ -194,10 +198,8 @@ pub struct Stats { pub datagram_tx: DatagramStats, - /// Number of paths known to be ECN capable. - pub ecn_paths_capable: usize, - /// Number of paths known to be ECN incapable. - pub ecn_paths_not_capable: usize, + /// ECN path validation count, indexed by validation outcome. + pub ecn_path_validation: ecn::ValidationCount, /// ECN counts for outgoing UDP datagrams, returned by remote through QUIC ACKs. /// /// Note: Given that QUIC ACKs only carry [`Ect0`], [`Ect1`] and [`Ce`], but @@ -209,9 +211,9 @@ pub struct Stats { /// [`Ect1`]: neqo_common::tos::IpTosEcn::Ect1 /// [`Ce`]: neqo_common::tos::IpTosEcn::Ce /// [`NotEct`]: neqo_common::tos::IpTosEcn::NotEct - pub ecn_tx: EcnCount, + pub ecn_tx: ecn::Count, /// ECN counts for incoming UDP datagrams, read from IP TOS header. - pub ecn_rx: EcnCount, + pub ecn_rx: ecn::Count, } impl Stats { @@ -222,8 +224,8 @@ impl Stats { pub fn pkt_dropped(&mut self, reason: impl AsRef) { self.dropped_rx += 1; qwarn!( - [self.info], - "Dropped received packet: {}; Total: {}", + "[{}] Dropped received packet: {}; Total: {}", + self.info, reason.as_ref(), self.dropped_rx ); @@ -261,8 +263,13 @@ impl Debug for Stats { )?; writeln!( f, - " pmtud: {} sent {} acked {} lost {} change", - self.pmtud_tx, self.pmtud_ack, self.pmtud_lost, self.pmtud_change + " pmtud: {} sent {} acked {} lost {} change {} iface_mtu {} pmtu", + self.pmtud_tx, + self.pmtud_ack, + self.pmtud_lost, + self.pmtud_change, + self.pmtud_iface_mtu, + self.pmtud_pmtu )?; writeln!(f, " resumed: {}", self.resumed)?; writeln!(f, " frames rx:")?; @@ -271,8 +278,8 @@ impl Debug for Stats { self.frame_tx.fmt(f)?; writeln!( f, - " ecn: {:?} for tx {:?} for rx {} capable paths {} not capable paths", - self.ecn_tx, self.ecn_rx, self.ecn_paths_capable, self.ecn_paths_not_capable + " ecn: {:?} for tx {:?} for rx {:?} path validation outcomes", + self.ecn_tx, self.ecn_rx, self.ecn_path_validation, ) } } diff --git a/third_party/rust/neqo-transport/src/stream_id.rs b/third_party/rust/neqo-transport/src/stream_id.rs index afd4bd8a3635..9768e1391bf6 100644 --- a/third_party/rust/neqo-transport/src/stream_id.rs +++ b/third_party/rust/neqo-transport/src/stream_id.rs @@ -104,6 +104,12 @@ impl StreamId { self.0 += 4; } + /// Return the stream index for this stream ID. + #[must_use] + pub const fn index(&self) -> u64 { + self.0 >> 2 + } + /// This returns a bit that is shared by all streams created by this role. #[must_use] pub const fn role_bit(role: Role) -> u64 { diff --git a/third_party/rust/neqo-transport/src/streams.rs b/third_party/rust/neqo-transport/src/streams.rs index eccd96a9e391..a79195ac72fc 100644 --- a/third_party/rust/neqo-transport/src/streams.rs +++ b/third_party/rust/neqo-transport/src/streams.rs @@ -183,7 +183,7 @@ impl Streams { } Frame::DataBlocked { data_limit } => { // Should never happen since we set data limit to max - qwarn!("Received DataBlocked with data limit {}", data_limit); + qwarn!("Received DataBlocked with data limit {data_limit}"); stats.data_blocked += 1; self.handle_data_blocked(); } @@ -202,10 +202,10 @@ impl Streams { } Frame::StreamsBlocked { .. } => { stats.streams_blocked += 1; - // We send an update evry time we retire a stream. There is no need to + // We send an update every time we retire a stream. There is no need to // trigger flow updates here. } - _ => unreachable!("This is not a stream Frame"), + _ => return Err(Error::InternalError), // This is not a stream frame. } Ok(()) } @@ -337,7 +337,7 @@ impl Streams { let (removed_bidi, removed_uni) = self.recv.clear_terminal(&self.send, self.role); // Send max_streams updates if we removed remote-initiated recv streams. - // The updates will be send if any steams has been removed. + // The updates will be send if any streams has been removed. self.remote_stream_limits[StreamType::BiDi].add_retired(removed_bidi); self.remote_stream_limits[StreamType::UniDi].add_retired(removed_uni); } @@ -405,15 +405,27 @@ impl Streams { /// indicated by its stream id. /// # Errors /// When the stream cannot be created due to stream limits. + /// When the stream is locally-initiated and has not existed. pub fn obtain_stream( &mut self, stream_id: StreamId, ) -> Res<(Option<&mut SendStream>, Option<&mut RecvStream>)> { self.ensure_created_if_remote(stream_id)?; - Ok(( - self.send.get_mut(stream_id).ok(), - self.recv.get_mut(stream_id).ok(), - )) + let ss = self.send.get_mut(stream_id).ok(); + let rs = self.recv.get_mut(stream_id).ok(); + // If it is: + // - neither a known send nor receive stream, + // - and it must be locally initiated, + // - and its index is larger than the local used stream limit, + // then it is an illegal stream. + if ss.is_none() + && rs.is_none() + && !stream_id.is_remote_initiated(self.role) + && self.local_stream_limits[stream_id.stream_type()].used() <= stream_id.index() + { + return Err(Error::StreamStateError); + } + Ok((ss, rs)) } /// # Errors diff --git a/third_party/rust/neqo-transport/src/tparams.rs b/third_party/rust/neqo-transport/src/tparams.rs index 7c8139f7b6b6..90796cdb0a0a 100644 --- a/third_party/rust/neqo-transport/src/tparams.rs +++ b/third_party/rust/neqo-transport/src/tparams.rs @@ -28,38 +28,27 @@ use crate::{ }; pub type TransportParameterId = u64; -macro_rules! tpids { - { $($n:ident = $v:expr),+ $(,)? } => { - $(pub const $n: TransportParameterId = $v as TransportParameterId;)+ - - /// A complete list of internal transport parameters. - #[cfg(not(test))] - pub(crate) const INTERNAL_TRANSPORT_PARAMETERS: &[TransportParameterId] = &[ $($n),+ ]; - }; - } -tpids! { - ORIGINAL_DESTINATION_CONNECTION_ID = 0x00, - IDLE_TIMEOUT = 0x01, - STATELESS_RESET_TOKEN = 0x02, - MAX_UDP_PAYLOAD_SIZE = 0x03, - INITIAL_MAX_DATA = 0x04, - INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 0x05, - INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = 0x06, - INITIAL_MAX_STREAM_DATA_UNI = 0x07, - INITIAL_MAX_STREAMS_BIDI = 0x08, - INITIAL_MAX_STREAMS_UNI = 0x09, - ACK_DELAY_EXPONENT = 0x0a, - MAX_ACK_DELAY = 0x0b, - DISABLE_MIGRATION = 0x0c, - PREFERRED_ADDRESS = 0x0d, - ACTIVE_CONNECTION_ID_LIMIT = 0x0e, - INITIAL_SOURCE_CONNECTION_ID = 0x0f, - RETRY_SOURCE_CONNECTION_ID = 0x10, - VERSION_INFORMATION = 0x11, - GREASE_QUIC_BIT = 0x2ab2, - MIN_ACK_DELAY = 0xff02_de1a, - MAX_DATAGRAM_FRAME_SIZE = 0x0020, -} +pub const ORIGINAL_DESTINATION_CONNECTION_ID: TransportParameterId = 0x00; +pub const IDLE_TIMEOUT: TransportParameterId = 0x01; +pub const STATELESS_RESET_TOKEN: TransportParameterId = 0x02; +pub const MAX_UDP_PAYLOAD_SIZE: TransportParameterId = 0x03; +pub const INITIAL_MAX_DATA: TransportParameterId = 0x04; +pub const INITIAL_MAX_STREAM_DATA_BIDI_LOCAL: TransportParameterId = 0x05; +pub const INITIAL_MAX_STREAM_DATA_BIDI_REMOTE: TransportParameterId = 0x06; +pub const INITIAL_MAX_STREAM_DATA_UNI: TransportParameterId = 0x07; +pub const INITIAL_MAX_STREAMS_BIDI: TransportParameterId = 0x08; +pub const INITIAL_MAX_STREAMS_UNI: TransportParameterId = 0x09; +pub const ACK_DELAY_EXPONENT: TransportParameterId = 0x0a; +pub const MAX_ACK_DELAY: TransportParameterId = 0x0b; +pub const DISABLE_MIGRATION: TransportParameterId = 0x0c; +pub const PREFERRED_ADDRESS: TransportParameterId = 0x0d; +pub const ACTIVE_CONNECTION_ID_LIMIT: TransportParameterId = 0x0e; +pub const INITIAL_SOURCE_CONNECTION_ID: TransportParameterId = 0x0f; +pub const RETRY_SOURCE_CONNECTION_ID: TransportParameterId = 0x10; +pub const VERSION_INFORMATION: TransportParameterId = 0x11; +pub const GREASE_QUIC_BIT: TransportParameterId = 0x2ab2; +pub const MIN_ACK_DELAY: TransportParameterId = 0xff02_de1a; +pub const MAX_DATAGRAM_FRAME_SIZE: TransportParameterId = 0x0020; #[derive(Clone, Debug)] pub struct PreferredAddress { @@ -139,7 +128,7 @@ pub enum TransportParameter { impl TransportParameter { fn encode(&self, enc: &mut Encoder, tp: TransportParameterId) { - qtrace!("TP encoded; type 0x{:02x} val {:?}", tp, self); + qtrace!("TP encoded; type 0x{tp:02x} val {self:?}"); enc.encode_varint(tp); match self { Self::Bytes(a) => { @@ -185,7 +174,7 @@ impl TransportParameter { fn decode_preferred_address(d: &mut Decoder) -> Res { // IPv4 address (maybe) let v4ip = Ipv4Addr::from(<[u8; 4]>::try_from(d.decode(4).ok_or(Error::NoMoreData)?)?); - let v4port = u16::try_from(d.decode_uint(2).ok_or(Error::NoMoreData)?)?; + let v4port = d.decode_uint::().ok_or(Error::NoMoreData)?; // Can't have non-zero IP and zero port, or vice versa. if v4ip.is_unspecified() ^ (v4port == 0) { return Err(Error::TransportParameterError); @@ -200,7 +189,7 @@ impl TransportParameter { let v6ip = Ipv6Addr::from(<[u8; 16]>::try_from( d.decode(16).ok_or(Error::NoMoreData)?, )?); - let v6port = u16::try_from(d.decode_uint(2).ok_or(Error::NoMoreData)?)?; + let v6port = d.decode_uint().ok_or(Error::NoMoreData)?; if v6ip.is_unspecified() ^ (v6port == 0) { return Err(Error::TransportParameterError); } @@ -216,7 +205,7 @@ impl TransportParameter { // Connection ID (non-zero length) let cid = ConnectionId::from(d.decode_vec(1).ok_or(Error::NoMoreData)?); - if cid.len() == 0 || cid.len() > MAX_CONNECTION_ID_LEN { + if cid.is_empty() || cid.len() > MAX_CONNECTION_ID_LEN { return Err(Error::TransportParameterError); } @@ -229,11 +218,11 @@ impl TransportParameter { fn decode_versions(dec: &mut Decoder) -> Res { fn dv(dec: &mut Decoder) -> Res { - let v = dec.decode_uint(4).ok_or(Error::NoMoreData)?; + let v = dec.decode_uint::().ok_or(Error::NoMoreData)?; if v == 0 { Err(Error::TransportParameterError) } else { - Ok(WireVersion::try_from(v)?) + Ok(v) } } @@ -250,7 +239,7 @@ impl TransportParameter { fn decode(dec: &mut Decoder) -> Res> { let tp = dec.decode_varint().ok_or(Error::NoMoreData)?; let content = dec.decode_vvec().ok_or(Error::NoMoreData)?; - qtrace!("TP {:x} length {:x}", tp, content.len()); + qtrace!("TP {tp:x} length {:x}", content.len()); let mut d = Decoder::from(content); let value = match tp { ORIGINAL_DESTINATION_CONNECTION_ID @@ -309,7 +298,7 @@ impl TransportParameter { if d.remaining() > 0 { return Err(Error::TooMuchData); } - qtrace!("TP decoded; type 0x{:02x} val {:?}", tp, value); + qtrace!("TP decoded; type 0x{tp:02x} val {value:?}"); Ok(Some((tp, value))) } } @@ -457,8 +446,7 @@ impl TransportParameters { let rbuf = random::<4>(); let mut other = Vec::with_capacity(versions.all().len() + 1); let mut dec = Decoder::new(&rbuf); - let grease = - (u32::try_from(dec.decode_uint(4).unwrap()).unwrap()) & 0xf0f0_f0f0 | 0x0a0a_0a0a; + let grease = dec.decode_uint::().unwrap() & 0xf0f0_f0f0 | 0x0a0a_0a0a; other.push(grease); for &v in versions.all() { if role == Role::Client && !versions.initial().is_compatible(v) { @@ -629,9 +617,7 @@ impl TransportParametersHandler { fn compatible_upgrade(&mut self, remote_tp: &TransportParameters) -> Res<()> { if let Some((current, other)) = remote_tp.get_versions() { qtrace!( - "Peer versions: {:x} {:x?}; config {:?}", - current, - other, + "Peer versions: {current:x} {other:x?}; config {:?}", self.versions, ); @@ -641,8 +627,7 @@ impl TransportParametersHandler { Ok(()) } else { qinfo!( - "Chosen version {:x} is not compatible with initial version {:x}", - current, + "Chosen version {current:x} is not compatible with initial version {:x}", self.versions.initial().wire_version(), ); Err(Error::TransportParameterError) @@ -650,8 +635,7 @@ impl TransportParametersHandler { } else { if current != self.versions.initial().wire_version() { qinfo!( - "Current version {:x} != own version {:x}", - current, + "Current version {current:x} != own version {:x}", self.versions.initial().wire_version(), ); return Err(Error::TransportParameterError); @@ -660,9 +644,8 @@ impl TransportParametersHandler { if let Some(preferred) = self.versions.preferred_compatible(other) { if preferred != self.versions.initial() { qinfo!( - "Compatible upgrade {:?} ==> {:?}", - self.versions.initial(), - preferred + "Compatible upgrade {:?} ==> {preferred:?}", + self.versions.initial() ); self.versions.set_initial(preferred); self.local.compatible_upgrade(preferred); @@ -685,7 +668,7 @@ impl ExtensionHandler for TransportParametersHandler { return ExtensionWriterResult::Skip; } - qdebug!("Writing transport parameters, msg={:?}", msg); + qdebug!("Writing transport parameters, msg={msg:?}"); // TODO(ekr@rtfm.com): Modify to avoid a copy. let mut enc = Encoder::default(); @@ -697,8 +680,7 @@ impl ExtensionHandler for TransportParametersHandler { fn handle(&mut self, msg: HandshakeMessage, d: &[u8]) -> ExtensionHandlerResult { qtrace!( - "Handling transport parameters, msg={:?} value={}", - msg, + "Handling transport parameters, msg={msg:?} value={}", hex(d), ); @@ -1056,9 +1038,9 @@ mod tests { for i in INTEGER_KEYS { let mut tps_b = tps_a.clone(); tps_b.remove(*i); - // A value that is missing from what is rememebered is OK. + // A value that is missing from what is remembered is OK. assert!(tps_a.ok_for_0rtt(&tps_b)); - // A value that is rememebered, but not current is not OK. + // A value that is remembered, but not current is not OK. assert!(!tps_b.ok_for_0rtt(&tps_a)); } } diff --git a/third_party/rust/neqo-transport/src/tracking.rs b/third_party/rust/neqo-transport/src/tracking.rs index 565b9bfd4d66..fb69644060a0 100644 --- a/third_party/rust/neqo-transport/src/tracking.rs +++ b/third_party/rust/neqo-transport/src/tracking.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tracking of received packets and generating acks thereof. +// Tracking of received packets and generating ACKs thereof. use std::{ cmp::min, @@ -18,7 +18,7 @@ use neqo_common::{qdebug, qinfo, qtrace, qwarn, IpTosEcn}; use neqo_crypto::{Epoch, TLS_EPOCH_HANDSHAKE, TLS_EPOCH_INITIAL}; use crate::{ - ecn::EcnCount, + ecn, frame::{FRAME_TYPE_ACK, FRAME_TYPE_ACK_ECN}, packet::{PacketBuilder, PacketNumber, PacketType}, recovery::RecoveryToken, @@ -86,14 +86,14 @@ impl PacketNumberSpaceSet { impl Index for PacketNumberSpaceSet { type Output = bool; - fn index(&self, space: PacketNumberSpace) -> &Self::Output { - &self.spaces[space] + fn index(&self, index: PacketNumberSpace) -> &Self::Output { + &self.spaces[index] } } impl IndexMut for PacketNumberSpaceSet { - fn index_mut(&mut self, space: PacketNumberSpace) -> &mut Self::Output { - &mut self.spaces[space] + fn index_mut(&mut self, index: PacketNumberSpace) -> &mut Self::Output { + &mut self.spaces[index] } } @@ -158,7 +158,7 @@ impl PacketRange { } } - /// Get the number of acknowleged packets in the range. + /// Get the number of acknowledged packets in the range. pub const fn len(&self) -> u64 { self.largest - self.smallest + 1 } @@ -180,12 +180,12 @@ impl PacketRange { assert!(!self.contains(pn)); // Only insert if this is adjacent the current range. if (self.largest + 1) == pn { - qtrace!([self], "Adding largest {}", pn); + qtrace!("[{self}] Adding largest {pn}"); self.largest += 1; self.ack_needed = true; InsertionResult::Largest } else if self.smallest == (pn + 1) { - qtrace!([self], "Adding smallest {}", pn); + qtrace!("[{self}] Adding smallest {pn}"); self.smallest -= 1; self.ack_needed = true; InsertionResult::Smallest @@ -196,7 +196,7 @@ impl PacketRange { /// Maybe merge a higher-numbered range into this. fn merge_larger(&mut self, other: &Self) { - qinfo!([self], "Merging {}", other); + qinfo!("[{self}] Merging {other}"); // This only works if they are immediately adjacent. assert_eq!(self.largest + 1, other.smallest); @@ -271,7 +271,7 @@ pub struct RecvdPackets { /// for the purposes of generating immediate acknowledgment. ignore_order: bool, // The counts of different ECN marks that have been received. - ecn_count: EcnCount, + ecn_count: ecn::Count, } impl RecvdPackets { @@ -294,12 +294,12 @@ impl RecvdPackets { 0 }, ignore_order: false, - ecn_count: EcnCount::default(), + ecn_count: ecn::Count::default(), } } /// Get the ECN counts. - pub fn ecn_marks(&mut self) -> &mut EcnCount { + pub fn ecn_marks(&mut self) -> &mut ecn::Count { &mut self.ecn_count } @@ -369,10 +369,10 @@ impl RecvdPackets { if self.ranges.len() > MAX_TRACKED_RANGES { let oldest = self.ranges.pop_back().unwrap(); if oldest.ack_needed { - qwarn!([self], "Dropping unacknowledged ACK range: {}", oldest); + qwarn!("[{self}] Dropping unacknowledged ACK range: {oldest}"); // TODO(mt) Record some statistics about this so we can tune MAX_TRACKED_RANGES. } else { - qdebug!([self], "Drop ACK range: {}", oldest); + qdebug!("[{self}] Drop ACK range: {oldest}"); } self.min_tracked = oldest.largest + 1; } @@ -382,7 +382,7 @@ impl RecvdPackets { /// Return true if the packet was the largest received so far. pub fn set_received(&mut self, now: Instant, pn: PacketNumber, ack_eliciting: bool) -> bool { let next_in_order_pn = self.ranges.front().map_or(0, |r| r.largest + 1); - qtrace!([self], "received {}, next: {}", pn, next_in_order_pn); + qtrace!("[{self}] received {pn}, next: {next_in_order_pn}"); self.add(pn); self.trim_ranges(); @@ -413,7 +413,7 @@ impl RecvdPackets { // of the change is very small. self.ack_time.unwrap_or_else(|| now + self.ack_delay) }; - qdebug!([self], "Set ACK timer to {:?}", ack_time); + qdebug!("[{self}] Set ACK timer to {ack_time:?}"); self.ack_time = Some(ack_time); } largest @@ -422,7 +422,7 @@ impl RecvdPackets { /// If we just received a PING frame, we should immediately acknowledge. pub fn immediate_ack(&mut self, now: Instant) { self.ack_time = Some(now); - qdebug!([self], "immediate_ack at {:?}", now); + qdebug!("[{self}] immediate_ack at {now:?}"); } /// Check if the packet is a duplicate. @@ -601,7 +601,7 @@ impl AckTracker { #[cfg(debug_assertions)] for (space, recvd) in &self.spaces { if let Some(recvd) = recvd { - qtrace!("ack_time for {} = {:?}", space, recvd.ack_time()); + qtrace!("ack_time for {space} = {:?}", recvd.ack_time()); } } @@ -1062,7 +1062,7 @@ mod tests { assert_eq!(stats.ack, 1); let mut dec = builder.as_decoder(); - _ = dec.decode_byte().unwrap(); // Skip the short header. + dec.skip(1); // Skip the short header. let frame = Frame::decode(&mut dec).unwrap(); if let Frame::Ack { ack_ranges, .. } = frame { assert_eq!(ack_ranges.len(), 0); diff --git a/third_party/rust/neqo-transport/src/version.rs b/third_party/rust/neqo-transport/src/version.rs index 2aee6b9acaa2..34fd3d543872 100644 --- a/third_party/rust/neqo-transport/src/version.rs +++ b/third_party/rust/neqo-transport/src/version.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(clippy::module_name_repetitions)] + use neqo_common::qdebug; use crate::{Error, Res}; @@ -15,10 +17,8 @@ pub enum Version { Version2, #[default] Version1, + #[cfg(feature = "draft-29")] Draft29, - Draft30, - Draft31, - Draft32, } impl Version { @@ -27,10 +27,8 @@ impl Version { match self { Self::Version2 => 0x6b33_43cf, Self::Version1 => 1, + #[cfg(feature = "draft-29")] Self::Draft29 => 0xff00_0000 + 29, - Self::Draft30 => 0xff00_0000 + 30, - Self::Draft31 => 0xff00_0000 + 31, - Self::Draft32 => 0xff00_0000 + 32, } } @@ -43,6 +41,7 @@ impl Version { 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a, ]; + #[cfg(feature = "draft-29")] const INITIAL_SALT_29_32: &[u8] = &[ 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99, @@ -50,16 +49,17 @@ impl Version { match self { Self::Version2 => INITIAL_SALT_V2, Self::Version1 => INITIAL_SALT_V1, - Self::Draft29 | Self::Draft30 | Self::Draft31 | Self::Draft32 => INITIAL_SALT_29_32, + #[cfg(feature = "draft-29")] + Self::Draft29 => INITIAL_SALT_29_32, } } pub(crate) const fn label_prefix(self) -> &'static str { match self { Self::Version2 => "quicv2 ", - Self::Version1 | Self::Draft29 | Self::Draft30 | Self::Draft31 | Self::Draft32 => { - "quic " - } + Self::Version1 => "quic ", + #[cfg(feature = "draft-29")] + Self::Draft29 => "quic ", } } @@ -74,6 +74,7 @@ impl Version { 0x81, 0x4c, 0x73, 0x03, 0x0f, 0x25, 0xc7, 0x9d, 0x71, 0xce, 0x87, 0x6e, 0xca, 0x87, 0x6e, 0x6f, 0xca, 0x8e, ]; + #[cfg(feature = "draft-29")] const RETRY_SECRET_29: &[u8] = &[ 0x8b, 0x0d, 0x37, 0xeb, 0x85, 0x35, 0x02, 0x2e, 0xbc, 0x8d, 0x76, 0xa2, 0x07, 0xd8, 0x0d, 0xf2, 0x26, 0x46, 0xec, 0x06, 0xdc, 0x80, 0x96, 0x42, 0xc3, 0x0a, 0x8b, 0xaa, @@ -82,15 +83,17 @@ impl Version { match self { Self::Version2 => RETRY_SECRET_V2, Self::Version1 => RETRY_SECRET_V1, - Self::Draft29 | Self::Draft30 | Self::Draft31 | Self::Draft32 => RETRY_SECRET_29, + #[cfg(feature = "draft-29")] + Self::Draft29 => RETRY_SECRET_29, } } + #[allow(clippy::unused_self)] // `self` only used in feature-gated code pub(crate) const fn is_draft(self) -> bool { - matches!( - self, - Self::Draft29 | Self::Draft30 | Self::Draft31 | Self::Draft32, - ) + #[cfg(feature = "draft-29")] + return matches!(self, Self::Draft29); + #[cfg(not(feature = "draft-29"))] + false } /// Determine if `self` can be upgraded to `other` compatibly. @@ -108,9 +111,7 @@ impl Version { vec![ Self::Version2, Self::Version1, - Self::Draft32, - Self::Draft31, - Self::Draft30, + #[cfg(feature = "draft-29")] Self::Draft29, ] } @@ -131,15 +132,11 @@ impl TryFrom for Version { Ok(Self::Version1) } else if wire == 0x6b33_43cf { Ok(Self::Version2) - } else if wire == 0xff00_0000 + 29 { - Ok(Self::Draft29) - } else if wire == 0xff00_0000 + 30 { - Ok(Self::Draft30) - } else if wire == 0xff00_0000 + 31 { - Ok(Self::Draft31) - } else if wire == 0xff00_0000 + 32 { - Ok(Self::Draft32) } else { + #[cfg(feature = "draft-29")] + if wire == 0xff00_0000 + 29 { + return Ok(Self::Draft29); + } Err(Error::VersionNegotiation) } } @@ -194,9 +191,8 @@ impl VersionConfig { /// and by the client on resumption. pub(crate) fn set_initial(&mut self, initial: Version) { qdebug!( - "Overwrite initial version {:?} ==> {:?}", - self.initial, - initial + "Overwrite initial version {:?} ==> {initial:?}", + self.initial ); assert!(self.all.contains(&initial)); self.initial = initial; diff --git a/third_party/rust/neqo-transport/tests/common/mod.rs b/third_party/rust/neqo-transport/tests/common/mod.rs index a16c5f2c9267..f8b9c98d6ae9 100644 --- a/third_party/rust/neqo-transport/tests/common/mod.rs +++ b/third_party/rust/neqo-transport/tests/common/mod.rs @@ -8,7 +8,7 @@ use std::{cell::RefCell, mem, ops::Range, rc::Rc}; -use neqo_common::{event::Provider, hex_with_len, qtrace, Datagram, Decoder, Role}; +use neqo_common::{event::Provider as _, hex_with_len, qtrace, Datagram, Decoder, Role}; use neqo_crypto::{ constants::{TLS_AES_128_GCM_SHA256, TLS_VERSION_1_3}, hkdf, @@ -112,7 +112,7 @@ pub fn generate_ticket(server: &mut Server) -> ResumptionToken { // Have the client close the connection and then let the server clean up. client.close(now(), 0, "got a ticket"); let out = client.process_output(now()); - mem::drop(server.process(out.dgram(), now())); + drop(server.process(out.dgram(), now())); // Calling active_connections clears the set of active connections. assert_eq!(server.active_connections().len(), 1); ticket diff --git a/third_party/rust/neqo-transport/tests/connection.rs b/third_party/rust/neqo-transport/tests/connection.rs index fcbcf228e5e0..12b4829732ed 100644 --- a/third_party/rust/neqo-transport/tests/connection.rs +++ b/third_party/rust/neqo-transport/tests/connection.rs @@ -283,8 +283,8 @@ fn handshake_mlkem768x25519() { client .set_groups(&[neqo_crypto::TLS_GRP_KEM_MLKEM768X25519]) - .ok(); - client.send_additional_key_shares(0).ok(); + .unwrap(); + client.send_additional_key_shares(0).unwrap(); test_fixture::handshake(&mut client, &mut server); assert_eq!(*client.state(), State::Confirmed); diff --git a/third_party/rust/neqo-transport/tests/retry.rs b/third_party/rust/neqo-transport/tests/retry.rs index 36325be2e117..99abfd96b912 100644 --- a/third_party/rust/neqo-transport/tests/retry.rs +++ b/third_party/rust/neqo-transport/tests/retry.rs @@ -9,7 +9,6 @@ mod common; use std::{ - mem, net::{IpAddr, Ipv4Addr, SocketAddr}, time::Duration, }; @@ -37,16 +36,14 @@ fn retry_basic() { let dgram = client.process_output(now()).dgram(); // Initial assert!(dgram.is_some()); - let dgram = server.process(dgram, now()).dgram(); // Retry - assert!(dgram.is_some()); + let dgram = server.process(dgram, now()).dgram().unwrap(); // Retry + assertions::assert_retry(&dgram); - assertions::assert_retry(dgram.as_ref().unwrap()); - - let dgram = client.process(dgram, now()).dgram(); // Initial w/token + let dgram = client.process(Some(dgram), now()).dgram(); // Initial w/token assert!(dgram.is_some()); let dgram = server.process(dgram, now()).dgram(); // Initial, HS assert!(dgram.is_some()); - mem::drop(client.process(dgram, now()).dgram()); // Ingest, drop any ACK. + drop(client.process(dgram, now()).dgram()); // Ingest, drop any ACK. client.authenticated(AuthenticationStatus::Ok, now()); let dgram = client.process_output(now()).dgram(); // Send Finished assert!(dgram.is_some()); diff --git a/third_party/rust/neqo-transport/tests/server.rs b/third_party/rust/neqo-transport/tests/server.rs index 12078a896012..c0a10b9afb52 100644 --- a/third_party/rust/neqo-transport/tests/server.rs +++ b/third_party/rust/neqo-transport/tests/server.rs @@ -6,7 +6,7 @@ mod common; -use std::{cell::RefCell, mem, net::SocketAddr, rc::Rc, time::Duration}; +use std::{cell::RefCell, net::SocketAddr, rc::Rc, time::Duration}; use common::{connect, connected_server, default_server, find_ticket, generate_ticket, new_server}; use neqo_common::{qtrace, Datagram, Decoder, Encoder, Role}; @@ -15,6 +15,7 @@ use neqo_crypto::{ }; use neqo_transport::{ server::{ConnectionRef, Server, ValidateAddress}, + version::WireVersion, CloseReason, Connection, ConnectionParameters, Error, Output, State, StreamType, Version, MIN_INITIAL_PACKET_SIZE, }; @@ -226,7 +227,7 @@ fn drop_non_initial() { let mut server = default_server(); // This is big enough to look like an Initial, but it uses the Retry type. - let mut header = neqo_common::Encoder::with_capacity(MIN_INITIAL_PACKET_SIZE); + let mut header = Encoder::with_capacity(MIN_INITIAL_PACKET_SIZE); header .encode_byte(0xfa) .encode_uint(4, Version::default().wire_version()) @@ -245,7 +246,7 @@ fn drop_short_initial() { let mut server = default_server(); // This too small to be an Initial, but it is otherwise plausible. - let mut header = neqo_common::Encoder::with_capacity(1199); + let mut header = Encoder::with_capacity(1199); header .encode_byte(0xca) .encode_uint(4, Version::default().wire_version()) @@ -263,7 +264,7 @@ fn drop_short_header_packet_for_unknown_connection() { const CID: &[u8] = &[55; 8]; // not a real connection ID let mut server = default_server(); - let mut header = neqo_common::Encoder::with_capacity(MIN_INITIAL_PACKET_SIZE); + let mut header = Encoder::with_capacity(MIN_INITIAL_PACKET_SIZE); header .encode_byte(0x40) // short header .encode_vec(1, CID) @@ -317,12 +318,12 @@ fn zero_rtt() { let c4 = client_send(); // 0-RTT packets that arrive before the handshake get dropped. - mem::drop(server.process(Some(c2), now)); + drop(server.process(Some(c2), now)); assert!(server.active_connections().is_empty()); // Now handshake and let another 0-RTT packet in. let shs = server.process(Some(c1), now); - mem::drop(server.process(Some(c3), now)); + drop(server.process(Some(c3), now)); // The server will have received two STREAM frames now if it processed both packets. // `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable types. #[allow(clippy::mutable_key_type)] @@ -344,10 +345,10 @@ fn zero_rtt() { // a little so that the pacer doesn't prevent the Finished from being sent. now += now - start_time; let cfin = client.process(shs.dgram(), now); - mem::drop(server.process(cfin.dgram(), now)); + drop(server.process(cfin.dgram(), now)); // The server will drop this last 0-RTT packet. - mem::drop(server.process(Some(c4), now)); + drop(server.process(Some(c4), now)); // `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable types. #[allow(clippy::mutable_key_type)] let active = server.active_connections(); @@ -584,13 +585,13 @@ fn version_negotiation_ignored() { let vn = vn.expect("a vn packet"); let mut dec = Decoder::from(&vn[1..]); // Skip first byte. - assert_eq!(dec.decode_uint(4).expect("VN"), 0); + assert_eq!(dec.decode_uint::().expect("VN"), 0); assert_eq!(dec.decode_vec(1).expect("VN DCID"), &s_cid[..]); assert_eq!(dec.decode_vec(1).expect("VN SCID"), &d_cid[..]); let mut found = false; while dec.remaining() > 0 { - let v = dec.decode_uint(4).expect("supported version"); - found |= v == u64::from(Version::default().wire_version()); + let v = dec.decode_uint::().expect("supported version"); + found |= v == Version::default().wire_version(); } assert!(found, "valid version not found"); diff --git a/third_party/rust/neqo-transport/tests/stats.rs b/third_party/rust/neqo-transport/tests/stats.rs new file mode 100644 index 000000000000..c8e6e657f28e --- /dev/null +++ b/third_party/rust/neqo-transport/tests/stats.rs @@ -0,0 +1,16 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use neqo_transport::ecn; + +#[test] +fn crate_exports_ecn_types() { + let stats = neqo_transport::Stats::default(); + + let _ = stats.ecn_path_validation[ecn::ValidationOutcome::Capable]; + let _ = stats.ecn_path_validation + [ecn::ValidationOutcome::NotCapable(ecn::ValidationError::BlackHole)]; +} diff --git a/third_party/rust/neqo-udp/.cargo-checksum.json b/third_party/rust/neqo-udp/.cargo-checksum.json index 438a20641c17..eff0a0be8327 100644 --- a/third_party/rust/neqo-udp/.cargo-checksum.json +++ b/third_party/rust/neqo-udp/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c605ebe475e9b580222d62c7e7fd59f48a895246ef70e96c4c0faf47f50d3a4a","src/lib.rs":"936f18d22f2ea61d7becf2a714db130fea4fdc39d3d3b3f07cbf5bb867b0c42f"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"e86c1ff07abe947e7867908b4be1d468068b835b73891afeb5431bd4e6a42147","build.rs":"bf57cd35a78f636c14c442c1926abc2deca3d137e9d207e4f2f960f5b8363b07","src/lib.rs":"d1de86e723ef81ce11483dd205bc940a6c049f992311f44840548827118e923f"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-udp/Cargo.toml b/third_party/rust/neqo-udp/Cargo.toml index 4dc7224490ef..35d20ee9c3dd 100644 --- a/third_party/rust/neqo-udp/Cargo.toml +++ b/third_party/rust/neqo-udp/Cargo.toml @@ -13,9 +13,9 @@ edition = "2021" rust-version = "1.76.0" name = "neqo-udp" -version = "0.11.0" +version = "0.12.2" authors = ["The Neqo Authors "] -build = false +build = "build.rs" autolib = false autobins = false autoexamples = false @@ -56,11 +56,35 @@ path = "./../neqo-common" [dependencies.quinn-udp] version = "0.5.6" -features = ["direct-log"] +features = [ + "direct-log", + "fast-apple-datapath", +] default-features = false +[build-dependencies] +cfg_aliases = "0.2" + +[features] +bench = ["neqo-common/bench"] + [lints.clippy] +cfg_not_test = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" multiple_crate_versions = "allow" +multiple_inherent_impl = "warn" +pathbuf_init_then_push = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +semicolon_inside_block = "warn" +try_err = "warn" +unneeded_field_pattern = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" [lints.clippy.cargo] level = "warn" @@ -73,3 +97,19 @@ priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 + +[lints.rust] +absolute_paths_not_starting_with_crate = "warn" +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +explicit_outlives_requirements = "warn" +macro_use_extern_crate = "warn" +missing_abi = "warn" +non_ascii_idents = "warn" +redundant_imports = "warn" +redundant_lifetimes = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" diff --git a/third_party/rust/neqo-udp/build.rs b/third_party/rust/neqo-udp/build.rs new file mode 100644 index 000000000000..c0ad7df7b3e4 --- /dev/null +++ b/third_party/rust/neqo-udp/build.rs @@ -0,0 +1,16 @@ +use cfg_aliases::cfg_aliases; + +fn main() { + // Setup cfg aliases + cfg_aliases! { + // Platforms + apple: { + any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "visionos" + ) + }, + } +} diff --git a/third_party/rust/neqo-udp/src/lib.rs b/third_party/rust/neqo-udp/src/lib.rs index 61f7fa1ca245..615f62cdf4c8 100644 --- a/third_party/rust/neqo-udp/src/lib.rs +++ b/third_party/rust/neqo-udp/src/lib.rs @@ -7,20 +7,56 @@ #![allow(clippy::missing_errors_doc)] // Functions simply delegate to tokio and quinn-udp. use std::{ + array, io::{self, IoSliceMut}, + iter, net::SocketAddr, slice::{self, Chunks}, }; +use log::{log_enabled, Level}; use neqo_common::{qdebug, qtrace, Datagram, IpTos}; use quinn_udp::{EcnCodepoint, RecvMeta, Transmit, UdpSocketState}; -/// Socket receive buffer size. +/// Receive buffer size /// -/// Allows reading multiple datagrams in a single [`Socket::recv`] call. -// -// TODO: Experiment with different values across platforms. -pub const RECV_BUF_SIZE: usize = u16::MAX as usize; +/// Fits a maximum size UDP datagram, or, on platforms with segmentation +/// offloading, multiple smaller datagrams. +const RECV_BUF_SIZE: usize = u16::MAX as usize; + +/// The number of buffers to pass to the OS on [`Socket::recv`]. +/// +/// Platforms without segmentation offloading, i.e. platforms not able to read +/// multiple datagrams into a single buffer, can benefit from using multiple +/// buffers instead. +/// +/// Platforms with segmentation offloading have not shown performance +/// improvements when additionally using multiple buffers. +/// +/// - Linux/Android: use segmentation offloading via GRO +/// - Windows: use segmentation offloading via URO (caveat see ) +/// - Apple: no segmentation offloading available, use multiple buffers +#[cfg(not(apple))] +const NUM_BUFS: usize = 1; +#[cfg(apple)] +// Value approximated based on neqo-bin "Download" benchmark only. +const NUM_BUFS: usize = 16; + +/// A UDP receive buffer. +pub struct RecvBuf(Vec>); + +impl RecvBuf { + #[must_use] + pub fn new() -> Self { + Self(vec![vec![0; RECV_BUF_SIZE]; NUM_BUFS]) + } +} + +impl Default for RecvBuf { + fn default() -> Self { + Self::new() + } +} pub fn send_inner( state: &UdpSocketState, @@ -52,88 +88,97 @@ use std::os::fd::AsFd as SocketRef; #[cfg(windows)] use std::os::windows::io::AsSocket as SocketRef; +#[allow(clippy::missing_panics_doc)] pub fn recv_inner<'a>( local_address: SocketAddr, state: &UdpSocketState, socket: impl SocketRef, - recv_buf: &'a mut [u8], + recv_buf: &'a mut RecvBuf, ) -> Result, io::Error> { - let mut meta; - - let data = loop { - meta = RecvMeta::default(); - - state.recv( - (&socket).into(), - &mut [IoSliceMut::new(recv_buf)], - slice::from_mut(&mut meta), - )?; - - if meta.len == 0 || meta.stride == 0 { - qdebug!( - "ignoring datagram from {} to {} len {} stride {}", - meta.addr, - local_address, - meta.len, - meta.stride - ); - continue; - } - - break &recv_buf[..meta.len]; + let mut metas = [RecvMeta::default(); NUM_BUFS]; + let mut iovs: [IoSliceMut; NUM_BUFS] = { + let mut bufs = recv_buf.0.iter_mut().map(|b| IoSliceMut::new(b)); + array::from_fn(|_| bufs.next().expect("NUM_BUFS elements")) }; - qtrace!( - "received {} bytes from {} to {} in {} segments", - data.len(), - meta.addr, - local_address, - data.len().div_ceil(meta.stride), - ); + let n = state.recv((&socket).into(), &mut iovs, &mut metas)?; + + if log_enabled!(Level::Trace) { + for meta in metas.iter().take(n) { + qtrace!( + "received {} bytes from {} to {local_address} in {} segments", + meta.len, + meta.addr, + if meta.stride == 0 { + 0 + } else { + meta.len.div_ceil(meta.stride) + } + ); + } + } Ok(DatagramIter { - meta, - datagrams: data.chunks(meta.stride), + current_buffer: None, + remaining_buffers: metas.into_iter().zip(recv_buf.0.iter()).take(n), local_address, }) } pub struct DatagramIter<'a> { - meta: RecvMeta, - datagrams: Chunks<'a, u8>, + /// The current buffer, containing zero or more datagrams, each sharing the + /// same [`RecvMeta`]. + current_buffer: Option<(RecvMeta, Chunks<'a, u8>)>, + /// Remaining buffers, each containing zero or more datagrams, one + /// [`RecvMeta`] per buffer. + remaining_buffers: + iter::Take, slice::Iter<'a, Vec>>>, + /// The local address of the UDP socket used to receive the datagrams. local_address: SocketAddr, } -impl std::fmt::Debug for DatagramIter<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("DatagramIter") - .field("meta", &self.meta) - .field("local_address", &self.local_address) - .finish() - } -} - impl<'a> Iterator for DatagramIter<'a> { type Item = Datagram<&'a [u8]>; fn next(&mut self) -> Option { - self.datagrams.next().map(|d| { - Datagram::from_slice( - self.meta.addr, - self.local_address, - self.meta - .ecn - .map(|n| IpTos::from(n as u8)) - .unwrap_or_default(), - d, - ) - }) - } -} + loop { + // Return the next datagram in the current buffer, if any. + if let Some((meta, d)) = self + .current_buffer + .as_mut() + .and_then(|(meta, ds)| ds.next().map(|d| (meta, d))) + { + return Some(Datagram::from_slice( + meta.addr, + self.local_address, + meta.ecn.map(|n| IpTos::from(n as u8)).unwrap_or_default(), + d, + )); + } -impl ExactSizeIterator for DatagramIter<'_> { - fn len(&self) -> usize { - self.datagrams.len() + // There are no more datagrams in the current buffer. Try promoting + // one of the remaining buffers, if any, to be the current buffer. + let Some((meta, buf)) = self.remaining_buffers.next() else { + // Handled all buffers. No more datagrams. Iterator is empty. + return None; + }; + + // Ignore empty datagrams. + if meta.len == 0 || meta.stride == 0 { + qdebug!( + "ignoring empty datagram from {} to {} len {} stride {}", + meta.addr, + self.local_address, + meta.len, + meta.stride + ); + continue; + } + + // Got another buffer. Let's chunk it into datagrams and return the + // first datagram in the next loop iteration. + self.current_buffer = Some((meta, buf[0..meta.len].chunks(meta.stride))); + } } } @@ -147,7 +192,7 @@ impl Socket { /// Create a new [`Socket`] given a raw file descriptor managed externally. pub fn new(socket: S) -> Result { Ok(Self { - state: quinn_udp::UdpSocketState::new((&socket).into())?, + state: UdpSocketState::new((&socket).into())?, inner: socket, }) } @@ -162,7 +207,7 @@ impl Socket { pub fn recv<'a>( &self, local_address: SocketAddr, - recv_buf: &'a mut [u8], + recv_buf: &'a mut RecvBuf, ) -> Result, io::Error> { recv_inner(local_address, &self.state, &self.inner, recv_buf) } @@ -182,22 +227,19 @@ mod tests { } #[test] - fn ignore_empty_datagram() -> Result<(), io::Error> { - let sender = socket()?; - let receiver = Socket::new(std::net::UdpSocket::bind("127.0.0.1:0")?)?; + fn handle_empty_datagram() -> Result<(), io::Error> { + // quinn-udp doesn't support sending emtpy datagrams across all + // platforms. Use `std` socket instead. See also + // . + let sender = std::net::UdpSocket::bind("127.0.0.1:0")?; + let receiver = socket()?; let receiver_addr: SocketAddr = "127.0.0.1:0".parse().unwrap(); - let datagram = Datagram::new( - sender.inner.local_addr()?, - receiver.inner.local_addr()?, - IpTos::default(), - vec![], - ); + sender.send_to(&[], receiver.inner.local_addr()?)?; + let mut recv_buf = RecvBuf::new(); + let mut datagrams = receiver.recv(receiver_addr, &mut recv_buf)?; - sender.send(&datagram)?; - let mut recv_buf = vec![0; RECV_BUF_SIZE]; - let res = receiver.recv(receiver_addr, &mut recv_buf); - assert_eq!(res.unwrap_err().kind(), std::io::ErrorKind::WouldBlock); + assert_eq!(datagrams.next(), None); Ok(()) } @@ -217,7 +259,7 @@ mod tests { sender.send(&datagram)?; - let mut recv_buf = vec![0; RECV_BUF_SIZE]; + let mut recv_buf = RecvBuf::new(); let mut received_datagrams = receiver .recv(receiver_addr, &mut recv_buf) .expect("receive to succeed"); @@ -260,7 +302,7 @@ mod tests { // Allow for one GSO sendmmsg to result in multiple GRO recvmmsg. let mut num_received = 0; - let mut recv_buf = vec![0; RECV_BUF_SIZE]; + let mut recv_buf = RecvBuf::new(); while num_received < max_gso_segments { receiver .recv(receiver_addr, &mut recv_buf) @@ -269,7 +311,7 @@ mod tests { assert_eq!( SEGMENT_SIZE, d.len(), - "Expect received datagrams to have same length as sent datagrams." + "Expect received datagrams to have same length as sent datagrams" ); num_received += 1; }); @@ -277,20 +319,4 @@ mod tests { Ok(()) } - - #[test] - fn fmt_datagram_iter() { - let dgrams = []; - - let i = DatagramIter { - meta: RecvMeta::default(), - datagrams: dgrams.chunks(1), - local_address: "[::]:0".parse().unwrap(), - }; - - assert_eq!( - &format!("{i:?}"), - "DatagramIter { meta: RecvMeta { addr: [::]:0, len: 0, stride: 0, ecn: None, dst_ip: None }, local_address: [::]:0 }" - ); - } } diff --git a/third_party/rust/quinn-udp/.cargo-checksum.json b/third_party/rust/quinn-udp/.cargo-checksum.json index 37b14c881bd2..21b252285082 100644 --- a/third_party/rust/quinn-udp/.cargo-checksum.json +++ b/third_party/rust/quinn-udp/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"739bf78e6b796c0d89224ba2bbed4350a16536fc1ebac928c018dbdee46a3686","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04","benches/throughput.rs":"095137508f85b68174978ff968cade74587751484402ca09269ffc2631d97f34","build.rs":"f15147312964f6a6dfc1a3b3d9645022c14a7be8bdb9bd321afc9a218235b431","src/cmsg/mod.rs":"63d6ea7126341fededdaef14260a7eed715ad3f507d4da586dbab814f581a54d","src/cmsg/unix.rs":"7917bce2f3c8e844eca2e4cfea82669b2a31cf311321dc42532626db4ee42de8","src/cmsg/windows.rs":"6fb936ec4a283efc5796872e777441e3039c40589073865644a8ef7936af4f4b","src/fallback.rs":"6378c177db7ba0eb88115b63f1ec9e17b05f53b1daae2c1e215520f103145585","src/lib.rs":"3c20f8012db32df03acb8b76094ce3f86f112159adf5e51ac9e2e9dec86516f1","src/unix.rs":"6583182c85cdaf7e1232332d161e4e537a3ea66b33604634daeba87df337dd9d","src/windows.rs":"09554e6b40fae544c1985b04dbe402454e0591877df243b10e86ff780a92aa1b","tests/tests.rs":"babb0fc08884958203b2a0546647e44a67f6b457fe2784935e32d73becb20f4c"},"package":"1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904"} \ No newline at end of file +{"files":{"Cargo.lock":"9fc873d0855dcb2bd5547c54d24631c95aebf9418432d6703d34c7dc7f20c54b","Cargo.toml":"f8746c995acf25451d3760b5ca5936f39cc19e99e7afebcf3d42688ca5b5627a","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04","benches/throughput.rs":"095137508f85b68174978ff968cade74587751484402ca09269ffc2631d97f34","build.rs":"1d7ecadda4a26fb0eba598789eef9b99a1b4febba9bcb61a34f0c92b1d1bbaeb","src/cmsg/mod.rs":"63d6ea7126341fededdaef14260a7eed715ad3f507d4da586dbab814f581a54d","src/cmsg/unix.rs":"b13d36e757eef3038303e9429573ca29c31aff406592514c304bba73e1bff22f","src/cmsg/windows.rs":"6fb936ec4a283efc5796872e777441e3039c40589073865644a8ef7936af4f4b","src/fallback.rs":"6378c177db7ba0eb88115b63f1ec9e17b05f53b1daae2c1e215520f103145585","src/lib.rs":"ff2012fc0733e0cf98970a50c2ed988e9f2564a3de1baf6f0f532d36fd1ad8bb","src/unix.rs":"6583182c85cdaf7e1232332d161e4e537a3ea66b33604634daeba87df337dd9d","src/windows.rs":"a41c5b9d45938b4cfc0f8e386ec32bb4843ddc801185f25cb0abae8c82b7155f","tests/tests.rs":"babb0fc08884958203b2a0546647e44a67f6b457fe2784935e32d73becb20f4c"},"package":"e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944"} \ No newline at end of file diff --git a/third_party/rust/quinn-udp/Cargo.lock b/third_party/rust/quinn-udp/Cargo.lock new file mode 100644 index 000000000000..d414ddc98456 --- /dev/null +++ b/third_party/rust/quinn-udp/Cargo.lock @@ -0,0 +1,660 @@ +# This file is automatically @generated by Cargo. +# 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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "futures", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "tokio", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[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-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "is-terminal" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "log" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[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.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quinn-udp" +version = "0.5.10" +dependencies = [ + "cfg_aliases", + "criterion", + "libc", + "log", + "once_cell", + "socket2", + "tokio", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "ryu" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tokio" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +dependencies = [ + "backtrace", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/third_party/rust/quinn-udp/Cargo.toml b/third_party/rust/quinn-udp/Cargo.toml index ac15d69b1798..f7d42922cba5 100644 --- a/third_party/rust/quinn-udp/Cargo.toml +++ b/third_party/rust/quinn-udp/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.71" name = "quinn-udp" -version = "0.5.9" +version = "0.5.10" build = "build.rs" autolib = false autobins = false @@ -54,9 +54,6 @@ version = "0.2.158" version = "0.4" optional = true -[dependencies.socket2] -version = "0.5" - [dependencies.tracing] version = "0.1.10" features = ["std"] @@ -89,6 +86,9 @@ direct-log = ["dep:log"] fast-apple-datapath = [] log = ["tracing/log"] +[target.'cfg(not(all(target_family = "wasm", target_os = "unknown")))'.dependencies.socket2] +version = "0.5" + [target."cfg(windows)".dependencies.once_cell] version = "1.19" diff --git a/third_party/rust/quinn-udp/build.rs b/third_party/rust/quinn-udp/build.rs index d9893ed9483e..c43c0aa34249 100644 --- a/third_party/rust/quinn-udp/build.rs +++ b/third_party/rust/quinn-udp/build.rs @@ -28,5 +28,6 @@ fn main() { // Convenience aliases apple_fast: { all(apple, feature = "fast-apple-datapath") }, apple_slow: { all(apple, not(feature = "fast-apple-datapath")) }, + wasm_browser: { all(target_family = "wasm", target_os = "unknown") }, } } diff --git a/third_party/rust/quinn-udp/src/cmsg/unix.rs b/third_party/rust/quinn-udp/src/cmsg/unix.rs index 93ac76ba8016..69b01756e02c 100644 --- a/third_party/rust/quinn-udp/src/cmsg/unix.rs +++ b/third_party/rust/quinn-udp/src/cmsg/unix.rs @@ -43,7 +43,18 @@ impl MsgHdr for crate::imp::msghdr_x { fn cmsg_nxt_hdr(&self, cmsg: &Self::ControlMessage) -> *mut Self::ControlMessage { let selfp = self as *const _ as *mut libc::msghdr; - unsafe { libc::CMSG_NXTHDR(selfp, cmsg) } + let next = unsafe { libc::CMSG_NXTHDR(selfp, cmsg) }; + + // On MacOS < 14 CMSG_NXTHDR might continuously return a zeroed cmsg. In + // such case, return a null pointer instead, thus indicating the end of + // the cmsghdr chain. + if unsafe { next.as_ref() } + .is_some_and(|n| (n.cmsg_len as usize) < std::mem::size_of::()) + { + return std::ptr::null_mut(); + } + + next } fn set_control_len(&mut self, len: usize) { diff --git a/third_party/rust/quinn-udp/src/lib.rs b/third_party/rust/quinn-udp/src/lib.rs index 101db9ffca9a..a8a0243cb42b 100644 --- a/third_party/rust/quinn-udp/src/lib.rs +++ b/third_party/rust/quinn-udp/src/lib.rs @@ -27,12 +27,13 @@ #![warn(unreachable_pub)] #![warn(clippy::use_self)] +use std::net::{IpAddr, Ipv6Addr, SocketAddr}; #[cfg(unix)] use std::os::unix::io::AsFd; #[cfg(windows)] use std::os::windows::io::AsSocket; +#[cfg(not(wasm_browser))] use std::{ - net::{IpAddr, Ipv6Addr, SocketAddr}, sync::Mutex, time::{Duration, Instant}, }; @@ -49,7 +50,7 @@ mod imp; mod imp; // No ECN support -#[cfg(not(any(unix, windows)))] +#[cfg(not(any(wasm_browser, unix, windows)))] #[path = "fallback.rs"] mod imp; @@ -76,10 +77,15 @@ mod log { pub(crate) use no_op::*; } +#[cfg(not(wasm_browser))] pub use imp::UdpSocketState; /// Number of UDP packets to send/receive at a time +#[cfg(not(wasm_browser))] pub const BATCH_SIZE: usize = imp::BATCH_SIZE; +/// Number of UDP packets to send/receive at a time +#[cfg(wasm_browser)] +pub const BATCH_SIZE: usize = 1; /// Metadata for a single buffer filled with bytes received from the network /// @@ -141,13 +147,14 @@ pub struct Transmit<'a> { } /// Log at most 1 IO error per minute +#[cfg(not(wasm_browser))] const IO_ERROR_LOG_INTERVAL: Duration = std::time::Duration::from_secs(60); /// Logs a warning message when sendmsg fails /// /// Logging will only be performed if at least [`IO_ERROR_LOG_INTERVAL`] /// has elapsed since the last error was logged. -#[cfg(any(feature = "tracing", feature = "direct-log"))] +#[cfg(all(not(wasm_browser), any(feature = "tracing", feature = "direct-log")))] fn log_sendmsg_error( last_send_error: &Mutex, err: impl core::fmt::Debug, @@ -164,7 +171,7 @@ fn log_sendmsg_error( } // No-op -#[cfg(not(any(feature = "tracing", feature = "direct-log")))] +#[cfg(not(any(wasm_browser, feature = "tracing", feature = "direct-log")))] fn log_sendmsg_error(_: &Mutex, _: impl core::fmt::Debug, _: &Transmit) {} /// A borrowed UDP socket @@ -172,6 +179,7 @@ fn log_sendmsg_error(_: &Mutex, _: impl core::fmt::Debug, _: &Transmit) /// On Unix, constructible via `From`. On Windows, constructible via `From`. // Wrapper around socket2 to avoid making it a public dependency and incurring stability risk +#[cfg(not(wasm_browser))] pub struct UdpSockRef<'a>(socket2::SockRef<'a>); #[cfg(unix)] @@ -198,18 +206,18 @@ where #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum EcnCodepoint { - #[doc(hidden)] + /// The ECT(0) codepoint, indicating that an endpoint is ECN-capable Ect0 = 0b10, - #[doc(hidden)] + /// The ECT(1) codepoint, indicating that an endpoint is ECN-capable Ect1 = 0b01, - #[doc(hidden)] + /// The CE codepoint, signalling that congestion was experienced Ce = 0b11, } impl EcnCodepoint { /// Create new object from the given bits pub fn from_bits(x: u8) -> Option { - use self::EcnCodepoint::*; + use EcnCodepoint::*; Some(match x & 0b11 { 0b10 => Ect0, 0b01 => Ect1, diff --git a/third_party/rust/quinn-udp/src/windows.rs b/third_party/rust/quinn-udp/src/windows.rs index b0e776e27b3c..9e6e823b8acf 100644 --- a/third_party/rust/quinn-udp/src/windows.rs +++ b/third_party/rust/quinn-udp/src/windows.rs @@ -81,7 +81,12 @@ impl UdpSocketState { WinSock::IP_PKTINFO, OPTION_ON, )?; - set_socket_option(&*socket.0, WinSock::IPPROTO_IP, WinSock::IP_ECN, OPTION_ON)?; + set_socket_option( + &*socket.0, + WinSock::IPPROTO_IP, + WinSock::IP_RECVECN, + OPTION_ON, + )?; } if is_ipv6 { @@ -102,7 +107,7 @@ impl UdpSocketState { set_socket_option( &*socket.0, WinSock::IPPROTO_IPV6, - WinSock::IPV6_ECN, + WinSock::IPV6_RECVECN, OPTION_ON, )?; }