Bug 1880110 - neqo 0.7.1, r=necko-reviewers,supply-chain-reviewers,jesup

Differential Revision: https://phabricator.services.mozilla.com/D201728
This commit is contained in:
Kershaw Chang 2024-02-14 08:51:05 +00:00
Родитель 9f664c10ed
Коммит 737d9c536c
64 изменённых файлов: 1415 добавлений и 1850 удалений

Просмотреть файл

@ -20,11 +20,6 @@ git = "https://github.com/chris-zen/coremidi.git"
rev = "fc68464b5445caf111e41f643a2e69ccce0b4f83"
replace-with = "vendored-sources"
[source."git+https://github.com/cloudflare/quiche?rev=09ea4b244096a013071cfe2175bbf2945fb7f8d1"]
git = "https://github.com/cloudflare/quiche"
rev = "09ea4b244096a013071cfe2175bbf2945fb7f8d1"
replace-with = "vendored-sources"
[source."git+https://github.com/franziskuskiefer/cose-rust?rev=43c22248d136c8b38fe42ea709d08da6355cf04b"]
git = "https://github.com/franziskuskiefer/cose-rust"
rev = "43c22248d136c8b38fe42ea709d08da6355cf04b"
@ -90,9 +85,9 @@ git = "https://github.com/mozilla/mp4parse-rust"
rev = "a138e40ec1c603615873e524b5b22e11c0ec4820"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/neqo?tag=v0.7.0"]
[source."git+https://github.com/mozilla/neqo?tag=v0.7.1"]
git = "https://github.com/mozilla/neqo"
tag = "v0.7.0"
tag = "v0.7.1"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/uniffi-rs.git?rev=afb29ebdc1d9edf15021b1c5332fc9f285bbe13b"]

29
Cargo.lock сгенерированный
Просмотреть файл

@ -3865,12 +3865,11 @@ dependencies = [
[[package]]
name = "neqo-common"
version = "0.7.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.0#9489511f7c82786f55bc9c713cddbff825507ed7"
version = "0.7.1"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.1#721a1eff430f644e23a3e06ef4c5a248a0cbf592"
dependencies = [
"enum-map",
"env_logger",
"lazy_static",
"log",
"qlog",
"time 0.3.23",
@ -3879,8 +3878,8 @@ dependencies = [
[[package]]
name = "neqo-crypto"
version = "0.7.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.0#9489511f7c82786f55bc9c713cddbff825507ed7"
version = "0.7.1"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.1#721a1eff430f644e23a3e06ef4c5a248a0cbf592"
dependencies = [
"bindgen 0.69.4",
"log",
@ -3893,11 +3892,10 @@ dependencies = [
[[package]]
name = "neqo-http3"
version = "0.7.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.0#9489511f7c82786f55bc9c713cddbff825507ed7"
version = "0.7.1"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.1#721a1eff430f644e23a3e06ef4c5a248a0cbf592"
dependencies = [
"enumset",
"lazy_static",
"log",
"neqo-common",
"neqo-crypto",
@ -3911,10 +3909,9 @@ dependencies = [
[[package]]
name = "neqo-qpack"
version = "0.7.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.0#9489511f7c82786f55bc9c713cddbff825507ed7"
version = "0.7.1"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.1#721a1eff430f644e23a3e06ef4c5a248a0cbf592"
dependencies = [
"lazy_static",
"log",
"neqo-common",
"neqo-crypto",
@ -3925,11 +3922,10 @@ dependencies = [
[[package]]
name = "neqo-transport"
version = "0.7.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.0#9489511f7c82786f55bc9c713cddbff825507ed7"
version = "0.7.1"
source = "git+https://github.com/mozilla/neqo?tag=v0.7.1#721a1eff430f644e23a3e06ef4c5a248a0cbf592"
dependencies = [
"indexmap 1.9.3",
"lazy_static",
"log",
"neqo-common",
"neqo-crypto",
@ -4572,8 +4568,9 @@ dependencies = [
[[package]]
name = "qlog"
version = "0.11.0"
source = "git+https://github.com/cloudflare/quiche?rev=09ea4b244096a013071cfe2175bbf2945fb7f8d1#09ea4b244096a013071cfe2175bbf2945fb7f8d1"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c0407438c69b3d99714a796a135cbfb2d60744e4747fb2b46a87acd1c1fcd0e"
dependencies = [
"serde",
"serde_derive",

Просмотреть файл

@ -9,16 +9,16 @@ license = "MPL-2.0"
name = "neqo_glue"
[dependencies]
neqo-http3 = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
xpcom = { path = "../../../xpcom/rust/xpcom" }
thin-vec = { version = "0.2.1", features = ["gecko-ffi"] }
log = "0.4.0"
qlog = { git = "https://github.com/cloudflare/quiche", rev = "09ea4b244096a013071cfe2175bbf2945fb7f8d1" }
qlog = "0.12"
libc = "0.2.0"
static_prefs = { path = "../../../modules/libpref/init/static_prefs"}
uuid = { version = "1.0", features = ["v4"] }
@ -27,7 +27,7 @@ uuid = { version = "1.0", features = ["v4"] }
winapi = {version = "0.3", features = ["ws2def"] }
[dependencies.neqo-crypto]
tag = "v0.7.0"
tag = "v0.7.1"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

Просмотреть файл

@ -6,10 +6,10 @@ edition = "2018"
license = "MPL-2.0"
[dependencies]
neqo-transport = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.7.0", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.7.1", git = "https://github.com/mozilla/neqo" }
mio = "0.6.17"
mio-extras = "2.0.5"
log = "0.4.0"
@ -21,7 +21,7 @@ tokio = { version = "1", features = ["rt-multi-thread"] }
mozilla-central-workspace-hack = { version = "0.1", features = ["http3server"], optional = true }
[dependencies.neqo-crypto]
tag = "v0.7.0"
tag = "v0.7.1"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

Просмотреть файл

@ -3127,8 +3127,7 @@ delta = "0.9.0 -> 0.11.0"
[[audits.qlog]]
who = "Kershaw Chang <kershaw@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.11.0 -> 0.11.0@git:09ea4b244096a013071cfe2175bbf2945fb7f8d1"
importable = false
delta = "0.11.0 -> 0.12.0"
[[audits.quote]]
who = "Nika Layzell <nika@thelayzells.com>"

Просмотреть файл

@ -165,10 +165,6 @@ notes = "This is a first-party crate which is entirely unrelated to the crates.i
audit-as-crates-io = true
notes = "This is a first-party crate which is also published to crates.io, but we should publish audits for it for the benefit of the ecosystem."
[policy.qlog]
audit-as-crates-io = true
notes = "Use this revision (09ea4b244096a013071cfe2175bbf2945fb7f8d1) of qlog temporarily."
[policy.rure]
audit-as-crates-io = true
notes = "Identical to upstream, but with cdylib and staticlib targets disabled to avoid unnecessary build artifacts and linker errors."

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"dbb5500f87df7aee6e680ac210ddb56b833aa82d6be5c407474de0895cee14e9","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"8c14f09864b095e28ff52e7d96a12a6591fc9c4b20a9cafca6720d132c80efdc","src/datagram.rs":"1a7028d96a2e7385e94265de53189eb824b7cf12e0e2de5d67c3f3f8751b6043","src/event.rs":"4ef9e6f3f5168f2eacb7be982e062e743c64a64e809765d2139122839aa407e5","src/header.rs":"467b947f78bfe354d8bb51e8df0c2be69e75a45e2be688d81f0d268aa77c89ef","src/hrtime.rs":"d7c8849e9ec7a312878ea2bc28939717fa03969fb9aee259a4a516351ee37643","src/incrdecoder.rs":"577c32b9ace51f2daaf940be6d0c391c4f55cd42ef6848c68c1ffc970d8c57b5","src/lib.rs":"47c14084c6d475ebb855f3ed9302b31fa42780b93a816bf098c96987ffe33572","src/log.rs":"c68099eae0e9014be35173ac802165b128433d973390e1111c08df56e71df063","src/qlog.rs":"3f43dc4e5fdccb9d6ee74d9e7b3ff29da63e4eb9f631e4e35446e452d8ec7af6","src/timer.rs":"50a2de20933b7b5884337aded69e59e2523503481308f25de1bba1a11d505be8","src/tos.rs":"5b5a61c699266716afce2f5bda7c98151db3223ede41ce451c390863198e30a2","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
{"files":{"Cargo.toml":"a5d8880c97023af584bb1116bf480ff957395e4e744c97aa52051b60b0bc5f80","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"c652182a23ada920e55d6c73c5ede3ed3d01696db0b1826136585cfa926370b4","src/datagram.rs":"1a7028d96a2e7385e94265de53189eb824b7cf12e0e2de5d67c3f3f8751b6043","src/event.rs":"4ef9e6f3f5168f2eacb7be982e062e743c64a64e809765d2139122839aa407e5","src/header.rs":"467b947f78bfe354d8bb51e8df0c2be69e75a45e2be688d81f0d268aa77c89ef","src/hrtime.rs":"d7c8849e9ec7a312878ea2bc28939717fa03969fb9aee259a4a516351ee37643","src/incrdecoder.rs":"577c32b9ace51f2daaf940be6d0c391c4f55cd42ef6848c68c1ffc970d8c57b5","src/lib.rs":"47c14084c6d475ebb855f3ed9302b31fa42780b93a816bf098c96987ffe33572","src/log.rs":"8b8e12f4317892fd130c6d021a00d5125c535dea4c1b2c94c1a48d6a65b3aa84","src/qlog.rs":"3f43dc4e5fdccb9d6ee74d9e7b3ff29da63e4eb9f631e4e35446e452d8ec7af6","src/timer.rs":"d5d0e1ae7cc96f06fb2a8a53ef9236e11c4e1b0be2e9312f16c64e48c76acad2","src/tos.rs":"5b5a61c699266716afce2f5bda7c98151db3223ede41ce451c390863198e30a2","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}

16
third_party/rust/neqo-common/Cargo.toml поставляемый
Просмотреть файл

@ -11,16 +11,18 @@
[package]
edition = "2018"
rust-version = "1.70.0"
rust-version = "1.74.0"
name = "neqo-common"
version = "0.7.0"
authors = ["Bobby Holley <bobbyholley@gmail.com>"]
version = "0.7.1"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = "build.rs"
homepage = "https://github.com/mozilla/neqo/"
license = "MIT OR Apache-2.0"
repository = "https://github.com/mozilla/neqo/"
[dependencies]
enum-map = "2.7"
lazy_static = "1.4"
qlog = "0.12"
[dependencies.env_logger]
version = "0.10"
@ -30,12 +32,8 @@ default-features = false
version = "0.4"
default-features = false
[dependencies.qlog]
git = "https://github.com/cloudflare/quiche"
rev = "09ea4b244096a013071cfe2175bbf2945fb7f8d1"
[dependencies.time]
version = "0.3.23"
version = "0.3"
features = ["formatting"]
[dev-dependencies.test-fixture]

4
third_party/rust/neqo-common/src/codec.rs поставляемый
Просмотреть файл

@ -112,9 +112,7 @@ impl<'a> Decoder<'a> {
/// Decodes a QUIC varint.
pub fn decode_varint(&mut self) -> Option<u64> {
let Some(b1) = self.decode_byte() else {
return None;
};
let b1 = self.decode_byte()?;
match b1 >> 6 {
0 => Some(u64::from(b1 & 0x3f)),
1 => Some((u64::from(b1 & 0x3f) << 8) | self.decode_uint(1)?),

17
third_party/rust/neqo-common/src/log.rs поставляемый
Просмотреть файл

@ -6,10 +6,13 @@
#![allow(clippy::module_name_repetitions)]
use std::{io::Write, sync::Once, time::Instant};
use std::{
io::Write,
sync::{Once, OnceLock},
time::{Duration, Instant},
};
use env_logger::Builder;
use lazy_static::lazy_static;
#[macro_export]
macro_rules! do_log {
@ -42,17 +45,17 @@ macro_rules! log_subject {
}};
}
static INIT_ONCE: Once = Once::new();
lazy_static! {
static ref START_TIME: Instant = Instant::now();
fn since_start() -> Duration {
static START_TIME: OnceLock<Instant> = OnceLock::new();
START_TIME.get_or_init(Instant::now).elapsed()
}
pub fn init() {
static INIT_ONCE: Once = Once::new();
INIT_ONCE.call_once(|| {
let mut builder = Builder::from_env("RUST_LOG");
builder.format(|buf, record| {
let elapsed = START_TIME.elapsed();
let elapsed = since_start();
writeln!(
buf,
"{}s{:3}ms {} {}",

61
third_party/rust/neqo-common/src/timer.rs поставляемый
Просмотреть файл

@ -247,49 +247,50 @@ impl<T> Timer<T> {
#[cfg(test)]
mod test {
use lazy_static::lazy_static;
use std::sync::OnceLock;
use super::{Duration, Instant, Timer};
lazy_static! {
static ref NOW: Instant = Instant::now();
fn now() -> Instant {
static NOW: OnceLock<Instant> = OnceLock::new();
*NOW.get_or_init(Instant::now)
}
const GRANULARITY: Duration = Duration::from_millis(10);
const CAPACITY: usize = 10;
#[test]
fn create() {
let t: Timer<()> = Timer::new(*NOW, GRANULARITY, CAPACITY);
let t: Timer<()> = Timer::new(now(), GRANULARITY, CAPACITY);
assert_eq!(t.span(), Duration::from_millis(100));
assert_eq!(None, t.next_time());
}
#[test]
fn immediate_entry() {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
t.add(*NOW, 12);
assert_eq!(*NOW, t.next_time().expect("should have an entry"));
let values: Vec<_> = t.take_until(*NOW).collect();
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
t.add(now(), 12);
assert_eq!(now(), t.next_time().expect("should have an entry"));
let values: Vec<_> = t.take_until(now()).collect();
assert_eq!(vec![12], values);
}
#[test]
fn same_time() {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
let v1 = 12;
let v2 = 13;
t.add(*NOW, v1);
t.add(*NOW, v2);
assert_eq!(*NOW, t.next_time().expect("should have an entry"));
let values: Vec<_> = t.take_until(*NOW).collect();
t.add(now(), v1);
t.add(now(), v2);
assert_eq!(now(), t.next_time().expect("should have an entry"));
let values: Vec<_> = t.take_until(now()).collect();
assert!(values.contains(&v1));
assert!(values.contains(&v2));
}
#[test]
fn add() {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
let near_future = *NOW + Duration::from_millis(17);
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
let near_future = now() + Duration::from_millis(17);
let v = 9;
t.add(near_future, v);
assert_eq!(near_future, t.next_time().expect("should return a value"));
@ -305,8 +306,8 @@ mod test {
#[test]
fn add_future() {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
let future = *NOW + Duration::from_millis(117);
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
let future = now() + Duration::from_millis(117);
let v = 9;
t.add(future, v);
assert_eq!(future, t.next_time().expect("should return a value"));
@ -315,8 +316,8 @@ mod test {
#[test]
fn add_far_future() {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
let far_future = *NOW + Duration::from_millis(892);
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
let far_future = now() + Duration::from_millis(892);
let v = 9;
t.add(far_future, v);
assert_eq!(far_future, t.next_time().expect("should return a value"));
@ -333,12 +334,12 @@ mod test {
];
fn with_times() -> Timer<usize> {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
for (i, time) in TIMES.iter().enumerate() {
t.add(*NOW + *time, i);
t.add(now() + *time, i);
}
assert_eq!(
*NOW + *TIMES.iter().min().unwrap(),
now() + *TIMES.iter().min().unwrap(),
t.next_time().expect("should have a time")
);
t
@ -348,7 +349,7 @@ mod test {
#[allow(clippy::needless_collect)] // false positive
fn multiple_values() {
let mut t = with_times();
let values: Vec<_> = t.take_until(*NOW + *TIMES.iter().max().unwrap()).collect();
let values: Vec<_> = t.take_until(now() + *TIMES.iter().max().unwrap()).collect();
for i in 0..TIMES.len() {
assert!(values.contains(&i));
}
@ -358,7 +359,7 @@ mod test {
#[allow(clippy::needless_collect)] // false positive
fn take_far_future() {
let mut t = with_times();
let values: Vec<_> = t.take_until(*NOW + Duration::from_secs(100)).collect();
let values: Vec<_> = t.take_until(now() + Duration::from_secs(100)).collect();
for i in 0..TIMES.len() {
assert!(values.contains(&i));
}
@ -368,15 +369,15 @@ mod test {
fn remove_each() {
let mut t = with_times();
for (i, time) in TIMES.iter().enumerate() {
assert_eq!(Some(i), t.remove(*NOW + *time, |&x| x == i));
assert_eq!(Some(i), t.remove(now() + *time, |&x| x == i));
}
assert_eq!(None, t.next_time());
}
#[test]
fn remove_future() {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
let future = *NOW + Duration::from_millis(117);
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
let future = now() + Duration::from_millis(117);
let v = 9;
t.add(future, v);
@ -385,9 +386,9 @@ mod test {
#[test]
fn remove_too_far_future() {
let mut t = Timer::new(*NOW, GRANULARITY, CAPACITY);
let future = *NOW + Duration::from_millis(117);
let too_far_future = *NOW + t.span() + Duration::from_millis(117);
let mut t = Timer::new(now(), GRANULARITY, CAPACITY);
let future = now() + Duration::from_millis(117);
let too_far_future = now() + t.span() + Duration::from_millis(117);
let v = 9;
t.add(future, v);

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"7f7348b55033e19bbe51b07ee50313c87237fe09b56b338af9ab24e00aab32c6","bindings/bindings.toml":"0660c1661318b8a5094834c2f1bb12266287ef467307f66947eff7762528f70a","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","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":"e712c16cb830a83eb4ea1f50dd341a4c30e1cce95d8c45af97030bc8ad0ae829","src/aead.rs":"b7cda4b89298cfd122cd2e1e94c462840e966c60f4832eb441106563ac332e00","src/aead_fuzzing.rs":"c3e590572314e0bb3fafa13dac3c831358b8a7b5570fe9cfe592752fce8cbdee","src/agent.rs":"c4fe47f9f5b0af20e3418da2e2ddce0ac2ca9665c0502115904f66a554e486ee","src/agentio.rs":"847ac63f6406e33bf20a861cadbfe6301ffa15bd73a5291298ffa93511b87dd5","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"6fc09012f994300ff4a7951bf8981aa266220521f58b8ff0989fee6dc1f27df9","src/constants.rs":"f22bf16bd8cb539862cb1e47138dbba79e93fe738f4b907e465891326f98883c","src/ech.rs":"58b7e0a1d2d52c59889cf8b735902577f7c3df93dfb89c72af2646b7aef29f39","src/err.rs":"fca0222167883231a5e0a569a593f44214501819adf5aadf814be27891c87c24","src/exp.rs":"cec59d61fc95914f9703d2fb6490a8507af993c9db710dde894f2f8fd38123c7","src/ext.rs":"c6ab9aefbbca531466dea938d853b1e42ed51816238afe400b20dbdb0111690b","src/hkdf.rs":"8e6cc5dce0f36efa4e13f5a24e2879bdbf10fb9a2b7dc8f13692e47d8959cdc8","src/hp.rs":"62ec073d99cf8bf3a123838c7d9b51bfdf68887148961f6307288e8dd56ac711","src/lib.rs":"40d9ac97c307c8161c2bf48156cc82377f81ad6e709f99cfd7dc0131dc192f86","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"6c0f2f1b18e9bf9088a5ca5bdc99e789bb42234f7d2fe24d0b463bc957cb84a2","src/prio.rs":"e5e169296c0ac69919c59fb6c1f8bd6bf079452eaa13d75da0edd41d435d3f6f","src/replay.rs":"1ff4a12f6135ef2c42aef2b0947e26fd6241cd4b359020245608046452a7fcb0","src/result.rs":"0587cbb6aace71a7f9765ef7c01dcd9f73a49dcc6331e1d8fe4de2aef6ca65b6","src/secrets.rs":"4ffaa66f25df47dadf042063bff5953effa7bf2f4920cafe827757d6a659cb58","src/selfencrypt.rs":"4d2f4a6ea0fc94502130413ab5e2ea82612228f38a96a1865bf7d2b3f440620e","src/ssl.rs":"c83baa5518b81dd06f2e4072ea3c2d666ccdeb8b1ff6e3746eea9f1af47023a6","src/time.rs":"9204f3a384fb9dd2c3816c88666ad61ac3538f9e2f028954e81fd335a1479070","tests/aead.rs":"efdb92a060ca1957d890da1604513369559cb43195ee54149ed3ab47958dad59","tests/agent.rs":"0e55354595ae5f0e1ab83731564da57ba88a296e00692147c47df7067a0f416a","tests/ext.rs":"54657b45bd86d2561bb0f548736bc6f141bb664a5b043506f428422919ab95d4","tests/handshake.rs":"40701bc22f16d1ba9b9bd9683738e52b96faafee4119f7057437dae705f7867a","tests/hkdf.rs":"4160978b96505c1f1b7d6c4b5f43536ff7bd791c8746f9546c9fbc0fce5cf1c7","tests/hp.rs":"8eeee21a439e0f991145dff07b01283ae39ccd4b8dac4d011d43a464f73db670","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"6edd0914b8466d79ecfb569c6d86995fd364b0dc71be2a0554e82f736ebd6b7c"},"package":null}
{"files":{"Cargo.toml":"780c81b4f5abd5d90126084127f22b61fb82773c175db6f3c4ec9d97a6a01aa2","bindings/bindings.toml":"0660c1661318b8a5094834c2f1bb12266287ef467307f66947eff7762528f70a","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","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":"e712c16cb830a83eb4ea1f50dd341a4c30e1cce95d8c45af97030bc8ad0ae829","src/aead.rs":"b7cda4b89298cfd122cd2e1e94c462840e966c60f4832eb441106563ac332e00","src/aead_fuzzing.rs":"c3e590572314e0bb3fafa13dac3c831358b8a7b5570fe9cfe592752fce8cbdee","src/agent.rs":"f1f570913afb6f7b2cedebd69c387e1f80eb49f48feac05f8b06108c8ff66a8a","src/agentio.rs":"34342094ce2de9bea7cfee8c61ef314e44c0f1a127a73ea22df1a7b84a9c51e4","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"ee40428e9f49ff9eacc30be499cb512e1fd846620f270bd93a97802c80a0514a","src/constants.rs":"f22bf16bd8cb539862cb1e47138dbba79e93fe738f4b907e465891326f98883c","src/ech.rs":"d43ee1df69ae0864eb38f322c5c6b1f7d7ec5f2b3a9c88be875cebdb543c29d7","src/err.rs":"fca0222167883231a5e0a569a593f44214501819adf5aadf814be27891c87c24","src/exp.rs":"cec59d61fc95914f9703d2fb6490a8507af993c9db710dde894f2f8fd38123c7","src/ext.rs":"663f56ff1f2dd471117f22005ba4663be146858ee78165d9f684eafe213cd633","src/hkdf.rs":"364d9bdd57edf0e2e1ca38b5067e0c34ac6fda53f9182b77307708477ab785f9","src/hp.rs":"0c0196f2def1b8429915c6559219414a70ff7326177aa11c127c97e2fd09152e","src/lib.rs":"61ae448c8de034eb6fd2970b81b01a573849c9c15ec739c639c90880b1bbca74","src/p11.rs":"d31464782b44b3b4be4616b1224af40e27a1e0e8a37973aaeb509902b1d71679","src/prio.rs":"e5e169296c0ac69919c59fb6c1f8bd6bf079452eaa13d75da0edd41d435d3f6f","src/replay.rs":"1ff4a12f6135ef2c42aef2b0947e26fd6241cd4b359020245608046452a7fcb0","src/result.rs":"0587cbb6aace71a7f9765ef7c01dcd9f73a49dcc6331e1d8fe4de2aef6ca65b6","src/secrets.rs":"4ffaa66f25df47dadf042063bff5953effa7bf2f4920cafe827757d6a659cb58","src/selfencrypt.rs":"ac65b13f5bade9d03ab4709364f9ec937fa4ca009965c77ca73b481534a0a470","src/ssl.rs":"c83baa5518b81dd06f2e4072ea3c2d666ccdeb8b1ff6e3746eea9f1af47023a6","src/time.rs":"9a617965cd4d926368838e7af9536030f294071c0e1dd0f1d0c4831d29d3274c","tests/aead.rs":"efdb92a060ca1957d890da1604513369559cb43195ee54149ed3ab47958dad59","tests/agent.rs":"0e55354595ae5f0e1ab83731564da57ba88a296e00692147c47df7067a0f416a","tests/ext.rs":"54657b45bd86d2561bb0f548736bc6f141bb664a5b043506f428422919ab95d4","tests/handshake.rs":"40701bc22f16d1ba9b9bd9683738e52b96faafee4119f7057437dae705f7867a","tests/hkdf.rs":"4160978b96505c1f1b7d6c4b5f43536ff7bd791c8746f9546c9fbc0fce5cf1c7","tests/hp.rs":"8eeee21a439e0f991145dff07b01283ae39ccd4b8dac4d011d43a464f73db670","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"6edd0914b8466d79ecfb569c6d86995fd364b0dc71be2a0554e82f736ebd6b7c"},"package":null}

18
third_party/rust/neqo-crypto/Cargo.toml поставляемый
Просмотреть файл

@ -11,15 +11,17 @@
[package]
edition = "2018"
rust-version = "1.70.0"
rust-version = "1.74.0"
name = "neqo-crypto"
version = "0.7.0"
authors = ["Martin Thomson <mt@lowentropy.net>"]
version = "0.7.1"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = "build.rs"
homepage = "https://github.com/mozilla/neqo/"
license = "MIT OR Apache-2.0"
repository = "https://github.com/mozilla/neqo/"
[dependencies.log]
version = "~0.4.17"
version = "0.4"
default-features = false
[dependencies.neqo-common]
@ -29,12 +31,12 @@ path = "../neqo-common"
path = "../test-fixture"
[build-dependencies]
serde = "1.0.195"
serde_derive = "1.0.195"
toml = "0.5.11"
serde = "1.0"
serde_derive = "1.0"
toml = "0.5"
[build-dependencies.bindgen]
version = "0.69.1"
version = "0.69"
features = ["runtime"]
default-features = false

9
third_party/rust/neqo-crypto/src/agent.rs поставляемый
Просмотреть файл

@ -33,6 +33,7 @@ use crate::{
ech,
err::{is_blocked, secstatus_to_res, Error, PRErrorCode, Res},
ext::{ExtensionHandler, ExtensionTracker},
null_safe_slice,
p11::{self, PrivateKey, PublicKey},
prio,
replay::AntiReplay,
@ -897,7 +898,7 @@ impl Client {
let resumption = arg.cast::<Vec<ResumptionToken>>().as_mut().unwrap();
let len = usize::try_from(len).unwrap();
let mut v = Vec::with_capacity(len);
v.extend_from_slice(std::slice::from_raw_parts(token, len));
v.extend_from_slice(null_safe_slice(token, len));
qinfo!(
[format!("{fd:p}")],
"Got resumption token {}",
@ -1105,11 +1106,7 @@ impl Server {
}
let check_state = arg.cast::<ZeroRttCheckState>().as_mut().unwrap();
let token = if client_token.is_null() {
&[]
} else {
std::slice::from_raw_parts(client_token, usize::try_from(client_token_len).unwrap())
};
let token = null_safe_slice(client_token, usize::try_from(client_token_len).unwrap());
match check_state.checker.check(token) {
ZeroRttCheckResult::Accept => ssl::SSLHelloRetryRequestAction::ssl_hello_retry_accept,
ZeroRttCheckResult::Fail => ssl::SSLHelloRetryRequestAction::ssl_hello_retry_fail,

7
third_party/rust/neqo-crypto/src/agentio.rs поставляемый
Просмотреть файл

@ -20,7 +20,7 @@ use neqo_common::{hex, hex_with_len, qtrace};
use crate::{
constants::{ContentType, Epoch},
err::{nspr, Error, PR_SetError, Res},
prio, ssl,
null_safe_slice, prio, ssl,
};
// Alias common types.
@ -100,7 +100,7 @@ impl RecordList {
) -> ssl::SECStatus {
let records = arg.cast::<Self>().as_mut().unwrap();
let slice = std::slice::from_raw_parts(data, len as usize);
let slice = null_safe_slice(data, len);
records.append(epoch, ContentType::try_from(ct).unwrap(), slice);
ssl::SECSuccess
}
@ -178,6 +178,7 @@ impl AgentIoInput {
return Err(Error::NoDataAvailable);
}
#[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));
let dst = unsafe { std::slice::from_raw_parts_mut(buf, amount) };
@ -232,7 +233,7 @@ impl AgentIo {
// Stage output from TLS into the output buffer.
fn save_output(&mut self, buf: *const u8, count: usize) {
let slice = unsafe { std::slice::from_raw_parts(buf, count) };
let slice = unsafe { null_safe_slice(buf, count) };
qtrace!([self], "save output {}", hex(slice));
self.output.extend_from_slice(slice);
}

11
third_party/rust/neqo-crypto/src/cert.rs поставляемый
Просмотреть файл

@ -7,13 +7,13 @@
use std::{
convert::TryFrom,
ptr::{addr_of, NonNull},
slice,
};
use neqo_common::qerror;
use crate::{
err::secstatus_to_res,
null_safe_slice,
p11::{CERTCertListNode, CERT_GetCertificateDer, CertList, Item, SECItem, SECItemArray},
ssl::{
PRFileDesc, SSL_PeerCertificateChain, SSL_PeerSignedCertTimestamps,
@ -52,7 +52,7 @@ fn stapled_ocsp_responses(fd: *mut PRFileDesc) -> Option<Vec<Vec<u8>>> {
};
for idx in 0..len {
let itemp: *const SECItem = unsafe { ocsp_ptr.as_ref().items.offset(idx).cast() };
let item = unsafe { slice::from_raw_parts((*itemp).data, (*itemp).len as usize) };
let item = unsafe { null_safe_slice((*itemp).data, (*itemp).len) };
ocsp_helper.push(item.to_owned());
}
Some(ocsp_helper)
@ -68,9 +68,8 @@ fn signed_cert_timestamp(fd: *mut PRFileDesc) -> Option<Vec<u8>> {
if unsafe { sct_ptr.as_ref().len == 0 || sct_ptr.as_ref().data.is_null() } {
Some(Vec::new())
} else {
let sct_slice = unsafe {
slice::from_raw_parts(sct_ptr.as_ref().data, sct_ptr.as_ref().len as usize)
};
let sct_slice =
unsafe { null_safe_slice(sct_ptr.as_ref().data, sct_ptr.as_ref().len) };
Some(sct_slice.to_owned())
}
}
@ -105,7 +104,7 @@ impl<'a> Iterator for &'a mut CertificateInfo {
let cert = unsafe { *self.cursor }.cert;
secstatus_to_res(unsafe { CERT_GetCertificateDer(cert, &mut item) })
.expect("getting DER from certificate should work");
Some(unsafe { std::slice::from_raw_parts(item.data, item.len as usize) })
Some(unsafe { null_safe_slice(item.data, item.len) })
}
}

9
third_party/rust/neqo-crypto/src/ech.rs поставляемый
Просмотреть файл

@ -15,7 +15,7 @@ use neqo_common::qtrace;
use crate::{
err::{ssl::SSL_ERROR_ECH_RETRY_WITH_ECH, Error, Res},
experimental_api,
experimental_api, null_safe_slice,
p11::{
self, Item, PrivateKey, PublicKey, SECITEM_FreeItem, SECItem, SECKEYPrivateKey,
SECKEYPublicKey, Slot,
@ -76,7 +76,7 @@ pub fn convert_ech_error(fd: *mut PRFileDesc, err: Error) -> Error {
return Error::InternalError;
}
let buf = unsafe {
let slc = std::slice::from_raw_parts(item.data, usize::try_from(item.len).unwrap());
let slc = null_safe_slice(item.data, item.len);
let buf = Vec::from(slc);
SECITEM_FreeItem(&mut item, PRBool::from(false));
buf
@ -101,8 +101,7 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
let oid_data = unsafe { p11::SECOID_FindOIDByTag(p11::SECOidTag::SEC_OID_CURVE25519) };
let oid = unsafe { oid_data.as_ref() }.ok_or(Error::InternalError)?;
let oid_slc =
unsafe { std::slice::from_raw_parts(oid.oid.data, usize::try_from(oid.oid.len).unwrap()) };
let oid_slc = unsafe { null_safe_slice(oid.oid.data, oid.oid.len) };
let mut params: Vec<u8> = Vec::with_capacity(oid_slc.len() + 2);
params.push(u8::try_from(p11::SEC_ASN1_OBJECT_ID).unwrap());
params.push(u8::try_from(oid.oid.len).unwrap());
@ -113,7 +112,6 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
// If we have tracing on, try to ensure that key data can be read.
let insensitive_secret_ptr = if log::log_enabled!(log::Level::Trace) {
#[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
unsafe {
p11::PK11_GenerateKeyPairWithOpFlags(
*slot,
@ -131,7 +129,6 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
};
assert_eq!(insensitive_secret_ptr.is_null(), public_ptr.is_null());
let secret_ptr = if insensitive_secret_ptr.is_null() {
#[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
unsafe {
p11::PK11_GenerateKeyPairWithOpFlags(
*slot,

3
third_party/rust/neqo-crypto/src/ext.rs поставляемый
Просмотреть файл

@ -16,6 +16,7 @@ use crate::{
agentio::as_c_void,
constants::{Extension, HandshakeMessage, TLS_HS_CLIENT_HELLO, TLS_HS_ENCRYPTED_EXTENSIONS},
err::Res,
null_safe_slice,
ssl::{
PRBool, PRFileDesc, SECFailure, SECStatus, SECSuccess, SSLAlertDescription,
SSLExtensionHandler, SSLExtensionWriter, SSLHandshakeType,
@ -105,7 +106,7 @@ impl ExtensionTracker {
alert: *mut SSLAlertDescription,
arg: *mut c_void,
) -> SECStatus {
let d = std::slice::from_raw_parts(data, len as usize);
let d = null_safe_slice(data, len);
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
Self::wrap_handler_call(arg, |handler| {
// Cast is safe here because the message type is always part of the enum

22
third_party/rust/neqo-crypto/src/hkdf.rs поставляемый
Просмотреть файл

@ -17,9 +17,10 @@ use crate::{
},
err::{Error, Res},
p11::{
random, Item, PK11Origin, PK11SymKey, PK11_ImportDataKey, Slot, SymKey, CKA_DERIVE,
Item, PK11Origin, PK11SymKey, PK11_ImportDataKey, Slot, SymKey, CKA_DERIVE,
CKM_HKDF_DERIVE, CK_ATTRIBUTE_TYPE, CK_MECHANISM_TYPE,
},
random,
};
experimental_api!(SSL_HkdfExtract(
@ -40,24 +41,32 @@ experimental_api!(SSL_HkdfExpandLabel(
secret: *mut *mut PK11SymKey,
));
fn key_size(version: Version, cipher: Cipher) -> Res<usize> {
const MAX_KEY_SIZE: usize = 48;
const fn key_size(version: Version, cipher: Cipher) -> Res<usize> {
if version != TLS_VERSION_1_3 {
return Err(Error::UnsupportedVersion);
}
Ok(match cipher {
let size = match cipher {
TLS_AES_128_GCM_SHA256 | TLS_CHACHA20_POLY1305_SHA256 => 32,
TLS_AES_256_GCM_SHA384 => 48,
_ => return Err(Error::UnsupportedCipher),
})
};
debug_assert!(size <= MAX_KEY_SIZE);
Ok(size)
}
/// Generate a random key of the right size for the given suite.
///
/// # Errors
///
/// Only if NSS fails.
/// If the ciphersuite or protocol version is not supported.
pub fn generate_key(version: Version, cipher: Cipher) -> Res<SymKey> {
import_key(version, &random(key_size(version, cipher)?))
// With generic_const_expr, this becomes:
// import_key(version, &random::<{ key_size(version, cipher) }>())
import_key(
version,
&random::<MAX_KEY_SIZE>()[0..key_size(version, cipher)?],
)
}
/// Import a symmetric key for use with HKDF.
@ -70,7 +79,6 @@ pub fn import_key(version: Version, buf: &[u8]) -> Res<SymKey> {
return Err(Error::UnsupportedVersion);
}
let slot = Slot::internal()?;
#[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
let key_ptr = unsafe {
PK11_ImportDataKey(
*slot,

5
third_party/rust/neqo-crypto/src/hp.rs поставляемый
Просмотреть файл

@ -76,7 +76,6 @@ impl HpKey {
let l = label.as_bytes();
let mut secret: *mut PK11SymKey = null_mut();
#[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
let (mech, key_size) = match cipher {
TLS_AES_128_GCM_SHA256 => (CK_MECHANISM_TYPE::from(CKM_AES_ECB), 16),
TLS_AES_256_GCM_SHA384 => (CK_MECHANISM_TYPE::from(CKM_AES_ECB), 32),
@ -104,8 +103,6 @@ impl HpKey {
let res = match cipher {
TLS_AES_128_GCM_SHA256 | TLS_AES_256_GCM_SHA384 => {
// TODO: Remove when we bump the MSRV to 1.74.0.
#[allow(clippy::useless_conversion)]
let context_ptr = unsafe {
PK11_CreateContextBySymKey(
mech,
@ -181,8 +178,6 @@ impl HpKey {
};
let mut output_len: c_uint = 0;
let mut param_item = Item::wrap_struct(&params);
// TODO: Remove when we bump the MSRV to 1.74.0.
#[allow(clippy::useless_conversion)]
secstatus_to_res(unsafe {
PK11_Encrypt(
**key,

111
third_party/rust/neqo-crypto/src/lib.rs поставляемый
Просмотреть файл

@ -27,7 +27,6 @@ mod exp;
pub mod ext;
pub mod hkdf;
pub mod hp;
mod once;
#[macro_use]
mod p11;
mod prio;
@ -38,9 +37,11 @@ mod ssl;
mod time;
use std::{
convert::TryFrom,
ffi::CString,
path::{Path, PathBuf},
ptr::null,
sync::OnceLock,
};
#[cfg(not(feature = "fuzzing"))]
@ -49,7 +50,6 @@ pub use self::aead::RealAead as Aead;
pub use self::aead::RealAead;
#[cfg(feature = "fuzzing")]
pub use self::aead_fuzzing::FuzzingAead as Aead;
use self::once::OnceResult;
pub use self::{
agent::{
Agent, AllowZeroRtt, Client, HandshakeState, Record, RecordList, ResumptionToken,
@ -64,7 +64,7 @@ pub use self::{
},
err::{Error, PRErrorCode, Res},
ext::{ExtensionHandler, ExtensionHandlerResult, ExtensionWriterResult},
p11::{random, PrivateKey, PublicKey, SymKey},
p11::{random, randomize, PrivateKey, PublicKey, SymKey},
replay::AntiReplay,
secrets::SecretDirection,
ssl::Opt,
@ -100,7 +100,7 @@ impl Drop for NssLoaded {
}
}
static mut INITIALIZED: OnceResult<NssLoaded> = OnceResult::new();
static INITIALIZED: OnceLock<NssLoaded> = OnceLock::new();
fn already_initialized() -> bool {
unsafe { nss::NSS_IsInitialized() != 0 }
@ -124,19 +124,18 @@ fn version_check() {
pub fn init() {
// Set time zero.
time::init();
unsafe {
INITIALIZED.call_once(|| {
version_check();
if already_initialized() {
return NssLoaded::External;
}
_ = INITIALIZED.get_or_init(|| {
version_check();
if already_initialized() {
return NssLoaded::External;
}
secstatus_to_res(nss::NSS_NoDB_Init(null())).expect("NSS_NoDB_Init failed");
secstatus_to_res(nss::NSS_SetDomesticPolicy()).expect("NSS_SetDomesticPolicy failed");
secstatus_to_res(unsafe { nss::NSS_NoDB_Init(null()) }).expect("NSS_NoDB_Init failed");
secstatus_to_res(unsafe { nss::NSS_SetDomesticPolicy() })
.expect("NSS_SetDomesticPolicy failed");
NssLoaded::NoDb
});
}
NssLoaded::NoDb
});
}
/// This enables SSLTRACE by calling a simple, harmless function to trigger its
@ -158,51 +157,71 @@ fn enable_ssl_trace() {
/// If NSS cannot be initialized.
pub fn init_db<P: Into<PathBuf>>(dir: P) {
time::init();
unsafe {
INITIALIZED.call_once(|| {
version_check();
if already_initialized() {
return NssLoaded::External;
}
_ = INITIALIZED.get_or_init(|| {
version_check();
if already_initialized() {
return NssLoaded::External;
}
let path = dir.into();
assert!(path.is_dir());
let pathstr = path.to_str().expect("path converts to string").to_string();
let dircstr = CString::new(pathstr).unwrap();
let empty = CString::new("").unwrap();
secstatus_to_res(nss::NSS_Initialize(
let path = dir.into();
assert!(path.is_dir());
let pathstr = path.to_str().expect("path converts to string").to_string();
let dircstr = CString::new(pathstr).unwrap();
let empty = CString::new("").unwrap();
secstatus_to_res(unsafe {
nss::NSS_Initialize(
dircstr.as_ptr(),
empty.as_ptr(),
empty.as_ptr(),
nss::SECMOD_DB.as_ptr().cast(),
nss::NSS_INIT_READONLY,
))
.expect("NSS_Initialize failed");
)
})
.expect("NSS_Initialize failed");
secstatus_to_res(nss::NSS_SetDomesticPolicy()).expect("NSS_SetDomesticPolicy failed");
secstatus_to_res(ssl::SSL_ConfigServerSessionIDCache(
1024,
0,
0,
dircstr.as_ptr(),
))
.expect("SSL_ConfigServerSessionIDCache failed");
secstatus_to_res(unsafe { nss::NSS_SetDomesticPolicy() })
.expect("NSS_SetDomesticPolicy failed");
secstatus_to_res(unsafe {
ssl::SSL_ConfigServerSessionIDCache(1024, 0, 0, dircstr.as_ptr())
})
.expect("SSL_ConfigServerSessionIDCache failed");
#[cfg(debug_assertions)]
enable_ssl_trace();
#[cfg(debug_assertions)]
enable_ssl_trace();
NssLoaded::Db(path.into_boxed_path())
});
}
NssLoaded::Db(path.into_boxed_path())
});
}
/// # Panics
///
/// If NSS isn't initialized.
pub fn assert_initialized() {
unsafe {
INITIALIZED.call_once(|| {
panic!("NSS not initialized with init or init_db");
});
INITIALIZED
.get()
.expect("NSS not initialized with init or init_db");
}
/// NSS tends to return empty "slices" with a null pointer, which will cause
/// `std::slice::from_raw_parts` to panic if passed directly. This wrapper avoids
/// that issue. It also performs conversion for lengths, as a convenience.
///
/// # Panics
/// If the provided length doesn't fit into a `usize`.
///
/// # Safety
/// The caller must adhere to the safety constraints of `std::slice::from_raw_parts`,
/// except that this will accept a null value for `data`.
unsafe fn null_safe_slice<'a, T>(data: *const u8, len: T) -> &'a [u8]
where
usize: TryFrom<T>,
{
if data.is_null() {
&[]
} else if let Ok(len) = usize::try_from(len) {
#[allow(clippy::disallowed_methods)]
std::slice::from_raw_parts(data, len)
} else {
panic!("null_safe_slice: size overflow");
}
}

44
third_party/rust/neqo-crypto/src/once.rs поставляемый
Просмотреть файл

@ -1,44 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::sync::Once;
#[allow(clippy::module_name_repetitions)]
pub struct OnceResult<T> {
once: Once,
v: Option<T>,
}
impl<T> OnceResult<T> {
#[must_use]
pub const fn new() -> Self {
Self {
once: Once::new(),
v: None,
}
}
pub fn call_once<F: FnOnce() -> T>(&mut self, f: F) -> &T {
let v = &mut self.v;
self.once.call_once(|| {
*v = Some(f());
});
self.v.as_ref().unwrap()
}
}
#[cfg(test)]
mod test {
use super::OnceResult;
static mut STATIC_ONCE_RESULT: OnceResult<u64> = OnceResult::new();
#[test]
fn static_update() {
assert_eq!(*unsafe { STATIC_ONCE_RESULT.call_once(|| 23) }, 23);
assert_eq!(*unsafe { STATIC_ONCE_RESULT.call_once(|| 24) }, 23);
}
}

113
third_party/rust/neqo-crypto/src/p11.rs поставляемый
Просмотреть файл

@ -10,6 +10,7 @@
#![allow(non_snake_case)]
use std::{
cell::RefCell,
convert::TryFrom,
mem,
ops::{Deref, DerefMut},
@ -19,7 +20,10 @@ use std::{
use neqo_common::hex_with_len;
use crate::err::{secstatus_to_res, Error, Res};
use crate::{
err::{secstatus_to_res, Error, Res},
null_safe_slice,
};
#[allow(clippy::upper_case_acronyms)]
#[allow(clippy::unreadable_literal)]
@ -139,7 +143,6 @@ impl PrivateKey {
/// When the values are too large to fit. So never.
pub fn key_data(&self) -> Res<Vec<u8>> {
let mut key_item = Item::make_empty();
#[allow(clippy::useless_conversion)] // TODO: Remove when we bump the MSRV to 1.74.0.
secstatus_to_res(unsafe {
PK11_ReadRawAttribute(
PK11ObjectType::PK11_TypePrivKey,
@ -148,9 +151,7 @@ impl PrivateKey {
&mut key_item,
)
})?;
let slc = unsafe {
std::slice::from_raw_parts(key_item.data, usize::try_from(key_item.len).unwrap())
};
let slc = unsafe { null_safe_slice(key_item.data, key_item.len) };
let key = Vec::from(slc);
// The data that `key_item` refers to needs to be freed, but we can't
// use the scoped `Item` implementation. This is OK as long as nothing
@ -206,7 +207,7 @@ impl SymKey {
// This is accessing a value attached to the key, so we can treat this as a borrow.
match unsafe { key_item.as_mut() } {
None => Err(Error::InternalError),
Some(key) => Ok(unsafe { std::slice::from_raw_parts(key.data, key.len as usize) }),
Some(key) => Ok(unsafe { null_safe_slice(key.data, key.len) }),
}
}
}
@ -285,36 +286,112 @@ impl Item {
let b = self.ptr.as_ref().unwrap();
// Sanity check the type, as some types don't count bytes in `Item::len`.
assert_eq!(b.type_, SECItemType::siBuffer);
let slc = std::slice::from_raw_parts(b.data, usize::try_from(b.len).unwrap());
let slc = null_safe_slice(b.data, b.len);
Vec::from(slc)
}
}
/// Generate a randomized buffer.
/// Fill a buffer with randomness.
///
/// # Panics
///
/// When `size` is too large or NSS fails.
pub fn randomize<B: AsMut<[u8]>>(mut buf: B) -> B {
let m_buf = buf.as_mut();
let len = c_int::try_from(m_buf.len()).unwrap();
secstatus_to_res(unsafe { PK11_GenerateRandom(m_buf.as_mut_ptr(), len) }).unwrap();
buf
}
struct RandomCache {
cache: [u8; Self::SIZE],
used: usize,
}
impl RandomCache {
const SIZE: usize = 256;
const CUTOFF: usize = 32;
fn new() -> Self {
RandomCache {
cache: [0; Self::SIZE],
used: Self::SIZE,
}
}
fn randomize<B: AsMut<[u8]>>(&mut self, mut buf: B) -> B {
let m_buf = buf.as_mut();
debug_assert!(m_buf.len() <= Self::CUTOFF);
let avail = Self::SIZE - self.used;
if m_buf.len() <= avail {
m_buf.copy_from_slice(&self.cache[self.used..self.used + m_buf.len()]);
self.used += m_buf.len();
} else {
if avail > 0 {
m_buf[..avail].copy_from_slice(&self.cache[self.used..]);
}
randomize(&mut self.cache[..]);
self.used = m_buf.len() - avail;
m_buf[avail..].copy_from_slice(&self.cache[..self.used]);
}
buf
}
}
/// Generate a randomized array.
///
/// # Panics
///
/// When `size` is too large or NSS fails.
#[must_use]
pub fn random(size: usize) -> Vec<u8> {
let mut buf = vec![0; size];
secstatus_to_res(unsafe {
PK11_GenerateRandom(buf.as_mut_ptr(), c_int::try_from(buf.len()).unwrap())
})
.unwrap();
buf
pub fn random<const N: usize>() -> [u8; N] {
thread_local! { static CACHE: RefCell<RandomCache> = RefCell::new(RandomCache::new()) };
let buf = [0; N];
if N <= RandomCache::CUTOFF {
CACHE.with_borrow_mut(|c| c.randomize(buf))
} else {
randomize(buf)
}
}
#[cfg(test)]
mod test {
use test_fixture::fixture_init;
use super::random;
use super::RandomCache;
use crate::{random, randomize};
#[test]
fn randomness() {
fixture_init();
// If this ever fails, there is either a bug, or it's time to buy a lottery ticket.
assert_ne!(random(16), random(16));
// If any of these ever fail, there is either a bug, or it's time to buy a lottery ticket.
assert_ne!(random::<16>(), randomize([0; 16]));
assert_ne!([0; 16], random::<16>());
assert_ne!([0; 64], random::<64>());
}
#[test]
fn cache_random_lengths() {
const ZERO: [u8; 256] = [0; 256];
fixture_init();
let mut cache = RandomCache::new();
let mut buf = [0; 256];
let bits = usize::BITS - (RandomCache::CUTOFF - 1).leading_zeros();
let mask = 0xff >> (u8::BITS - bits);
for _ in 0..100 {
let len = loop {
let len = usize::from(random::<1>()[0] & mask) + 1;
if len <= RandomCache::CUTOFF {
break len;
}
};
buf.fill(0);
if len >= 16 {
assert_ne!(&cache.randomize(&mut buf[..len])[..len], &ZERO[..len]);
}
}
}
}

Просмотреть файл

@ -82,7 +82,7 @@ impl SelfEncrypt {
// opaque aead_encrypted(plaintext)[length as expanded];
// };
// AAD covers the entire header, plus the value of the AAD parameter that is provided.
let salt = random(Self::SALT_LENGTH);
let salt = random::<{ Self::SALT_LENGTH }>();
let cipher = self.make_aead(&self.key, &salt)?;
let encoded_len = 2 + salt.len() + plaintext.len() + cipher.expansion();

67
third_party/rust/neqo-crypto/src/time.rs поставляемый
Просмотреть файл

@ -12,13 +12,13 @@ use std::{
ops::Deref,
os::raw::c_void,
pin::Pin,
sync::OnceLock,
time::{Duration, Instant},
};
use crate::{
agentio::as_c_void,
err::{Error, Res},
once::OnceResult,
ssl::{PRFileDesc, SSLTimeFunc},
};
@ -67,14 +67,13 @@ impl TimeZero {
}
}
static mut BASE_TIME: OnceResult<TimeZero> = OnceResult::new();
static BASE_TIME: OnceLock<TimeZero> = OnceLock::new();
fn get_base() -> &'static TimeZero {
let f = || TimeZero {
BASE_TIME.get_or_init(|| TimeZero {
instant: Instant::now(),
prtime: unsafe { PR_Now() },
};
unsafe { BASE_TIME.call_once(f) }
})
}
pub(crate) fn init() {
@ -97,9 +96,8 @@ impl Deref for Time {
impl From<Instant> for Time {
/// Convert from an Instant into a Time.
fn from(t: Instant) -> Self {
// Call `TimeZero::baseline(t)` so that time zero can be set.
let f = || TimeZero::baseline(t);
_ = unsafe { BASE_TIME.call_once(f) };
// Initialize `BASE_TIME` using `TimeZero::baseline(t)`.
BASE_TIME.get_or_init(|| TimeZero::baseline(t));
Self { t }
}
}
@ -108,14 +106,17 @@ impl TryFrom<PRTime> for Time {
type Error = Error;
fn try_from(prtime: PRTime) -> Res<Self> {
let base = get_base();
if let Some(delta) = prtime.checked_sub(base.prtime) {
let d = Duration::from_micros(delta.try_into()?);
base.instant
.checked_add(d)
.map_or(Err(Error::TimeTravelError), |t| Ok(Self { t }))
let delta = prtime
.checked_sub(base.prtime)
.ok_or(Error::TimeTravelError)?;
let d = Duration::from_micros(u64::try_from(delta.abs())?);
let t = if delta >= 0 {
base.instant.checked_add(d)
} else {
Err(Error::TimeTravelError)
}
base.instant.checked_sub(d)
};
let t = t.ok_or(Error::TimeTravelError)?;
Ok(Self { t })
}
}
@ -123,14 +124,21 @@ impl TryInto<PRTime> for Time {
type Error = Error;
fn try_into(self) -> Res<PRTime> {
let base = get_base();
let delta = self
.t
.checked_duration_since(base.instant)
.ok_or(Error::TimeTravelError)?;
if let Ok(d) = PRTime::try_from(delta.as_micros()) {
d.checked_add(base.prtime).ok_or(Error::TimeTravelError)
if let Some(delta) = self.t.checked_duration_since(base.instant) {
if let Ok(d) = PRTime::try_from(delta.as_micros()) {
d.checked_add(base.prtime).ok_or(Error::TimeTravelError)
} else {
Err(Error::TimeTravelError)
}
} else {
Err(Error::TimeTravelError)
// Try to go backwards from the base time.
let backwards = base.instant - self.t; // infallible
if let Ok(d) = PRTime::try_from(backwards.as_micros()) {
base.prtime.checked_sub(d).ok_or(Error::TimeTravelError)
} else {
Err(Error::TimeTravelError)
}
}
}
}
@ -228,16 +236,23 @@ mod test {
}
#[test]
fn past_time() {
fn past_prtime() {
const DELTA: Duration = Duration::from_secs(1);
init();
let base = get_base();
assert!(Time::try_from(base.prtime - 1).is_err());
let delta_micros = PRTime::try_from(DELTA.as_micros()).unwrap();
println!("{} - {}", base.prtime, delta_micros);
let t = Time::try_from(base.prtime - delta_micros).unwrap();
assert_eq!(Instant::from(t) + DELTA, base.instant);
}
#[test]
fn negative_time() {
fn past_instant() {
const DELTA: Duration = Duration::from_secs(1);
init();
assert!(Time::try_from(-1).is_err());
let base = get_base();
let t = Time::from(base.instant.checked_sub(DELTA).unwrap());
assert_eq!(Instant::from(t) + DELTA, base.instant);
}
#[test]

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"fe3c1114cfbb94004bf56740c0d373568cb459efdb12504e67f31923fbd436e1","src/buffered_send_stream.rs":"f45bdf9ad2a04b3828c74ff5440681d3c9d1af39b55470e4f729842dc2412295","src/client_events.rs":"e1392e7bbb62fb0505a4d8bcd27559699bbf38f3c94e7d8cae7291db82e6334c","src/conn_params.rs":"224a8ea6ef632930a7788a1cabf47ce69ad41bd4bc8dcf3053fbd998fdb38e82","src/connection.rs":"09aeb123f8dc6b903dd7d30579e5bb09ed8f70bfae563fb2fcc1871c67d604d4","src/connection_client.rs":"ed1c9ebf443f49dbf12c193953a71ec0e6b95555e1927afce813d2a8324758be","src/connection_server.rs":"ca33b50650bd1ca2a952851b72712d55ec2e48b48f1f06e4184c808b8e1e009a","src/control_stream_local.rs":"d6ecc0adc926e1d5cec9a378317f9dfcfeeb9840a0873a2afb380c2d252d8c54","src/control_stream_remote.rs":"59eb4041e366d92f9f294e8446755caa5e91fd943bba7b79b726698ba13be248","src/features/extended_connect/mod.rs":"3b02f6b18627f3855465a81b1d9b285e6f13839e75a8a6db648ed9082908d7f0","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"7e3bdd591b9c7d02f69954629f889d52bd54f13dbca11d555e614138c2a55107","src/features/extended_connect/tests/webtransport/mod.rs":"fed03f0ded21a9f17be5be99e4572e16dd0c8598e37044df3228990ea7fcc9f4","src/features/extended_connect/tests/webtransport/negotiation.rs":"98254ef8446581ec520026b04ef9549645602181b61602c9936f6660141edf0b","src/features/extended_connect/tests/webtransport/sessions.rs":"de3d836f666c2bec31e70b33bdc2669572cabbe17df2225db7282613a224a364","src/features/extended_connect/tests/webtransport/streams.rs":"8b3c34cac1b2171252a4bb53d420ac2098549a20309c327bf56e2e9ba9e33538","src/features/extended_connect/webtransport_session.rs":"a6472eca50a2d097aa6ba8a76b45ae69fe2edd2696b2953945faa3ce6e7417f9","src/features/extended_connect/webtransport_streams.rs":"a9a106eefc93a9f6e9e1c246df64904353de1c4fbcd394b338e6b117f6c677f5","src/features/mod.rs":"925aae4427ad82e4d019354802b223d53db5e5585d4a940f5417a24a9503d7ee","src/frames/hframe.rs":"726842108261c9af1e7576bc546e7bd7bea86fbef4a5804f4b45a2b4612e2679","src/frames/mod.rs":"7d0a46ca147336d14781edb8dbee8b03c2e4bcd6646f5473a9d93d31fe73fecb","src/frames/reader.rs":"4883e25064da1fb3a6ae46b5d15e6bcfec9c5bbea55a1937ecdb9465b62a93b2","src/frames/tests/hframe.rs":"01ec74eb3eb25d95042aa0263f9267f89535e6b7b8c1161fab4ba9ee5352d4a7","src/frames/tests/mod.rs":"0610609b316767a6a022837d32ee0452e37ea296fde37e51bec87e7c77e923a3","src/frames/tests/reader.rs":"2bfadc7afbc41bff9f5f930b31550259a8a92484d35f6c5d8dd8fd9acfb88f5b","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"c80518d1569de277767c7ccb7441898aadbfc5fb2afb968c1d5105f8d175ccff","src/headers_checks.rs":"44891c16dda6b7ef742058ecb0a8d34e219c51cae1216c09c661cf72d9a5e7d5","src/lib.rs":"ed8da14e573cc5a97afb012a78af7f076eb83b5cc20cb4fe432eb7136a3ffe52","src/priority.rs":"10d9dcfcd4585f2ca256daf254c78a428297c41976c6548f19cd3ed2222b7cd2","src/push_controller.rs":"eb27c7c2a52c6108c0e4d040b021775a2b573f32d78b7ac8652ff46fd549f780","src/qlog.rs":"b1e6108b018abb077f218d1806e0a83370afa87709e26b3d51f482ae5d9b9c82","src/qpack_decoder_receiver.rs":"c927dfc3e58c71d282210ba79280f6f03e789733bc3bedc247e68bab516b9e9e","src/qpack_encoder_receiver.rs":"d0ac03cc111b6e1c555a8654d3234116f2b135b5b040edac23cefe2d640beba9","src/recv_message.rs":"06666c22101cda41de14682dc7e2e6721f2821bd45baefc22caceae4ccfcf2e0","src/request_target.rs":"6041a69a0a74969ec08bc164509c055e9bad99f53bbeb16c0aa17d108dd68b8c","src/send_message.rs":"70f8a91d85515f42a64a88bd2a9480175b12596bc082f77587cc5bcff9ce996c","src/server.rs":"ab6d4c80cb5f6c070f74d8df27e7bd62d5c8a8e7756ff9d1a31d3f9ff91327a1","src/server_connection_events.rs":"12d353ca6301467f6d475dde3b789951a5716c89ddd7dbf1383efef8082361f3","src/server_events.rs":"c96cff96d5893a9ab7165d17e3d1afaafc5492418b30003c1c26ca8f489ab7ca","src/settings.rs":"476b154b5eea4c8d69a4a790fee3e527cef4d375df1cfb5eed04ec56406fe15a","src/stream_type_reader.rs":"7a7226b7911d69f7e00ec4987c2a32a5e8a33463203398cbee1e6645d2691478","tests/httpconn.rs":"bb6927801a8c75e4f05eb6cdb1e7f2d57be69b74e68ddad2a1614f2aeed04369","tests/priority.rs":"3418be17fbdfdbcfd80dc4532f9365f405925442fabc916f2b22f90aee89629f","tests/send_message.rs":"1e893216d9252e6fb69a0fb291b4f8b8ea954847c346ff7f9347d7895618cabf","tests/webtransport.rs":"cb30d348c0ce05efb722abac3b1c524216fa4cbde8b62a1d1e3238c3fadecbe7"},"package":null}
{"files":{"Cargo.toml":"d91d814a49a77d19195fbeaed449de6730802ad429b2f6a7e06524e599fcf0e2","src/buffered_send_stream.rs":"f45bdf9ad2a04b3828c74ff5440681d3c9d1af39b55470e4f729842dc2412295","src/client_events.rs":"e1392e7bbb62fb0505a4d8bcd27559699bbf38f3c94e7d8cae7291db82e6334c","src/conn_params.rs":"224a8ea6ef632930a7788a1cabf47ce69ad41bd4bc8dcf3053fbd998fdb38e82","src/connection.rs":"09aeb123f8dc6b903dd7d30579e5bb09ed8f70bfae563fb2fcc1871c67d604d4","src/connection_client.rs":"c38ebb402ce410e872866e4093f806f6c1bae25b1de320e22a0f99efb847ac5e","src/connection_server.rs":"ca33b50650bd1ca2a952851b72712d55ec2e48b48f1f06e4184c808b8e1e009a","src/control_stream_local.rs":"d6ecc0adc926e1d5cec9a378317f9dfcfeeb9840a0873a2afb380c2d252d8c54","src/control_stream_remote.rs":"59eb4041e366d92f9f294e8446755caa5e91fd943bba7b79b726698ba13be248","src/features/extended_connect/mod.rs":"3b02f6b18627f3855465a81b1d9b285e6f13839e75a8a6db648ed9082908d7f0","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"7e3bdd591b9c7d02f69954629f889d52bd54f13dbca11d555e614138c2a55107","src/features/extended_connect/tests/webtransport/mod.rs":"a30ea715f5271a826a739278b18e145964dedbce7026eed45f1b7d0355c407d5","src/features/extended_connect/tests/webtransport/negotiation.rs":"98254ef8446581ec520026b04ef9549645602181b61602c9936f6660141edf0b","src/features/extended_connect/tests/webtransport/sessions.rs":"de3d836f666c2bec31e70b33bdc2669572cabbe17df2225db7282613a224a364","src/features/extended_connect/tests/webtransport/streams.rs":"8b3c34cac1b2171252a4bb53d420ac2098549a20309c327bf56e2e9ba9e33538","src/features/extended_connect/webtransport_session.rs":"a6472eca50a2d097aa6ba8a76b45ae69fe2edd2696b2953945faa3ce6e7417f9","src/features/extended_connect/webtransport_streams.rs":"a9a106eefc93a9f6e9e1c246df64904353de1c4fbcd394b338e6b117f6c677f5","src/features/mod.rs":"925aae4427ad82e4d019354802b223d53db5e5585d4a940f5417a24a9503d7ee","src/frames/hframe.rs":"56c36ac597504f28c73cf2370acd82104f8c7a7b9ffc0f6d222378abc524482d","src/frames/mod.rs":"7d0a46ca147336d14781edb8dbee8b03c2e4bcd6646f5473a9d93d31fe73fecb","src/frames/reader.rs":"4883e25064da1fb3a6ae46b5d15e6bcfec9c5bbea55a1937ecdb9465b62a93b2","src/frames/tests/hframe.rs":"01ec74eb3eb25d95042aa0263f9267f89535e6b7b8c1161fab4ba9ee5352d4a7","src/frames/tests/mod.rs":"0610609b316767a6a022837d32ee0452e37ea296fde37e51bec87e7c77e923a3","src/frames/tests/reader.rs":"2bfadc7afbc41bff9f5f930b31550259a8a92484d35f6c5d8dd8fd9acfb88f5b","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"c80518d1569de277767c7ccb7441898aadbfc5fb2afb968c1d5105f8d175ccff","src/headers_checks.rs":"44891c16dda6b7ef742058ecb0a8d34e219c51cae1216c09c661cf72d9a5e7d5","src/lib.rs":"ed8da14e573cc5a97afb012a78af7f076eb83b5cc20cb4fe432eb7136a3ffe52","src/priority.rs":"10d9dcfcd4585f2ca256daf254c78a428297c41976c6548f19cd3ed2222b7cd2","src/push_controller.rs":"eb27c7c2a52c6108c0e4d040b021775a2b573f32d78b7ac8652ff46fd549f780","src/qlog.rs":"b1e6108b018abb077f218d1806e0a83370afa87709e26b3d51f482ae5d9b9c82","src/qpack_decoder_receiver.rs":"c927dfc3e58c71d282210ba79280f6f03e789733bc3bedc247e68bab516b9e9e","src/qpack_encoder_receiver.rs":"d0ac03cc111b6e1c555a8654d3234116f2b135b5b040edac23cefe2d640beba9","src/recv_message.rs":"06666c22101cda41de14682dc7e2e6721f2821bd45baefc22caceae4ccfcf2e0","src/request_target.rs":"6041a69a0a74969ec08bc164509c055e9bad99f53bbeb16c0aa17d108dd68b8c","src/send_message.rs":"70f8a91d85515f42a64a88bd2a9480175b12596bc082f77587cc5bcff9ce996c","src/server.rs":"ab6d4c80cb5f6c070f74d8df27e7bd62d5c8a8e7756ff9d1a31d3f9ff91327a1","src/server_connection_events.rs":"12d353ca6301467f6d475dde3b789951a5716c89ddd7dbf1383efef8082361f3","src/server_events.rs":"c96cff96d5893a9ab7165d17e3d1afaafc5492418b30003c1c26ca8f489ab7ca","src/settings.rs":"476b154b5eea4c8d69a4a790fee3e527cef4d375df1cfb5eed04ec56406fe15a","src/stream_type_reader.rs":"7a7226b7911d69f7e00ec4987c2a32a5e8a33463203398cbee1e6645d2691478","tests/httpconn.rs":"bb6927801a8c75e4f05eb6cdb1e7f2d57be69b74e68ddad2a1614f2aeed04369","tests/priority.rs":"3418be17fbdfdbcfd80dc4532f9365f405925442fabc916f2b22f90aee89629f","tests/send_message.rs":"b5435045b16429d9e626ea94a8f10e2937e1a5a878af0035763a4f5ec09bf53c","tests/webtransport.rs":"25794305017ff58e57dc3c3b9b078e5bfc1814ea82a521b7b7156228e613c092"},"package":null}

22
third_party/rust/neqo-http3/Cargo.toml поставляемый
Просмотреть файл

@ -11,21 +11,23 @@
[package]
edition = "2018"
rust-version = "1.70.0"
rust-version = "1.74.0"
name = "neqo-http3"
version = "0.7.0"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
version = "0.7.1"
authors = ["The Neqo Authors <necko@mozilla.com>"]
homepage = "https://github.com/mozilla/neqo/"
license = "MIT OR Apache-2.0"
repository = "https://github.com/mozilla/neqo/"
[dependencies]
enumset = "1.1.2"
lazy_static = "1.4"
sfv = "0.9.3"
smallvec = "1.11.1"
enumset = "1.1"
qlog = "0.12"
sfv = "0.9"
smallvec = "1.11"
url = "2.5"
[dependencies.log]
version = "0.4.17"
version = "0.4"
default-features = false
[dependencies.neqo-common]
@ -40,10 +42,6 @@ path = "./../neqo-qpack"
[dependencies.neqo-transport]
path = "./../neqo-transport"
[dependencies.qlog]
git = "https://github.com/cloudflare/quiche"
rev = "09ea4b244096a013071cfe2175bbf2945fb7f8d1"
[dev-dependencies.test-fixture]
path = "../test-fixture"

Просмотреть файл

@ -1306,8 +1306,9 @@ mod tests {
StreamType, Version, RECV_BUFFER_SIZE, SEND_BUFFER_SIZE,
};
use test_fixture::{
addr, anti_replay, default_server_h3, fixture_init, new_server, now,
CountingConnectionIdGenerator, DEFAULT_ALPN_H3, DEFAULT_KEYS, DEFAULT_SERVER_NAME,
anti_replay, default_server_h3, fixture_init, new_server, now,
CountingConnectionIdGenerator, DEFAULT_ADDR, DEFAULT_ALPN_H3, DEFAULT_KEYS,
DEFAULT_SERVER_NAME,
};
use super::{
@ -1340,8 +1341,8 @@ mod tests {
Http3Client::new(
DEFAULT_SERVER_NAME,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
Http3Parameters::default()
.connection_parameters(
// Disable compatible upgrade, which complicates tests.

Просмотреть файл

@ -14,7 +14,7 @@ use neqo_common::event::Provider;
use neqo_crypto::AuthenticationStatus;
use neqo_transport::{ConnectionParameters, StreamId, StreamType};
use test_fixture::{
addr, anti_replay, fixture_init, now, CountingConnectionIdGenerator, DEFAULT_ALPN_H3,
anti_replay, fixture_init, now, CountingConnectionIdGenerator, DEFAULT_ADDR, DEFAULT_ALPN_H3,
DEFAULT_KEYS, DEFAULT_SERVER_NAME,
};
@ -38,8 +38,8 @@ pub fn default_http3_client(client_params: Http3Parameters) -> Http3Client {
Http3Client::new(
DEFAULT_SERVER_NAME,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
client_params,
now(),
)

Просмотреть файл

@ -74,10 +74,7 @@ impl HFrame {
Self::MaxPushId { .. } => H3_FRAME_TYPE_MAX_PUSH_ID,
Self::PriorityUpdateRequest { .. } => H3_FRAME_TYPE_PRIORITY_UPDATE_REQUEST,
Self::PriorityUpdatePush { .. } => H3_FRAME_TYPE_PRIORITY_UPDATE_PUSH,
Self::Grease => {
let r = random(7);
Decoder::from(&r).decode_uint(7).unwrap() * 0x1f + 0x21
}
Self::Grease => Decoder::from(&random::<7>()).decode_uint(7).unwrap() * 0x1f + 0x21,
}
}
@ -120,7 +117,7 @@ impl HFrame {
}
Self::Grease => {
// Encode some number of random bytes.
let r = random(8);
let r = random::<8>();
enc.encode_vvec(&r[1..usize::from(1 + (r[0] & 0x7))]);
}
Self::PriorityUpdateRequest {

Просмотреть файл

@ -4,7 +4,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lazy_static::lazy_static;
use std::sync::OnceLock;
use neqo_common::event::Provider;
use neqo_crypto::AuthenticationStatus;
use neqo_http3::{
@ -15,14 +16,14 @@ use test_fixture::*;
const RESPONSE_DATA: &[u8] = &[0x61, 0x62, 0x63];
lazy_static! {
static ref RESPONSE_HEADER_NO_DATA: Vec<Header> =
vec![Header::new(":status", "200"), Header::new("something", "3")];
fn response_header_no_data() -> &'static Vec<Header> {
static HEADERS: OnceLock<Vec<Header>> = OnceLock::new();
HEADERS.get_or_init(|| vec![Header::new(":status", "200"), Header::new("something", "3")])
}
lazy_static! {
static ref RESPONSE_HEADER_103: Vec<Header> =
vec![Header::new(":status", "103"), Header::new("link", "...")];
fn response_header_103() -> &'static Vec<Header> {
static HEADERS: OnceLock<Vec<Header>> = OnceLock::new();
HEADERS.get_or_init(|| vec![Header::new(":status", "103"), Header::new("link", "...")])
}
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
@ -68,7 +69,7 @@ fn send_trailers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
}
fn send_informational_headers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
request.send_headers(&RESPONSE_HEADER_103)
request.send_headers(response_header_103())
}
fn send_headers(request: &mut Http3OrWebTransportStream) -> Result<(), Error> {
@ -90,7 +91,7 @@ fn process_client_events(conn: &mut Http3Client) {
Header::new(":status", "200"),
Header::new("content-length", "3"),
])
|| (headers.as_ref() == *RESPONSE_HEADER_103)
|| (headers.as_ref() == *response_header_103())
);
assert!(!fin);
response_header_found = true;
@ -116,7 +117,7 @@ fn process_client_events_no_data(conn: &mut Http3Client) {
while let Some(event) = conn.next_event() {
match event {
Http3ClientEvent::HeaderReady { headers, fin, .. } => {
assert_eq!(headers.as_ref(), *RESPONSE_HEADER_NO_DATA);
assert_eq!(headers.as_ref(), *response_header_no_data());
fin_received = fin;
response_header_found = true;
}
@ -201,7 +202,7 @@ fn response_trailers3() {
#[test]
fn response_trailers_no_data() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(&RESPONSE_HEADER_NO_DATA).unwrap();
request.send_headers(response_header_no_data()).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
send_trailers(&mut request).unwrap();
exchange_packets(&mut hconn_c, &mut hconn_s);
@ -258,10 +259,10 @@ fn trailers_after_close() {
#[test]
fn multiple_response_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(&RESPONSE_HEADER_NO_DATA).unwrap();
request.send_headers(response_header_no_data()).unwrap();
assert_eq!(
request.send_headers(&RESPONSE_HEADER_NO_DATA),
request.send_headers(response_header_no_data()),
Err(Error::InvalidHeader)
);
@ -273,7 +274,7 @@ fn multiple_response_headers() {
#[test]
fn informational_after_response_headers() {
let (mut hconn_c, mut hconn_s, mut request) = connect_send_and_receive_request();
request.send_headers(&RESPONSE_HEADER_NO_DATA).unwrap();
request.send_headers(response_header_no_data()).unwrap();
assert_eq!(
send_informational_headers(&mut request),
@ -307,7 +308,7 @@ fn non_trailers_headers_after_data() {
exchange_packets(&mut hconn_c, &mut hconn_s);
assert_eq!(
request.send_headers(&RESPONSE_HEADER_NO_DATA),
request.send_headers(response_header_no_data()),
Err(Error::InvalidHeader)
);

Просмотреть файл

@ -15,7 +15,7 @@ use neqo_http3::{
};
use neqo_transport::{StreamId, StreamType};
use test_fixture::{
addr, anti_replay, fixture_init, now, CountingConnectionIdGenerator, DEFAULT_ALPN_H3,
anti_replay, fixture_init, now, CountingConnectionIdGenerator, DEFAULT_ADDR, DEFAULT_ALPN_H3,
DEFAULT_KEYS, DEFAULT_SERVER_NAME,
};
@ -24,8 +24,8 @@ fn connect() -> (Http3Client, Http3Server) {
let mut client = Http3Client::new(
DEFAULT_SERVER_NAME,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
Http3Parameters::default().webtransport(true),
now(),
)

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"2eabb2ad2846a08b51b306634ed75dc14ab3a43738b1190e3b4c4f2beb00b8e2","src/decoder.rs":"7e468d59adff1fa9373cbb703d13a7503f721a89bebafd049feaf0308a39b606","src/decoder_instructions.rs":"d991d70e51f079bc5b30d3982fd0176edfa9bb7ba14c17a20ec3eea878c56206","src/encoder.rs":"e026da38c2c3410a4e9aa330cda09ac411008772dd66d262d6c375601cebf481","src/encoder_instructions.rs":"86e3abbd9cf94332041326ac6cf806ed64623e3fd38dbc0385b1f63c37e73fd9","src/header_block.rs":"3925476df69b90d950594faadc5cb24c374d46de8c75a374a235f0d27323a7d8","src/huffman.rs":"8b0b2ea069c2a6eb6677b076b99b08ac0d29eabe1f2bbbab37f18f49187ef276","src/huffman_decode_helper.rs":"81309e27ff8f120a10c0b1598888ded21b76e297dc02cea8c7378d6a6627d62a","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"196114397c2b1bf6ef154206018f519b012789cf712e89b069a7616d7278ef3a","src/prefix.rs":"fb4a9acbcf6fd3178f4474404cd3d3b131abca934f69fe14a9d744bc7e636dc5","src/qlog.rs":"e320007ea8309546b26f9c0019ab8722da80dbd38fa976233fd8ae19a0af637c","src/qpack_send_buf.rs":"14d71310c260ee15ea40a783998b507c968eef12db2892b47c689e872b5242a5","src/reader.rs":"b9a7dccd726f471fc24f1d3304f03ac0a039c0828aac7b33c927be07d395c655","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"05dbec6483bb24c9fc8d721b70fdfefc2df53b458488b55104147f13c386a47d"},"package":null}
{"files":{"Cargo.toml":"385fb0450ea02925108585a1d4e48ad6ef304a5f3c5f4385ee5f8b829bc85393","src/decoder.rs":"7e468d59adff1fa9373cbb703d13a7503f721a89bebafd049feaf0308a39b606","src/decoder_instructions.rs":"d991d70e51f079bc5b30d3982fd0176edfa9bb7ba14c17a20ec3eea878c56206","src/encoder.rs":"e026da38c2c3410a4e9aa330cda09ac411008772dd66d262d6c375601cebf481","src/encoder_instructions.rs":"86e3abbd9cf94332041326ac6cf806ed64623e3fd38dbc0385b1f63c37e73fd9","src/header_block.rs":"3925476df69b90d950594faadc5cb24c374d46de8c75a374a235f0d27323a7d8","src/huffman.rs":"4b3308ed71da233181d99101bc2eeb30eca7ec30ba776f055f01e94f10974a24","src/huffman_decode_helper.rs":"e9d405f00327a124d1751481077c31fb6348daeee7032ea3b0fa5cf6d5d8add1","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"196114397c2b1bf6ef154206018f519b012789cf712e89b069a7616d7278ef3a","src/prefix.rs":"fb4a9acbcf6fd3178f4474404cd3d3b131abca934f69fe14a9d744bc7e636dc5","src/qlog.rs":"e320007ea8309546b26f9c0019ab8722da80dbd38fa976233fd8ae19a0af637c","src/qpack_send_buf.rs":"14d71310c260ee15ea40a783998b507c968eef12db2892b47c689e872b5242a5","src/reader.rs":"b9a7dccd726f471fc24f1d3304f03ac0a039c0828aac7b33c927be07d395c655","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"05dbec6483bb24c9fc8d721b70fdfefc2df53b458488b55104147f13c386a47d"},"package":null}

18
third_party/rust/neqo-qpack/Cargo.toml поставляемый
Просмотреть файл

@ -11,18 +11,20 @@
[package]
edition = "2018"
rust-version = "1.70.0"
rust-version = "1.74.0"
name = "neqo-qpack"
version = "0.7.0"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
version = "0.7.1"
authors = ["The Neqo Authors <necko@mozilla.com>"]
homepage = "https://github.com/mozilla/neqo/"
license = "MIT OR Apache-2.0"
repository = "https://github.com/mozilla/neqo/"
[dependencies]
lazy_static = "~1.4.0"
static_assertions = "~1.1.0"
qlog = "0.12"
static_assertions = "1.1"
[dependencies.log]
version = "~0.4.17"
version = "0.4"
default-features = false
[dependencies.neqo-common]
@ -34,10 +36,6 @@ path = "./../neqo-crypto"
[dependencies.neqo-transport]
path = "./../neqo-transport"
[dependencies.qlog]
git = "https://github.com/cloudflare/quiche"
rev = "09ea4b244096a013071cfe2175bbf2945fb7f8d1"
[dev-dependencies.test-fixture]
path = "../test-fixture"

4
third_party/rust/neqo-qpack/src/huffman.rs поставляемый
Просмотреть файл

@ -7,7 +7,7 @@
use std::convert::TryFrom;
use crate::{
huffman_decode_helper::{HuffmanDecoderNode, HUFFMAN_DECODE_ROOT},
huffman_decode_helper::{huffman_decoder_root, HuffmanDecoderNode},
huffman_table::HUFFMAN_TABLE,
Error, Res,
};
@ -93,7 +93,7 @@ pub fn decode_huffman(input: &[u8]) -> Res<Vec<u8>> {
}
fn decode_character(reader: &mut BitReader) -> Res<Option<u16>> {
let mut node: &HuffmanDecoderNode = &HUFFMAN_DECODE_ROOT;
let mut node: &HuffmanDecoderNode = huffman_decoder_root();
let mut i = 0;
while node.value.is_none() {
match reader.read_bit() {

Просмотреть файл

@ -4,9 +4,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::convert::TryFrom;
use lazy_static::lazy_static;
use std::{convert::TryFrom, sync::OnceLock};
use crate::huffman_table::HUFFMAN_TABLE;
@ -15,8 +13,9 @@ pub struct HuffmanDecoderNode {
pub value: Option<u16>,
}
lazy_static! {
pub static ref HUFFMAN_DECODE_ROOT: HuffmanDecoderNode = make_huffman_tree(0, 0);
pub fn huffman_decoder_root() -> &'static HuffmanDecoderNode {
static ROOT: OnceLock<HuffmanDecoderNode> = OnceLock::new();
ROOT.get_or_init(|| make_huffman_tree(0, 0))
}
fn make_huffman_tree(prefix: u32, len: u8) -> HuffmanDecoderNode {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

38
third_party/rust/neqo-transport/Cargo.toml поставляемый
Просмотреть файл

@ -11,27 +11,36 @@
[package]
edition = "2018"
rust-version = "1.70.0"
rust-version = "1.74.0"
name = "neqo-transport"
version = "0.7.0"
authors = [
"EKR <ekr@rtfm.com>",
"Andy Grover <agrover@mozilla.com>",
]
version = "0.7.1"
authors = ["The Neqo Authors <necko@mozilla.com>"]
homepage = "https://github.com/mozilla/neqo/"
license = "MIT OR Apache-2.0"
repository = "https://github.com/mozilla/neqo/"
[[bench]]
name = "transfer"
harness = false
required-features = ["bench"]
[[bench]]
name = "rx_stream_orderer"
harness = false
required-features = ["bench"]
[[bench]]
name = "range_tracker"
harness = false
required-features = ["bench"]
[dependencies]
indexmap = "1.9.3"
lazy_static = "1.4"
smallvec = "1.11.1"
indexmap = "1.9"
qlog = "0.12"
smallvec = "1.11"
[dependencies.log]
version = "0.4.17"
version = "0.4"
default-features = false
[dependencies.neqo-common]
@ -40,14 +49,13 @@ path = "../neqo-common"
[dependencies.neqo-crypto]
path = "../neqo-crypto"
[dependencies.qlog]
git = "https://github.com/cloudflare/quiche"
rev = "09ea4b244096a013071cfe2175bbf2945fb7f8d1"
[dev-dependencies]
criterion = "0.5.1"
enum-map = "2.7"
[dev-dependencies.criterion]
version = "0.5"
features = ["html_reports"]
[dev-dependencies.test-fixture]
path = "../test-fixture"

44
third_party/rust/neqo-transport/benches/range_tracker.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,44 @@
use criterion::{criterion_group, criterion_main, Criterion}; // black_box
use neqo_transport::send_stream::RangeTracker;
const CHUNK: u64 = 1000;
const END: u64 = 100_000;
fn build_coalesce(len: u64) -> RangeTracker {
let mut used = RangeTracker::default();
used.mark_acked(0, CHUNK as usize);
used.mark_sent(CHUNK, END as usize);
// leave a gap or it will coalesce here
for i in 2..=len {
// These do not get immediately coalesced when marking since they're not at the end or start
used.mark_acked(i * CHUNK, CHUNK as usize);
}
used
}
fn coalesce(c: &mut Criterion, count: u64) {
c.bench_function(
&format!("coalesce_acked_from_zero {count}+1 entries"),
|b| {
b.iter_batched_ref(
|| build_coalesce(count),
|used| {
used.mark_acked(CHUNK, CHUNK as usize);
let tail = (count + 1) * CHUNK;
used.mark_sent(tail, CHUNK as usize);
used.mark_acked(tail, CHUNK as usize);
},
criterion::BatchSize::SmallInput,
)
},
);
}
fn benchmark_coalesce(c: &mut Criterion) {
coalesce(c, 1);
coalesce(c, 3);
coalesce(c, 10);
coalesce(c, 1000);
}
criterion_group!(benches, benchmark_coalesce);
criterion_main!(benches);

64
third_party/rust/neqo-transport/benches/transfer.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,64 @@
use std::time::Duration;
use criterion::{criterion_group, criterion_main, BatchSize::SmallInput, Criterion};
use test_fixture::{
boxed,
sim::{
connection::{ConnectionNode, ReceiveData, SendData},
network::{Delay, TailDrop},
Simulator,
},
};
const ZERO: Duration = Duration::from_millis(0);
const JITTER: Duration = Duration::from_millis(10);
const TRANSFER_AMOUNT: usize = 1 << 22; // 4Mbyte
fn benchmark_transfer(c: &mut Criterion, label: &str, seed: Option<impl AsRef<str>>) {
c.bench_function(label, |b| {
b.iter_batched(
|| {
let nodes = boxed![
ConnectionNode::default_client(boxed![SendData::new(TRANSFER_AMOUNT)]),
TailDrop::dsl_uplink(),
Delay::new(ZERO..JITTER),
ConnectionNode::default_server(boxed![ReceiveData::new(TRANSFER_AMOUNT)]),
TailDrop::dsl_downlink(),
Delay::new(ZERO..JITTER),
];
let mut sim = Simulator::new(label, nodes);
if let Some(seed) = &seed {
sim.seed_str(seed);
}
sim.setup()
},
|sim| {
sim.run();
},
SmallInput,
)
});
}
fn benchmark_transfer_variable(c: &mut Criterion) {
benchmark_transfer(
c,
"Run multiple transfers with varying seeds",
std::env::var("SIMULATION_SEED").ok(),
);
}
fn benchmark_transfer_fixed(c: &mut Criterion) {
benchmark_transfer(
c,
"Run multiple transfers with the same seed",
Some("62df6933ba1f543cece01db8f27fb2025529b27f93df39e19f006e1db3b8c843"),
);
}
criterion_group! {
name = transfer;
config = Criterion::default().warm_up_time(Duration::from_secs(5)).measurement_time(Duration::from_secs(15));
targets = benchmark_transfer_variable, benchmark_transfer_fixed
}
criterion_main!(transfer);

32
third_party/rust/neqo-transport/src/cid.rs поставляемый
Просмотреть файл

@ -16,8 +16,8 @@ use std::{
};
use neqo_common::{hex, hex_with_len, qinfo, Decoder, Encoder};
use neqo_crypto::random;
use smallvec::SmallVec;
use neqo_crypto::{random, randomize};
use smallvec::{smallvec, SmallVec};
use crate::{
frame::FRAME_TYPE_NEW_CONNECTION_ID, packet::PacketBuilder, recovery::RecoveryToken,
@ -41,14 +41,16 @@ pub struct ConnectionId {
impl ConnectionId {
pub fn generate(len: usize) -> Self {
assert!(matches!(len, 0..=MAX_CONNECTION_ID_LEN));
Self::from(random(len))
let mut cid = smallvec![0; len];
randomize(&mut cid);
Self { cid }
}
// Apply a wee bit of greasing here in picking a length between 8 and 20 bytes long.
pub fn generate_initial() -> Self {
let v = random(1);
let v = random::<1>()[0];
// Bias selection toward picking 8 (>50% of the time).
let len: usize = max(8, 5 + (v[0] & (v[0] >> 4))).into();
let len: usize = max(8, 5 + (v & (v >> 4))).into();
Self::generate(len)
}
@ -75,12 +77,6 @@ impl From<SmallVec<[u8; MAX_CONNECTION_ID_LEN]>> for ConnectionId {
}
}
impl From<Vec<u8>> for ConnectionId {
fn from(cid: Vec<u8>) -> Self {
Self::from(SmallVec::from(cid))
}
}
impl<T: AsRef<[u8]> + ?Sized> From<&T> for ConnectionId {
fn from(buf: &T) -> Self {
Self::from(SmallVec::from(buf.as_ref()))
@ -222,7 +218,9 @@ impl ConnectionIdDecoder for RandomConnectionIdGenerator {
impl ConnectionIdGenerator for RandomConnectionIdGenerator {
fn generate_cid(&mut self) -> Option<ConnectionId> {
Some(ConnectionId::from(&random(self.len)))
let mut buf = smallvec![0; self.len];
randomize(&mut buf);
Some(ConnectionId::from(buf))
}
fn as_decoder(&self) -> &dyn ConnectionIdDecoder {
@ -250,8 +248,8 @@ pub struct ConnectionIdEntry<SRT: Clone + PartialEq> {
impl ConnectionIdEntry<[u8; 16]> {
/// Create a random stateless reset token so that it is hard to guess the correct
/// value and reset the connection.
fn random_srt() -> [u8; 16] {
<[u8; 16]>::try_from(&random(16)[..]).unwrap()
pub fn random_srt() -> [u8; 16] {
random::<16>()
}
/// Create the first entry, which won't have a stateless reset token.
@ -476,7 +474,7 @@ impl ConnectionIdManager {
.add_local(ConnectionIdEntry::new(self.next_seqno, cid.clone(), ()));
self.next_seqno += 1;
let srt = <[u8; 16]>::try_from(&random(16)[..]).unwrap();
let srt = ConnectionIdEntry::random_srt();
Ok((cid, srt))
} else {
Err(Error::ConnectionIdsExhausted)
@ -565,7 +563,7 @@ impl ConnectionIdManager {
if let Some(cid) = maybe_cid {
assert_ne!(cid.len(), 0);
// TODO: generate the stateless reset tokens from the connection ID and a key.
let srt = <[u8; 16]>::try_from(&random(16)[..]).unwrap();
let srt = ConnectionIdEntry::random_srt();
let seqno = self.next_seqno;
self.next_seqno += 1;
@ -573,7 +571,7 @@ impl ConnectionIdManager {
.add_local(ConnectionIdEntry::new(seqno, cid.clone(), ()));
let entry = ConnectionIdEntry::new(seqno, cid, srt);
debug_assert!(self.write_entry(&entry, builder, stats)?);
self.write_entry(&entry, builder, stats)?;
tokens.push(RecoveryToken::NewConnectionId(entry));
}
}

Просмотреть файл

@ -23,7 +23,7 @@ use neqo_common::{
qlog::NeqoQlog, qtrace, qwarn, Datagram, Decoder, Encoder, Role,
};
use neqo_crypto::{
agent::CertificateInfo, random, Agent, AntiReplay, AuthenticationStatus, Cipher, Client, Group,
agent::CertificateInfo, Agent, AntiReplay, AuthenticationStatus, Cipher, Client, Group,
HandshakeState, PrivateKey, PublicKey, ResumptionToken, SecretAgentInfo, SecretAgentPreInfo,
Server, ZeroRttChecker,
};
@ -59,6 +59,7 @@ use crate::{
version::{Version, WireVersion},
AppError, ConnectionError, Error, Res, StreamId,
};
mod dump;
mod idle;
pub mod params;
@ -66,6 +67,7 @@ mod saved;
mod state;
#[cfg(test)]
pub mod test_internal;
use dump::dump_packet;
use idle::IdleTimeout;
pub use params::ConnectionParameters;
@ -78,9 +80,6 @@ pub use state::{ClosingFrame, State};
pub use crate::send_stream::{RetransmissionPriority, SendStreamStats, TransmissionPriority};
#[derive(Debug, Default)]
struct Packet(Vec<u8>);
/// The number of Initial packets that the client will send in response
/// to receiving an undecryptable packet during the early part of the
/// handshake. This is a hack, but a useful one.
@ -1576,7 +1575,6 @@ impl Connection {
/// During connection setup, the first path needs to be setup.
/// This uses the connection IDs that were provided during the handshake
/// to setup that path.
#[allow(clippy::or_fun_call)] // Remove when MSRV >= 1.59
fn setup_handshake_path(&mut self, path: &PathRef, now: Instant) {
self.paths.make_permanent(
path,
@ -2404,7 +2402,7 @@ impl Connection {
} else {
// The other side didn't provide a stateless reset token.
// That's OK, they can try guessing this.
<[u8; 16]>::try_from(&random(16)[..]).unwrap()
ConnectionIdEntry::random_srt()
};
self.paths
.primary()
@ -2585,10 +2583,16 @@ impl Connection {
) -> Res<()> {
qtrace!([self], "Handshake space={} data={:0x?}", space, data);
let was_authentication_pending =
*self.crypto.tls.state() == HandshakeState::AuthenticationPending;
let try_update = data.is_some();
match self.crypto.handshake(now, space, data)? {
HandshakeState::Authenticated(_) | HandshakeState::InProgress => (),
HandshakeState::AuthenticationPending => self.events.authentication_needed(),
HandshakeState::AuthenticationPending => {
if !was_authentication_pending {
self.events.authentication_needed()
}
}
HandshakeState::EchFallbackAuthenticationPending(public_name) => self
.events
.ech_fallback_authentication_needed(public_name.clone()),

Просмотреть файл

@ -6,7 +6,7 @@
use std::{mem, time::Duration};
use test_fixture::{addr_v4, assertions};
use test_fixture::{assertions, DEFAULT_ADDR_V4};
use super::{
super::{ConnectionParameters, ACK_RATIO_SCALE},
@ -164,7 +164,7 @@ fn migrate_ack_delay() {
let mut now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
client
.migrate(Some(addr_v4()), Some(addr_v4()), true, now)
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), true, now)
.unwrap();
let client1 = send_something(&mut client, now);

Просмотреть файл

@ -18,8 +18,8 @@ use neqo_crypto::{
constants::TLS_CHACHA20_POLY1305_SHA256, generate_ech_keys, AuthenticationStatus,
};
use test_fixture::{
self, addr, assertions, assertions::assert_coalesced_0rtt, datagram, fixture_init, now,
split_datagram,
self, assertions, assertions::assert_coalesced_0rtt, datagram, fixture_init, now,
split_datagram, DEFAULT_ADDR,
};
use super::{
@ -122,8 +122,8 @@ fn no_alpn() {
"example.com",
&["bad-alpn"],
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
ConnectionParameters::default(),
now(),
)
@ -251,8 +251,8 @@ fn chacha20poly1305() {
test_fixture::DEFAULT_SERVER_NAME,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(EmptyConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
ConnectionParameters::default(),
now(),
)
@ -730,8 +730,8 @@ fn connect_one_version() {
test_fixture::DEFAULT_SERVER_NAME,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
ConnectionParameters::default().versions(version, vec![version]),
now(),
)
@ -1135,3 +1135,54 @@ fn implicit_rtt_server() {
// an RTT estimate from having discarded the Initial packet number space.
assert_eq!(server.stats().rtt, RTT);
}
#[test]
fn emit_authentication_needed_once() {
let mut client = default_client();
let mut server = Connection::new_server(
test_fixture::LONG_CERT_KEYS,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
ConnectionParameters::default(),
)
.expect("create a server");
let client1 = client.process(None, now());
assert!(client1.as_dgram_ref().is_some());
// The entire server flight doesn't fit in a single packet because the
// certificate is large, therefore the server will produce 2 packets.
let server1 = server.process(client1.as_dgram_ref(), now());
assert!(server1.as_dgram_ref().is_some());
let server2 = server.process(None, now());
assert!(server2.as_dgram_ref().is_some());
let authentication_needed_count = |client: &mut Connection| {
client
.events()
.filter(|e| matches!(e, ConnectionEvent::AuthenticationNeeded))
.count()
};
// Upon receiving the first packet, the client has the server certificate,
// but not yet all required handshake data. It moves to
// `HandshakeState::AuthenticationPending` and emits a
// `ConnectionEvent::AuthenticationNeeded` event.
//
// Note that this is a tiny bit fragile in that it depends on having a certificate
// that is within a fairly narrow range of sizes. It has to fit in a single
// packet, but be large enough that the CertificateVerify message does not
// also fit in the same packet. Our default test setup achieves this, but
// changes to the setup might invalidate this test.
let _ = client.process(server1.as_dgram_ref(), now());
assert_eq!(1, authentication_needed_count(&mut client));
assert!(client.peer_certificate().is_some());
// The `AuthenticationNeeded` event is still pending a call to
// `Connection::authenticated`. On receiving the second packet from the
// server, the client must not emit a another
// `ConnectionEvent::AuthenticationNeeded`.
let _ = client.process(server2.as_dgram_ref(), now());
assert_eq!(0, authentication_needed_count(&mut client));
}

Просмотреть файл

@ -13,9 +13,9 @@ use std::{
use neqo_common::{Datagram, Decoder};
use test_fixture::{
self, addr, addr_v4,
self,
assertions::{assert_v4_path, assert_v6_path},
fixture_init, new_neqo_qlog, now,
fixture_init, new_neqo_qlog, now, DEFAULT_ADDR, DEFAULT_ADDR_V4,
};
use super::{
@ -94,8 +94,8 @@ fn rebinding_port() {
server.stream_close_send(stream_id).unwrap();
let dgram = server.process_output(now()).dgram();
let dgram = dgram.unwrap();
assert_eq!(dgram.source(), addr());
assert_eq!(dgram.destination(), new_port(addr()));
assert_eq!(dgram.source(), DEFAULT_ADDR);
assert_eq!(dgram.destination(), new_port(DEFAULT_ADDR));
}
/// This simulates an attack where a valid packet is forwarded on
@ -109,7 +109,7 @@ fn path_forwarding_attack() {
let mut now = now();
let dgram = send_something(&mut client, now);
let dgram = change_path(&dgram, addr_v4());
let dgram = change_path(&dgram, DEFAULT_ADDR_V4);
server.process_input(&dgram, now);
// The server now probes the new (primary) path.
@ -188,7 +188,7 @@ fn migrate_immediate() {
let now = now();
client
.migrate(Some(addr_v4()), Some(addr_v4()), true, now)
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), true, now)
.unwrap();
let client1 = send_something(&mut client, now);
@ -229,7 +229,7 @@ fn migrate_rtt() {
let now = connect_rtt_idle(&mut client, &mut server, RTT);
client
.migrate(Some(addr_v4()), Some(addr_v4()), true, now)
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), true, now)
.unwrap();
// The RTT might be increased for the new path, so allow a little flexibility.
let rtt = client.paths.rtt();
@ -245,7 +245,7 @@ fn migrate_immediate_fail() {
let mut now = now();
client
.migrate(Some(addr_v4()), Some(addr_v4()), true, now)
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), true, now)
.unwrap();
let probe = client.process_output(now).dgram().unwrap();
@ -293,7 +293,7 @@ fn migrate_same() {
let now = now();
client
.migrate(Some(addr()), Some(addr()), true, now)
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), true, now)
.unwrap();
let probe = client.process_output(now).dgram().unwrap();
@ -320,7 +320,7 @@ fn migrate_same_fail() {
let mut now = now();
client
.migrate(Some(addr()), Some(addr()), true, now)
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), true, now)
.unwrap();
let probe = client.process_output(now).dgram().unwrap();
@ -375,7 +375,7 @@ fn migration(mut client: Connection) {
let now = now();
client
.migrate(Some(addr_v4()), Some(addr_v4()), false, now)
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), false, now)
.unwrap();
let probe = client.process_output(now).dgram().unwrap();
@ -449,8 +449,8 @@ fn migration_client_empty_cid() {
test_fixture::DEFAULT_SERVER_NAME,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(EmptyConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
ConnectionParameters::default(),
now(),
)
@ -568,22 +568,22 @@ fn preferred_address(hs_client: SocketAddr, hs_server: SocketAddr, preferred: So
/// Migration works for a new port number.
#[test]
fn preferred_address_new_port() {
let a = addr();
let a = DEFAULT_ADDR;
preferred_address(a, a, new_port(a));
}
/// Migration works for a new address too.
#[test]
fn preferred_address_new_address() {
let mut preferred = addr();
let mut preferred = DEFAULT_ADDR;
preferred.set_ip(IpAddr::V6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 2)));
preferred_address(addr(), addr(), preferred);
preferred_address(DEFAULT_ADDR, DEFAULT_ADDR, preferred);
}
/// Migration works for IPv4 addresses.
#[test]
fn preferred_address_new_port_v4() {
let a = addr_v4();
let a = DEFAULT_ADDR_V4;
preferred_address(a, a, new_port(a));
}
@ -623,7 +623,7 @@ fn preferred_address_ignore_loopback() {
/// A preferred address in the wrong address family is ignored.
#[test]
fn preferred_address_ignore_different_family() {
preferred_address_ignored(PreferredAddress::new_any(Some(addr_v4()), None));
preferred_address_ignored(PreferredAddress::new_any(Some(DEFAULT_ADDR_V4), None));
}
/// Disabling preferred addresses at the client means that it ignores a perfectly
@ -631,7 +631,7 @@ fn preferred_address_ignore_different_family() {
#[test]
fn preferred_address_disabled_client() {
let mut client = new_client(ConnectionParameters::default().disable_preferred_address());
let mut preferred = addr();
let mut preferred = DEFAULT_ADDR;
preferred.set_ip(IpAddr::V6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 2)));
let spa = PreferredAddress::new_any(None, Some(preferred));
let mut server = new_server(ConnectionParameters::default().preferred_address(spa));
@ -643,7 +643,7 @@ fn preferred_address_disabled_client() {
fn preferred_address_empty_cid() {
fixture_init();
let spa = PreferredAddress::new_any(None, Some(new_port(addr())));
let spa = PreferredAddress::new_any(None, Some(new_port(DEFAULT_ADDR)));
let res = Connection::new_server(
test_fixture::DEFAULT_KEYS,
test_fixture::DEFAULT_ALPN,
@ -706,33 +706,33 @@ fn preferred_address_client() {
fn migration_invalid_state() {
let mut client = default_client();
assert!(client
.migrate(Some(addr()), Some(addr()), false, now())
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
let mut server = default_server();
assert!(server
.migrate(Some(addr()), Some(addr()), false, now())
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
connect_force_idle(&mut client, &mut server);
assert!(server
.migrate(Some(addr()), Some(addr()), false, now())
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
client.close(now(), 0, "closing");
assert!(client
.migrate(Some(addr()), Some(addr()), false, now())
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
let close = client.process(None, now()).dgram();
let dgram = server.process(close.as_ref(), now()).dgram();
assert!(server
.migrate(Some(addr()), Some(addr()), false, now())
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
client.process_input(&dgram.unwrap(), now());
assert!(client
.migrate(Some(addr()), Some(addr()), false, now())
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
}
@ -753,32 +753,32 @@ fn migration_invalid_address() {
cant_migrate(None, None);
// Providing a zero port number isn't valid.
let mut zero_port = addr();
let mut zero_port = DEFAULT_ADDR;
zero_port.set_port(0);
cant_migrate(None, Some(zero_port));
cant_migrate(Some(zero_port), None);
// An unspecified remote address is bad.
let mut remote_unspecified = addr();
let mut remote_unspecified = DEFAULT_ADDR;
remote_unspecified.set_ip(IpAddr::V6(Ipv6Addr::from(0)));
cant_migrate(None, Some(remote_unspecified));
// Mixed address families is bad.
cant_migrate(Some(addr()), Some(addr_v4()));
cant_migrate(Some(addr_v4()), Some(addr()));
cant_migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR_V4));
cant_migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR));
// Loopback to non-loopback is bad.
cant_migrate(Some(addr()), Some(loopback()));
cant_migrate(Some(loopback()), Some(addr()));
cant_migrate(Some(DEFAULT_ADDR), Some(loopback()));
cant_migrate(Some(loopback()), Some(DEFAULT_ADDR));
assert_eq!(
client
.migrate(Some(addr()), Some(loopback()), true, now())
.migrate(Some(DEFAULT_ADDR), Some(loopback()), true, now())
.unwrap_err(),
Error::InvalidMigration
);
assert_eq!(
client
.migrate(Some(loopback()), Some(addr()), true, now())
.migrate(Some(loopback()), Some(DEFAULT_ADDR), true, now())
.unwrap_err(),
Error::InvalidMigration
);
@ -864,7 +864,7 @@ fn retire_prior_to_migration_failure() {
let original_cid = ConnectionId::from(get_cid(&send_something(&mut client, now())));
client
.migrate(Some(addr_v4()), Some(addr_v4()), false, now())
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), false, now())
.unwrap();
// The client now probes the new path.
@ -919,7 +919,7 @@ fn retire_prior_to_migration_success() {
let original_cid = ConnectionId::from(get_cid(&send_something(&mut client, now())));
client
.migrate(Some(addr_v4()), Some(addr_v4()), false, now())
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), false, now())
.unwrap();
// The client now probes the new path.

Просмотреть файл

@ -18,7 +18,7 @@ use std::{
use enum_map::enum_map;
use neqo_common::{event::Provider, qdebug, qtrace, Datagram, Decoder, Role};
use neqo_crypto::{random, AllowZeroRtt, AuthenticationStatus, ResumptionToken};
use test_fixture::{self, addr, fixture_init, new_neqo_qlog, now};
use test_fixture::{self, fixture_init, new_neqo_qlog, now, DEFAULT_ADDR};
use super::{Connection, ConnectionError, ConnectionId, Output, State};
use crate::{
@ -79,7 +79,7 @@ impl ConnectionIdDecoder for CountingConnectionIdGenerator {
impl ConnectionIdGenerator for CountingConnectionIdGenerator {
fn generate_cid(&mut self) -> Option<ConnectionId> {
let mut r = random(20);
let mut r = random::<20>();
r[0] = 8;
r[1] = u8::try_from(self.counter >> 24).unwrap();
r[2] = u8::try_from((self.counter >> 16) & 0xff).unwrap();
@ -107,8 +107,8 @@ pub fn new_client(params: ConnectionParameters) -> Connection {
test_fixture::DEFAULT_SERVER_NAME,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
DEFAULT_ADDR,
DEFAULT_ADDR,
params,
now(),
)

3
third_party/rust/neqo-transport/src/lib.rs поставляемый
Просмотреть файл

@ -30,6 +30,9 @@ pub mod recv_stream;
#[cfg(not(feature = "bench"))]
mod recv_stream;
mod rtt;
#[cfg(feature = "bench")]
pub mod send_stream;
#[cfg(not(feature = "bench"))]
mod send_stream;
mod sender;
pub mod server;

Просмотреть файл

@ -271,7 +271,7 @@ impl PacketBuilder {
let mask = if quic_bit { PACKET_BIT_FIXED_QUIC } else { 0 }
| if self.is_long() { 0 } else { PACKET_BIT_SPIN };
let first = self.header.start;
self.encoder.as_mut()[first] ^= random(1)[0] & mask;
self.encoder.as_mut()[first] ^= random::<1>()[0] & mask;
}
/// For an Initial packet, encode the token.
@ -424,7 +424,7 @@ impl PacketBuilder {
PACKET_BIT_LONG
| PACKET_BIT_FIXED_QUIC
| (PacketType::Retry.to_byte(version) << 4)
| (random(1)[0] & 0xf),
| (random::<1>()[0] & 0xf),
);
encoder.encode_uint(4, version.wire_version());
encoder.encode_vec(1, dcid);
@ -448,7 +448,7 @@ impl PacketBuilder {
versions: &[Version],
) -> Vec<u8> {
let mut encoder = Encoder::default();
let mut grease = random(4);
let mut grease = random::<4>();
// This will not include the "QUIC bit" sometimes. Intentionally.
encoder.encode_byte(PACKET_BIT_LONG | (grease[3] & 0x7f));
encoder.encode(&[0; 4]); // Zero version == VN.

2
third_party/rust/neqo-transport/src/path.rs поставляемый
Просмотреть файл

@ -796,7 +796,7 @@ impl Path {
// Send PATH_CHALLENGE.
if let ProbeState::ProbeNeeded { probe_count } = self.state {
qtrace!([self], "Initiating path challenge {}", probe_count);
let data = <[u8; 8]>::try_from(&random(8)[..]).unwrap();
let data = random::<8>();
builder.encode_varint(FRAME_TYPE_PATH_CHALLENGE);
builder.encode(&data);

Просмотреть файл

@ -1027,7 +1027,7 @@ mod tests {
};
use neqo_common::qlog::NeqoQlog;
use test_fixture::{addr, now};
use test_fixture::{now, DEFAULT_ADDR};
use super::{
LossRecovery, LossRecoverySpace, PacketNumberSpace, SendProfile, SentPacket, FAST_PTO_SCALE,
@ -1105,7 +1105,14 @@ mod tests {
impl Default for Fixture {
fn default() -> Self {
const CC: CongestionControlAlgorithm = CongestionControlAlgorithm::NewReno;
let mut path = Path::temporary(addr(), addr(), CC, true, NeqoQlog::default(), now());
let mut path = Path::temporary(
DEFAULT_ADDR,
DEFAULT_ADDR,
CC,
true,
NeqoQlog::default(),
now(),
);
path.make_permanent(
None,
ConnectionIdEntry::new(0, ConnectionId::from(&[1, 2, 3]), [0; 16]),

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -438,7 +438,7 @@ impl TransportParameters {
/// Set version information.
pub fn set_versions(&mut self, role: Role, versions: &VersionConfig) {
let rbuf = random(4);
let rbuf = random::<4>();
let mut other = Vec::with_capacity(versions.all().len() + 1);
let mut dec = Decoder::new(&rbuf);
let grease = (dec.decode_uint(4).unwrap() as u32) & 0xf0f0_f0f0 | 0x0a0a_0a0a;

Просмотреть файл

@ -746,8 +746,8 @@ impl Default for AckTracker {
mod tests {
use std::collections::HashSet;
use lazy_static::lazy_static;
use neqo_common::Encoder;
use test_fixture::now;
use super::{
AckTracker, Duration, Instant, PacketNumberSpace, PacketNumberSpaceSet, RecoveryToken,
@ -760,16 +760,13 @@ mod tests {
};
const RTT: Duration = Duration::from_millis(100);
lazy_static! {
static ref NOW: Instant = Instant::now();
}
fn test_ack_range(pns: &[PacketNumber], nranges: usize) {
let mut rp = RecvdPackets::new(PacketNumberSpace::Initial); // Any space will do.
let mut packets = HashSet::new();
for pn in pns {
rp.set_received(*NOW, *pn, true);
rp.set_received(now(), *pn, true);
packets.insert(*pn);
}
@ -824,7 +821,7 @@ mod tests {
// This will add one too many disjoint ranges.
for i in 0..=MAX_TRACKED_RANGES {
rp.set_received(*NOW, (i * 2) as u64, true);
rp.set_received(now(), (i * 2) as u64, true);
}
assert_eq!(rp.ranges.len(), MAX_TRACKED_RANGES);
@ -843,22 +840,22 @@ mod tests {
// Only application data packets are delayed.
let mut rp = RecvdPackets::new(PacketNumberSpace::ApplicationData);
assert!(rp.ack_time().is_none());
assert!(!rp.ack_now(*NOW, RTT));
assert!(!rp.ack_now(now(), RTT));
rp.ack_freq(0, COUNT, DELAY, false);
// Some packets won't cause an ACK to be needed.
for i in 0..COUNT {
rp.set_received(*NOW, i, true);
assert_eq!(Some(*NOW + DELAY), rp.ack_time());
assert!(!rp.ack_now(*NOW, RTT));
assert!(rp.ack_now(*NOW + DELAY, RTT));
rp.set_received(now(), i, true);
assert_eq!(Some(now() + DELAY), rp.ack_time());
assert!(!rp.ack_now(now(), RTT));
assert!(rp.ack_now(now() + DELAY, RTT));
}
// Exceeding COUNT will move the ACK time to now.
rp.set_received(*NOW, COUNT, true);
assert_eq!(Some(*NOW), rp.ack_time());
assert!(rp.ack_now(*NOW, RTT));
rp.set_received(now(), COUNT, true);
assert_eq!(Some(now()), rp.ack_time());
assert!(rp.ack_now(now(), RTT));
}
#[test]
@ -866,12 +863,12 @@ mod tests {
for space in &[PacketNumberSpace::Initial, PacketNumberSpace::Handshake] {
let mut rp = RecvdPackets::new(*space);
assert!(rp.ack_time().is_none());
assert!(!rp.ack_now(*NOW, RTT));
assert!(!rp.ack_now(now(), RTT));
// Any packet in these spaces is acknowledged straight away.
rp.set_received(*NOW, 0, true);
assert_eq!(Some(*NOW), rp.ack_time());
assert!(rp.ack_now(*NOW, RTT));
rp.set_received(now(), 0, true);
assert_eq!(Some(now()), rp.ack_time());
assert!(rp.ack_now(now(), RTT));
}
}
@ -879,12 +876,12 @@ mod tests {
fn ooo_no_ack_delay_new() {
let mut rp = RecvdPackets::new(PacketNumberSpace::ApplicationData);
assert!(rp.ack_time().is_none());
assert!(!rp.ack_now(*NOW, RTT));
assert!(!rp.ack_now(now(), RTT));
// Anything other than packet 0 is acknowledged immediately.
rp.set_received(*NOW, 1, true);
assert_eq!(Some(*NOW), rp.ack_time());
assert!(rp.ack_now(*NOW, RTT));
rp.set_received(now(), 1, true);
assert_eq!(Some(now()), rp.ack_time());
assert!(rp.ack_now(now(), RTT));
}
fn write_frame_at(rp: &mut RecvdPackets, now: Instant) {
@ -897,37 +894,37 @@ mod tests {
}
fn write_frame(rp: &mut RecvdPackets) {
write_frame_at(rp, *NOW);
write_frame_at(rp, now());
}
#[test]
fn ooo_no_ack_delay_fill() {
let mut rp = RecvdPackets::new(PacketNumberSpace::ApplicationData);
rp.set_received(*NOW, 1, true);
rp.set_received(now(), 1, true);
write_frame(&mut rp);
// Filling in behind the largest acknowledged causes immediate ACK.
rp.set_received(*NOW, 0, true);
rp.set_received(now(), 0, true);
write_frame(&mut rp);
// Receiving the next packet won't elicit an ACK.
rp.set_received(*NOW, 2, true);
assert!(!rp.ack_now(*NOW, RTT));
rp.set_received(now(), 2, true);
assert!(!rp.ack_now(now(), RTT));
}
#[test]
fn immediate_ack_after_rtt() {
let mut rp = RecvdPackets::new(PacketNumberSpace::ApplicationData);
rp.set_received(*NOW, 1, true);
rp.set_received(now(), 1, true);
write_frame(&mut rp);
// Filling in behind the largest acknowledged causes immediate ACK.
rp.set_received(*NOW, 0, true);
rp.set_received(now(), 0, true);
write_frame(&mut rp);
// A new packet ordinarily doesn't result in an ACK, but this time it does.
rp.set_received(*NOW + RTT, 2, true);
write_frame_at(&mut rp, *NOW + RTT);
rp.set_received(now() + RTT, 2, true);
write_frame_at(&mut rp, now() + RTT);
}
#[test]
@ -937,29 +934,29 @@ mod tests {
// Set tolerance to 2 and then it takes three packets.
rp.ack_freq(0, 2, Duration::from_millis(10), true);
rp.set_received(*NOW, 1, true);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(*NOW, 2, true);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(*NOW, 3, true);
assert_eq!(Some(*NOW), rp.ack_time());
rp.set_received(now(), 1, true);
assert_ne!(Some(now()), rp.ack_time());
rp.set_received(now(), 2, true);
assert_ne!(Some(now()), rp.ack_time());
rp.set_received(now(), 3, true);
assert_eq!(Some(now()), rp.ack_time());
}
#[test]
fn ooo_no_ack_delay_threshold_gap() {
let mut rp = RecvdPackets::new(PacketNumberSpace::ApplicationData);
rp.set_received(*NOW, 1, true);
rp.set_received(now(), 1, true);
write_frame(&mut rp);
// Set tolerance to 2 and then it takes three packets.
rp.ack_freq(0, 2, Duration::from_millis(10), true);
rp.set_received(*NOW, 3, true);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(*NOW, 4, true);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(*NOW, 5, true);
assert_eq!(Some(*NOW), rp.ack_time());
rp.set_received(now(), 3, true);
assert_ne!(Some(now()), rp.ack_time());
rp.set_received(now(), 4, true);
assert_ne!(Some(now()), rp.ack_time());
rp.set_received(now(), 5, true);
assert_eq!(Some(now()), rp.ack_time());
}
/// Test that an in-order packet that is not ack-eliciting doesn't
@ -970,13 +967,13 @@ mod tests {
rp.ack_freq(0, 1, Duration::from_millis(10), true);
// This should be ignored.
rp.set_received(*NOW, 0, false);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(now(), 0, false);
assert_ne!(Some(now()), rp.ack_time());
// Skip 1 (it has no effect).
rp.set_received(*NOW, 2, true);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(*NOW, 3, true);
assert_eq!(Some(*NOW), rp.ack_time());
rp.set_received(now(), 2, true);
assert_ne!(Some(now()), rp.ack_time());
rp.set_received(now(), 3, true);
assert_eq!(Some(now()), rp.ack_time());
}
/// If a packet that is not ack-eliciting is reordered, that's fine too.
@ -986,16 +983,16 @@ mod tests {
rp.ack_freq(0, 1, Duration::from_millis(10), false);
// These are out of order, but they are not ack-eliciting.
rp.set_received(*NOW, 1, false);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(*NOW, 0, false);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(now(), 1, false);
assert_ne!(Some(now()), rp.ack_time());
rp.set_received(now(), 0, false);
assert_ne!(Some(now()), rp.ack_time());
// These are in order.
rp.set_received(*NOW, 2, true);
assert_ne!(Some(*NOW), rp.ack_time());
rp.set_received(*NOW, 3, true);
assert_eq!(Some(*NOW), rp.ack_time());
rp.set_received(now(), 2, true);
assert_ne!(Some(now()), rp.ack_time());
rp.set_received(now(), 3, true);
assert_eq!(Some(now()), rp.ack_time());
}
#[test]
@ -1007,23 +1004,23 @@ mod tests {
tracker
.get_mut(PacketNumberSpace::Handshake)
.unwrap()
.set_received(*NOW, 0, false);
assert_eq!(None, tracker.ack_time(*NOW));
.set_received(now(), 0, false);
assert_eq!(None, tracker.ack_time(now()));
// This should be delayed.
tracker
.get_mut(PacketNumberSpace::ApplicationData)
.unwrap()
.set_received(*NOW, 0, true);
assert_eq!(Some(*NOW + DELAY), tracker.ack_time(*NOW));
.set_received(now(), 0, true);
assert_eq!(Some(now() + DELAY), tracker.ack_time(now()));
// This should move the time forward.
let later = *NOW + (DELAY / 2);
let later = now() + (DELAY / 2);
tracker
.get_mut(PacketNumberSpace::Initial)
.unwrap()
.set_received(later, 0, true);
assert_eq!(Some(later), tracker.ack_time(*NOW));
assert_eq!(Some(later), tracker.ack_time(now()));
}
#[test]
@ -1047,17 +1044,17 @@ mod tests {
tracker
.get_mut(PacketNumberSpace::Initial)
.unwrap()
.set_received(*NOW, 0, true);
.set_received(now(), 0, true);
// The reference time for `ack_time` has to be in the past or we filter out the timer.
assert!(tracker
.ack_time(NOW.checked_sub(Duration::from_millis(1)).unwrap())
.ack_time(now().checked_sub(Duration::from_millis(1)).unwrap())
.is_some());
let mut tokens = Vec::new();
let mut stats = FrameStats::default();
tracker.write_frame(
PacketNumberSpace::Initial,
*NOW,
now(),
RTT,
&mut builder,
&mut tokens,
@ -1069,9 +1066,9 @@ mod tests {
tracker
.get_mut(PacketNumberSpace::Initial)
.unwrap()
.set_received(*NOW, 1, true);
.set_received(now(), 1, true);
assert!(tracker
.ack_time(NOW.checked_sub(Duration::from_millis(1)).unwrap())
.ack_time(now().checked_sub(Duration::from_millis(1)).unwrap())
.is_some());
// Now drop that space.
@ -1079,11 +1076,11 @@ mod tests {
assert!(tracker.get_mut(PacketNumberSpace::Initial).is_none());
assert!(tracker
.ack_time(NOW.checked_sub(Duration::from_millis(1)).unwrap())
.ack_time(now().checked_sub(Duration::from_millis(1)).unwrap())
.is_none());
tracker.write_frame(
PacketNumberSpace::Initial,
*NOW,
now(),
RTT,
&mut builder,
&mut tokens,
@ -1103,9 +1100,9 @@ mod tests {
tracker
.get_mut(PacketNumberSpace::Initial)
.unwrap()
.set_received(*NOW, 0, true);
.set_received(now(), 0, true);
assert!(tracker
.ack_time(NOW.checked_sub(Duration::from_millis(1)).unwrap())
.ack_time(now().checked_sub(Duration::from_millis(1)).unwrap())
.is_some());
let mut builder = PacketBuilder::short(Encoder::new(), false, []);
@ -1114,7 +1111,7 @@ mod tests {
let mut stats = FrameStats::default();
tracker.write_frame(
PacketNumberSpace::Initial,
*NOW,
now(),
RTT,
&mut builder,
&mut Vec::new(),
@ -1130,13 +1127,13 @@ mod tests {
tracker
.get_mut(PacketNumberSpace::Initial)
.unwrap()
.set_received(*NOW, 0, true);
.set_received(now(), 0, true);
tracker
.get_mut(PacketNumberSpace::Initial)
.unwrap()
.set_received(*NOW, 2, true);
.set_received(now(), 2, true);
assert!(tracker
.ack_time(NOW.checked_sub(Duration::from_millis(1)).unwrap())
.ack_time(now().checked_sub(Duration::from_millis(1)).unwrap())
.is_some());
let mut builder = PacketBuilder::short(Encoder::new(), false, []);
@ -1145,7 +1142,7 @@ mod tests {
let mut stats = FrameStats::default();
tracker.write_frame(
PacketNumberSpace::Initial,
*NOW,
now(),
RTT,
&mut builder,
&mut Vec::new(),
@ -1168,19 +1165,19 @@ mod tests {
let mut tracker = AckTracker::default();
// While we have multiple PN spaces, we ignore ACK timers from the past.
// Send out of order to cause the delayed ack timer to be set to `*NOW`.
// Send out of order to cause the delayed ack timer to be set to `now()`.
tracker
.get_mut(PacketNumberSpace::ApplicationData)
.unwrap()
.set_received(*NOW, 3, true);
assert!(tracker.ack_time(*NOW + Duration::from_millis(1)).is_none());
.set_received(now(), 3, true);
assert!(tracker.ack_time(now() + Duration::from_millis(1)).is_none());
// When we are reduced to one space, that filter is off.
tracker.drop_space(PacketNumberSpace::Initial);
tracker.drop_space(PacketNumberSpace::Handshake);
assert_eq!(
tracker.ack_time(*NOW + Duration::from_millis(1)),
Some(*NOW)
tracker.ack_time(now() + Duration::from_millis(1)),
Some(now())
);
}

Просмотреть файл

@ -7,15 +7,17 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
mod sim;
use std::{ops::Range, time::Duration};
use neqo_transport::{ConnectionError, ConnectionParameters, Error, State};
use sim::{
connection::{ConnectionNode, ReachState, ReceiveData, SendData},
network::{Delay, Drop, TailDrop},
Simulator,
use test_fixture::{
boxed,
sim::{
connection::{ConnectionNode, ReachState, ReceiveData, SendData},
network::{Delay, Drop, TailDrop},
Simulator,
},
simulate,
};
/// The amount of transfer. Much more than this takes a surprising amount of time.
@ -32,26 +34,28 @@ const fn weeks(m: u32) -> Duration {
simulate!(
connect_direct,
[
ConnectionNode::default_client(boxed![ReachState::new(State::Confirmed)]),
ConnectionNode::default_server(boxed![ReachState::new(State::Confirmed)]),
ConnectionNode::new_client(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
ConnectionNode::new_server(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
]
);
simulate!(
idle_timeout,
[
ConnectionNode::default_client(boxed![
ReachState::new(State::Confirmed),
ReachState::new(State::Closed(ConnectionError::Transport(
Error::IdleTimeout
)))
]),
ConnectionNode::default_server(boxed![
ReachState::new(State::Confirmed),
ReachState::new(State::Closed(ConnectionError::Transport(
Error::IdleTimeout
)))
]),
ConnectionNode::default_client(boxed![ReachState::new(State::Closed(
ConnectionError::Transport(Error::IdleTimeout)
))]),
ConnectionNode::default_server(boxed![ReachState::new(State::Closed(
ConnectionError::Transport(Error::IdleTimeout)
))]),
]
);
@ -60,23 +64,19 @@ simulate!(
[
ConnectionNode::new_client(
ConnectionParameters::default().idle_timeout(weeks(1000)),
boxed![
ReachState::new(State::Confirmed),
ReachState::new(State::Closed(ConnectionError::Transport(
Error::IdleTimeout
)))
]
boxed![ReachState::new(State::Confirmed),],
boxed![ReachState::new(State::Closed(ConnectionError::Transport(
Error::IdleTimeout
)))]
),
Delay::new(weeks(6)..weeks(6)),
Drop::percentage(10),
ConnectionNode::new_server(
ConnectionParameters::default().idle_timeout(weeks(1000)),
boxed![
ReachState::new(State::Confirmed),
ReachState::new(State::Closed(ConnectionError::Transport(
Error::IdleTimeout
)))
]
boxed![ReachState::new(State::Confirmed),],
boxed![ReachState::new(State::Closed(ConnectionError::Transport(
Error::IdleTimeout
)))]
),
Delay::new(weeks(8)..weeks(8)),
Drop::percentage(10),
@ -94,9 +94,17 @@ simulate!(
simulate!(
connect_fixed_rtt,
[
ConnectionNode::default_client(boxed![ReachState::new(State::Confirmed)]),
ConnectionNode::new_client(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
Delay::new(DELAY..DELAY),
ConnectionNode::default_server(boxed![ReachState::new(State::Confirmed)]),
ConnectionNode::new_server(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
Delay::new(DELAY..DELAY),
],
);
@ -104,22 +112,38 @@ simulate!(
simulate!(
connect_taildrop_jitter,
[
ConnectionNode::default_client(boxed![ReachState::new(State::Confirmed)]),
TailDrop::dsl_uplink(),
Delay::new(ZERO..JITTER),
ConnectionNode::default_server(boxed![ReachState::new(State::Confirmed)]),
ConnectionNode::new_client(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
TailDrop::dsl_downlink(),
Delay::new(ZERO..JITTER),
ConnectionNode::new_server(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
TailDrop::dsl_uplink(),
Delay::new(ZERO..JITTER),
],
);
simulate!(
connect_taildrop,
[
ConnectionNode::default_client(boxed![ReachState::new(State::Confirmed)]),
TailDrop::dsl_uplink(),
ConnectionNode::default_server(boxed![ReachState::new(State::Confirmed)]),
ConnectionNode::new_client(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
TailDrop::dsl_downlink(),
ConnectionNode::new_server(
ConnectionParameters::default(),
[],
boxed![ReachState::new(State::Confirmed)]
),
TailDrop::dsl_uplink(),
],
);
@ -139,9 +163,9 @@ simulate!(
transfer_taildrop,
[
ConnectionNode::default_client(boxed![SendData::new(TRANSFER_AMOUNT)]),
TailDrop::dsl_uplink(),
ConnectionNode::default_server(boxed![ReceiveData::new(TRANSFER_AMOUNT)]),
TailDrop::dsl_downlink(),
ConnectionNode::default_server(boxed![ReceiveData::new(TRANSFER_AMOUNT)]),
TailDrop::dsl_uplink(),
],
);
@ -149,10 +173,10 @@ simulate!(
transfer_taildrop_jitter,
[
ConnectionNode::default_client(boxed![SendData::new(TRANSFER_AMOUNT)]),
TailDrop::dsl_uplink(),
TailDrop::dsl_downlink(),
Delay::new(ZERO..JITTER),
ConnectionNode::default_server(boxed![ReceiveData::new(TRANSFER_AMOUNT)]),
TailDrop::dsl_downlink(),
TailDrop::dsl_uplink(),
Delay::new(ZERO..JITTER),
],
);

Просмотреть файл

@ -1,315 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(clippy::module_name_repetitions)]
use std::{
cmp::min,
fmt::{self, Debug},
time::Instant,
};
use neqo_common::{event::Provider, qdebug, qtrace, Datagram};
use neqo_crypto::AuthenticationStatus;
use neqo_transport::{
Connection, ConnectionEvent, ConnectionParameters, Output, State, StreamId, StreamType,
};
use super::{Node, Rng};
/// The status of the processing of an event.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GoalStatus {
/// The event didn't result in doing anything; the goal is waiting for something.
Waiting,
/// An action was taken as a result of the event.
Active,
/// The goal was accomplished.
Done,
}
/// A goal for the connection.
/// Goals can be accomplished in any order.
pub trait ConnectionGoal {
fn init(&mut self, _c: &mut Connection, _now: Instant) {}
/// Perform some processing.
fn process(&mut self, _c: &mut Connection, _now: Instant) -> GoalStatus {
GoalStatus::Waiting
}
/// Handle an event from the provided connection, returning `true` when the
/// goal is achieved.
fn handle_event(&mut self, c: &mut Connection, e: &ConnectionEvent, now: Instant)
-> GoalStatus;
}
pub struct ConnectionNode {
c: Connection,
goals: Vec<Box<dyn ConnectionGoal>>,
}
impl ConnectionNode {
pub fn new_client(
params: ConnectionParameters,
goals: impl IntoIterator<Item = Box<dyn ConnectionGoal>>,
) -> Self {
Self {
c: test_fixture::new_client(params),
goals: goals.into_iter().collect(),
}
}
pub fn new_server(
params: ConnectionParameters,
goals: impl IntoIterator<Item = Box<dyn ConnectionGoal>>,
) -> Self {
Self {
c: test_fixture::new_server(test_fixture::DEFAULT_ALPN, params),
goals: goals.into_iter().collect(),
}
}
pub fn default_client(goals: impl IntoIterator<Item = Box<dyn ConnectionGoal>>) -> Self {
Self::new_client(ConnectionParameters::default(), goals)
}
pub fn default_server(goals: impl IntoIterator<Item = Box<dyn ConnectionGoal>>) -> Self {
Self::new_server(ConnectionParameters::default(), goals)
}
#[allow(dead_code)]
pub fn clear_goals(&mut self) {
self.goals.clear();
}
#[allow(dead_code)]
pub fn add_goal(&mut self, goal: Box<dyn ConnectionGoal>) {
self.goals.push(goal);
}
/// Process all goals using the given closure and return whether any were active.
fn process_goals<F>(&mut self, mut f: F) -> bool
where
F: FnMut(&mut Box<dyn ConnectionGoal>, &mut Connection) -> GoalStatus,
{
// Waiting on drain_filter...
// self.goals.drain_filter(|g| f(g, &mut self.c, &e)).count();
let mut active = false;
let mut i = 0;
while i < self.goals.len() {
let status = f(&mut self.goals[i], &mut self.c);
if status == GoalStatus::Done {
self.goals.remove(i);
active = true;
} else {
active |= status == GoalStatus::Active;
i += 1;
}
}
active
}
}
impl Node for ConnectionNode {
fn init(&mut self, _rng: Rng, now: Instant) {
for g in &mut self.goals {
g.init(&mut self.c, now);
}
}
fn process(&mut self, mut d: Option<Datagram>, now: Instant) -> Output {
_ = self.process_goals(|goal, c| goal.process(c, now));
loop {
let res = self.c.process(d.take().as_ref(), now);
let mut active = false;
while let Some(e) = self.c.next_event() {
qtrace!([self.c], "received event {:?}", e);
// Perform authentication automatically.
if matches!(e, ConnectionEvent::AuthenticationNeeded) {
self.c.authenticated(AuthenticationStatus::Ok, now);
}
active |= self.process_goals(|goal, c| goal.handle_event(c, &e, now));
}
// Exit at this point if the connection produced a datagram.
// We also exit if none of the goals were active, as there is
// no point trying again if they did nothing.
if matches!(res, Output::Datagram(_)) || !active {
return res;
}
qdebug!([self.c], "no datagram and goal activity, looping");
}
}
fn done(&self) -> bool {
self.goals.is_empty()
}
fn print_summary(&self, test_name: &str) {
println!("{}: {:?}", test_name, self.c.stats());
}
}
impl Debug for ConnectionNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.c, f)
}
}
#[derive(Debug, Clone)]
pub struct ReachState {
target: State,
}
impl ReachState {
pub fn new(target: State) -> Self {
Self { target }
}
}
impl ConnectionGoal for ReachState {
fn handle_event(
&mut self,
_c: &mut Connection,
e: &ConnectionEvent,
_now: Instant,
) -> GoalStatus {
if matches!(e, ConnectionEvent::StateChange(state) if *state == self.target) {
GoalStatus::Done
} else {
GoalStatus::Waiting
}
}
}
#[derive(Debug)]
pub struct SendData {
remaining: usize,
stream_id: Option<StreamId>,
}
impl SendData {
pub fn new(amount: usize) -> Self {
Self {
remaining: amount,
stream_id: None,
}
}
fn make_stream(&mut self, c: &mut Connection) {
if self.stream_id.is_none() {
if let Ok(stream_id) = c.stream_create(StreamType::UniDi) {
qdebug!([c], "made stream {} for sending", stream_id);
self.stream_id = Some(stream_id);
}
}
}
fn send(&mut self, c: &mut Connection, stream_id: StreamId) -> GoalStatus {
const DATA: &[u8] = &[0; 4096];
let mut status = GoalStatus::Waiting;
loop {
let end = min(self.remaining, DATA.len());
let sent = c.stream_send(stream_id, &DATA[..end]).unwrap();
if sent == 0 {
return status;
}
self.remaining -= sent;
qtrace!("sent {} remaining {}", sent, self.remaining);
if self.remaining == 0 {
c.stream_close_send(stream_id).unwrap();
return GoalStatus::Done;
}
status = GoalStatus::Active;
}
}
}
impl ConnectionGoal for SendData {
fn init(&mut self, c: &mut Connection, _now: Instant) {
self.make_stream(c);
}
fn process(&mut self, c: &mut Connection, _now: Instant) -> GoalStatus {
self.stream_id
.map_or(GoalStatus::Waiting, |stream_id| self.send(c, stream_id))
}
fn handle_event(
&mut self,
c: &mut Connection,
e: &ConnectionEvent,
_now: Instant,
) -> GoalStatus {
match e {
ConnectionEvent::SendStreamCreatable {
stream_type: StreamType::UniDi,
}
// TODO(mt): remove the second condition when #842 is fixed.
| ConnectionEvent::StateChange(_) => {
self.make_stream(c);
GoalStatus::Active
}
ConnectionEvent::SendStreamWritable { stream_id }
if Some(*stream_id) == self.stream_id =>
{
self.send(c, *stream_id)
}
// If we sent data in 0-RTT, then we didn't track how much we should
// have sent. This is trivial to fix if 0-RTT testing is ever needed.
ConnectionEvent::ZeroRttRejected => panic!("not supported"),
_ => GoalStatus::Waiting,
}
}
}
/// Receive a prescribed amount of data from any stream.
#[derive(Debug)]
pub struct ReceiveData {
remaining: usize,
}
impl ReceiveData {
pub fn new(amount: usize) -> Self {
Self { remaining: amount }
}
fn recv(&mut self, c: &mut Connection, stream_id: StreamId) -> GoalStatus {
let mut buf = vec![0; 4096];
let mut status = GoalStatus::Waiting;
loop {
let end = min(self.remaining, buf.len());
let (recvd, _) = c.stream_recv(stream_id, &mut buf[..end]).unwrap();
qtrace!("received {} remaining {}", recvd, self.remaining);
if recvd == 0 {
return status;
}
self.remaining -= recvd;
if self.remaining == 0 {
return GoalStatus::Done;
}
status = GoalStatus::Active;
}
}
}
impl ConnectionGoal for ReceiveData {
fn handle_event(
&mut self,
c: &mut Connection,
e: &ConnectionEvent,
_now: Instant,
) -> GoalStatus {
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
self.recv(c, *stream_id)
} else {
GoalStatus::Waiting
}
}
}

Просмотреть файл

@ -1,102 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(clippy::module_name_repetitions)]
use std::{
collections::BTreeMap,
convert::TryFrom,
fmt::{self, Debug},
ops::Range,
time::{Duration, Instant},
};
use neqo_common::Datagram;
use neqo_transport::Output;
use super::{Node, Rng};
/// An iterator that shares a `Random` instance and produces uniformly
/// random `Duration`s within a specified range.
pub struct RandomDelay {
start: Duration,
max: u64,
rng: Option<Rng>,
}
impl RandomDelay {
/// Make a new random `Duration` generator. This panics if the range provided
/// is inverted (i.e., `bounds.start > bounds.end`), or spans 2^64
/// or more nanoseconds.
/// A zero-length range means that random values won't be taken from the Rng
pub fn new(bounds: Range<Duration>) -> Self {
let max = u64::try_from((bounds.end - bounds.start).as_nanos()).unwrap();
Self {
start: bounds.start,
max,
rng: None,
}
}
pub fn set_rng(&mut self, rng: Rng) {
self.rng = Some(rng);
}
pub fn next(&mut self) -> Duration {
let mut rng = self.rng.as_ref().unwrap().borrow_mut();
let r = rng.random_from(0..self.max);
self.start + Duration::from_nanos(r)
}
}
pub struct Delay {
random: RandomDelay,
queue: BTreeMap<Instant, Datagram>,
}
impl Delay {
pub fn new(bounds: Range<Duration>) -> Self {
Self {
random: RandomDelay::new(bounds),
queue: BTreeMap::default(),
}
}
fn insert(&mut self, d: Datagram, now: Instant) {
let mut t = now + self.random.next();
while self.queue.contains_key(&t) {
// This is a little inefficient, but it avoids drops on collisions,
// which are super-common for a fixed delay.
t += Duration::from_nanos(1);
}
self.queue.insert(t, d);
}
}
impl Node for Delay {
fn init(&mut self, rng: Rng, _now: Instant) {
self.random.set_rng(rng);
}
fn process(&mut self, d: Option<Datagram>, now: Instant) -> Output {
if let Some(dgram) = d {
self.insert(dgram, now);
}
if let Some((&k, _)) = self.queue.range(..=now).next() {
Output::Datagram(self.queue.remove(&k).unwrap())
} else if let Some(&t) = self.queue.keys().next() {
Output::Callback(t - now)
} else {
Output::None
}
}
}
impl Debug for Delay {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("delay")
}
}

Просмотреть файл

@ -1,75 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(clippy::module_name_repetitions)]
use std::{
fmt::{self, Debug},
time::Instant,
};
use neqo_common::{qtrace, Datagram};
use neqo_transport::Output;
use super::{Node, Rng};
/// A random dropper.
pub struct Drop {
threshold: u64,
max: u64,
rng: Option<Rng>,
}
impl Drop {
/// Make a new random drop generator. Each `drop` is called, this generates a
/// random value between 0 and `max` (exclusive). If this value is less than
/// `threshold` a value of `true` is returned.
pub fn new(threshold: u64, max: u64) -> Self {
Self {
threshold,
max,
rng: None,
}
}
/// Generate random drops with the given percentage.
pub fn percentage(pct: u8) -> Self {
// Multiply by 10 so that the random number generator works more efficiently.
Self::new(u64::from(pct) * 10, 1000)
}
pub fn drop(&mut self) -> bool {
let mut rng = self.rng.as_ref().unwrap().borrow_mut();
let r = rng.random_from(0..self.max);
r < self.threshold
}
}
impl Node for Drop {
fn init(&mut self, rng: Rng, _now: Instant) {
self.rng = Some(rng);
}
// Pass any datagram provided directly out, but drop some of them.
fn process(&mut self, d: Option<Datagram>, _now: Instant) -> Output {
if let Some(dgram) = d {
if self.drop() {
qtrace!("drop {}", dgram.len());
Output::None
} else {
Output::Datagram(dgram)
}
} else {
Output::None
}
}
}
impl Debug for Drop {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("drop")
}
}

Просмотреть файл

@ -1,232 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Tests with simulated network
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(clippy::pedantic)]
pub mod connection;
mod delay;
mod drop;
pub mod rng;
mod taildrop;
use std::{
cell::RefCell,
cmp::min,
convert::TryFrom,
fmt::Debug,
rc::Rc,
time::{Duration, Instant},
};
use neqo_common::{qdebug, qinfo, qtrace, Datagram, Encoder};
use neqo_transport::Output;
use rng::Random;
use test_fixture::{self, now};
use NodeState::{Active, Idle, Waiting};
pub mod network {
pub use super::{delay::Delay, drop::Drop, taildrop::TailDrop};
}
type Rng = Rc<RefCell<Random>>;
/// A macro that turns a list of values into boxed versions of the same.
#[macro_export]
macro_rules! boxed {
[$($v:expr),+ $(,)?] => {
vec![ $( Box::new($v) as _ ),+ ]
};
}
/// Create a simulation test case. This takes either two or three arguments.
/// The two argument form takes a bare name (`ident`), a comma, and an array of
/// items that implement `Node`.
/// The three argument form adds a setup block that can be used to construct a
/// complex value that is then shared between all nodes. The values in the
/// three-argument form have to be closures (or functions) that accept a reference
/// to the value returned by the setup.
#[macro_export]
macro_rules! simulate {
($n:ident, [ $($v:expr),+ $(,)? ] $(,)?) => {
simulate!($n, (), [ $(|_| $v),+ ]);
};
($n:ident, $setup:expr, [ $( $v:expr ),+ $(,)? ] $(,)?) => {
#[test]
fn $n() {
let fixture = $setup;
let mut nodes: Vec<Box<dyn $crate::sim::Node>> = Vec::new();
$(
let f: Box<dyn FnOnce(&_) -> _> = Box::new($v);
nodes.push(Box::new(f(&fixture)));
)*
let mut sim = Simulator::new(stringify!($n), nodes);
if let Ok(seed) = std::env::var("SIMULATION_SEED") {
sim.seed_str(seed);
}
sim.run();
}
};
}
pub trait Node: Debug {
fn init(&mut self, _rng: Rng, _now: Instant) {}
/// Perform processing. This optionally takes a datagram and produces either
/// another data, a time that the simulator needs to wait, or nothing.
fn process(&mut self, d: Option<Datagram>, now: Instant) -> Output;
/// An node can report when it considers itself "done".
fn done(&self) -> bool {
true
}
fn print_summary(&self, _test_name: &str) {}
}
/// The state of a single node. Nodes will be activated if they are `Active`
/// or if the previous node in the loop generated a datagram. Nodes that return
/// `true` from `Node::done` will be activated as normal.
#[derive(Debug, PartialEq)]
enum NodeState {
/// The node just produced a datagram. It should be activated again as soon as possible.
Active,
/// The node is waiting.
Waiting(Instant),
/// The node became idle.
Idle,
}
#[derive(Debug)]
struct NodeHolder {
node: Box<dyn Node>,
state: NodeState,
}
impl NodeHolder {
fn ready(&self, now: Instant) -> bool {
match self.state {
Active => true,
Waiting(t) => t >= now,
Idle => false,
}
}
}
pub struct Simulator {
name: String,
nodes: Vec<NodeHolder>,
rng: Rng,
}
impl Simulator {
pub fn new(name: impl AsRef<str>, nodes: impl IntoIterator<Item = Box<dyn Node>>) -> Self {
let name = String::from(name.as_ref());
// The first node is marked as Active, the rest are idle.
let mut it = nodes.into_iter();
let nodes = it
.next()
.map(|node| NodeHolder {
node,
state: Active,
})
.into_iter()
.chain(it.map(|node| NodeHolder { node, state: Idle }))
.collect::<Vec<_>>();
Self {
name,
nodes,
rng: Rc::default(),
}
}
pub fn seed(&mut self, seed: [u8; 32]) {
self.rng = Rc::new(RefCell::new(Random::new(seed)));
}
/// Seed from a hex string.
/// Though this is convenient, it panics if this isn't a 64 character hex string.
pub fn seed_str(&mut self, seed: impl AsRef<str>) {
let seed = Encoder::from_hex(seed);
self.seed(<[u8; 32]>::try_from(seed.as_ref()).unwrap());
}
fn next_time(&self, now: Instant) -> Instant {
let mut next = None;
for n in &self.nodes {
match n.state {
Idle => continue,
Active => return now,
Waiting(a) => next = Some(next.map_or(a, |b| min(a, b))),
}
}
next.expect("a node cannot be idle and not done")
}
/// Runs the simulation.
pub fn run(mut self) -> Duration {
let start = now();
let mut now = start;
let mut dgram = None;
for n in &mut self.nodes {
n.node.init(self.rng.clone(), now);
}
println!("{}: seed {}", self.name, self.rng.borrow().seed_str());
let real_start = Instant::now();
loop {
for n in &mut self.nodes {
if dgram.is_none() && !n.ready(now) {
qdebug!([self.name], "skipping {:?}", n.node);
continue;
}
qdebug!([self.name], "processing {:?}", n.node);
let res = n.node.process(dgram.take(), now);
n.state = match res {
Output::Datagram(d) => {
qtrace!([self.name], " => datagram {}", d.len());
dgram = Some(d);
Active
}
Output::Callback(delay) => {
qtrace!([self.name], " => callback {:?}", delay);
assert_ne!(delay, Duration::new(0, 0));
Waiting(now + delay)
}
Output::None => {
qtrace!([self.name], " => nothing");
assert!(n.node.done(), "nodes have to be done when they go idle");
Idle
}
};
}
if self.nodes.iter().all(|n| n.node.done()) {
let real_elapsed = real_start.elapsed();
println!("{}: real elapsed time: {:?}", self.name, real_elapsed);
let elapsed = now - start;
println!("{}: simulated elapsed time: {:?}", self.name, elapsed);
for n in &self.nodes {
n.node.print_summary(&self.name);
}
return elapsed;
}
if dgram.is_none() {
let next = self.next_time(now);
if next > now {
qinfo!(
[self.name],
"advancing time by {:?} to {:?}",
next - now,
next - start
);
now = next;
}
}
}
}
}

Просмотреть файл

@ -1,111 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::rng::RandomDuration;
use super::{Node, Rng};
use neqo_common::Datagram;
use neqo_transport::Output;
use std::collections::BTreeMap;
use std::fmt::{self, Debug};
use std::iter;
use std::ops::Range;
use std::time::{Duration, Instant};
///
pub struct RandomDrop {
threshold: u64,
max: u64,
rng: Rng,
}
impl RandomDuration {
/// Make a new random `Duration` generator. This asserts if the range provided
/// is inverted (i.e., `bounds.start > bounds.end`), or spans 2^64
/// or more nanoseconds.
/// A zero-length range means that random values won't be taken from the Rng
pub fn new(bounds: Range<Duration>, rng: Rng) -> Self {
let max = u64::try_from((bounds.end - bounds.start).as_nanos()).unwrap();
Self {
start: bounds.start,
max,
rng,
}
}
fn next(&mut self) -> Duration {
let r = if self.max == 0 {
Duration::new(0, 0)
} else {
self.rng.borrow_mut().random_from(0..self.max)
}
self.start + Duration::from_nanos(r)
}
}
enum DelayState {
New(Range<Duration>),
Ready(RandomDuration),
}
pub struct Delay {
state: DelayState,
queue: BTreeMap<Instant, Datagram>,
}
impl Delay
{
pub fn new(bounds: Range<Duration>) -> Self
{
Self {
State: DelayState::New(bounds),
queue: BTreeMap::default(),
}
}
fn insert(&mut self, d: Datagram, now: Instant) {
let mut t = if let State::Ready(r) = self.state {
now + self.source.next()
} else {
unreachable!();
}
while self.queue.contains_key(&t) {
// This is a little inefficient, but it avoids drops on collisions,
// which are super-common for a fixed delay.
t += Duration::from_nanos(1);
}
self.queue.insert(t, d);
}
}
impl Node for Delay
{
fn init(&mut self, rng: Rng, now: Instant) {
if let DelayState::New(bounds) = self.state {
self.state = RandomDuration::new(bounds);
} else {
unreachable!();
}
}
fn process(&mut self, d: Option<Datagram>, now: Instant) -> Output {
if let Some(dgram) = d {
self.insert(dgram, now);
}
if let Some((&k, _)) = self.queue.range(..now).nth(0) {
Output::Datagram(self.queue.remove(&k).unwrap())
} else if let Some(&t) = self.queue.keys().nth(0) {
Output::Callback(t - now)
} else {
Output::None
}
}
}
impl<T> Debug for Delay<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("delay")
}
}

Просмотреть файл

@ -1,81 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::{convert::TryFrom, ops::Range};
use neqo_common::Decoder;
/// An implementation of a xoshiro256** pseudorandom generator.
pub struct Random {
state: [u64; 4],
}
impl Random {
pub fn new(seed: [u8; 32]) -> Self {
assert!(seed.iter().any(|&x| x != 0));
let mut dec = Decoder::from(&seed);
Self {
state: [
dec.decode_uint(8).unwrap(),
dec.decode_uint(8).unwrap(),
dec.decode_uint(8).unwrap(),
dec.decode_uint(8).unwrap(),
],
}
}
pub fn random(&mut self) -> u64 {
let result = (self.state[1].overflowing_mul(5).0)
.rotate_right(7)
.overflowing_mul(9)
.0;
let t = self.state[1] << 17;
self.state[2] ^= self.state[0];
self.state[3] ^= self.state[1];
self.state[1] ^= self.state[2];
self.state[0] ^= self.state[3];
self.state[2] ^= t;
self.state[3] = self.state[3].rotate_right(45);
result
}
/// Generate a random value from the range.
/// If the range is empty or inverted (`range.start > range.end`), then
/// this returns the value of `range.start` without generating any random values.
pub fn random_from(&mut self, range: Range<u64>) -> u64 {
let max = range.end.saturating_sub(range.start);
if max == 0 {
return range.start;
}
let shift = (max - 1).leading_zeros();
assert_ne!(max, 0);
loop {
let r = self.random() >> shift;
if r < max {
return range.start + r;
}
}
}
/// Get the seed necessary to continue from this point.
pub fn seed_str(&self) -> String {
format!(
"{:8x}{:8x}{:8x}{:8x}",
self.state[0], self.state[1], self.state[2], self.state[3],
)
}
}
impl Default for Random {
fn default() -> Self {
let buf = neqo_crypto::random(32);
Random::new(<[u8; 32]>::try_from(&buf[..]).unwrap())
}
}

Просмотреть файл

@ -1,188 +0,0 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(clippy::module_name_repetitions)]
use std::{
cmp::max,
collections::VecDeque,
convert::TryFrom,
fmt::{self, Debug},
time::{Duration, Instant},
};
use neqo_common::{qtrace, Datagram};
use neqo_transport::Output;
use super::Node;
/// One second in nanoseconds.
const ONE_SECOND_NS: u128 = 1_000_000_000;
/// This models a link with a tail drop router at the front of it.
pub struct TailDrop {
/// An overhead associated with each entry. This accounts for
/// layer 2, IP, and UDP overheads.
overhead: usize,
/// The rate at which bytes egress the link, in bytes per second.
rate: usize,
/// The depth of the queue, in bytes.
capacity: usize,
/// A counter for how many bytes are enqueued.
used: usize,
/// A queue of unsent bytes.
queue: VecDeque<Datagram>,
/// The time that the next datagram can enter the link.
next_deque: Option<Instant>,
/// Any sub-ns delay from the last enqueue.
sub_ns_delay: u32,
/// The time it takes a byte to exit the other end of the link.
delay: Duration,
/// The packets that are on the link and when they can be delivered.
on_link: VecDeque<(Instant, Datagram)>,
/// The number of packets received.
received: usize,
/// The number of packets dropped.
dropped: usize,
/// The number of packets delivered.
delivered: usize,
/// The maximum amount of queue capacity ever used.
/// As packets leave the queue as soon as they start being used, this doesn't
/// count them.
maxq: usize,
}
impl TailDrop {
/// Make a new taildrop node with the given rate, queue capacity, and link delay.
pub fn new(rate: usize, capacity: usize, delay: Duration) -> Self {
Self {
overhead: 64,
rate,
capacity,
used: 0,
queue: VecDeque::new(),
next_deque: None,
sub_ns_delay: 0,
delay,
on_link: VecDeque::new(),
received: 0,
dropped: 0,
delivered: 0,
maxq: 0,
}
}
/// A tail drop queue on a 10Mbps link (approximated to 1 million bytes per second)
/// with a fat 32k buffer (about 30ms), and the default forward delay of 50ms.
pub fn dsl_uplink() -> Self {
TailDrop::new(1_000_000, 32_768, Duration::from_millis(50))
}
/// Cut downlink to one fifth of the uplink (2Mbps), and reduce the buffer to 1/4.
pub fn dsl_downlink() -> Self {
TailDrop::new(200_000, 8_192, Duration::from_millis(50))
}
/// How "big" is this datagram, accounting for overheads.
/// This approximates by using the same overhead for storing in the queue
/// and for sending on the wire.
fn size(&self, d: &Datagram) -> usize {
d.len() + self.overhead
}
/// Start sending a datagram.
fn send(&mut self, d: Datagram, now: Instant) {
// How many bytes are we "transmitting"?
let sz = u128::try_from(self.size(&d)).unwrap();
// Calculate how long it takes to put the packet on the link.
// Perform the calculation based on 2^32 seconds and save any remainder.
// This ensures that high rates and small packets don't result in rounding
// down times too badly.
// Duration consists of a u64 and a u32, so we have 32 high bits to spare.
let t = sz * (ONE_SECOND_NS << 32) / u128::try_from(self.rate).unwrap()
+ u128::from(self.sub_ns_delay);
let send_ns = u64::try_from(t >> 32).unwrap();
assert_ne!(send_ns, 0, "sending a packet takes <1ns");
self.sub_ns_delay = u32::try_from(t & u128::from(u32::MAX)).unwrap();
let deque_time = now + Duration::from_nanos(send_ns);
self.next_deque = Some(deque_time);
// Now work out when the packet is fully received at the other end of
// the link. Setup to deliver the packet then.
let delivery_time = deque_time + self.delay;
self.on_link.push_back((delivery_time, d));
}
/// Enqueue for sending. Maybe. If this overflows the queue, drop it instead.
fn maybe_enqueue(&mut self, d: Datagram, now: Instant) {
self.received += 1;
if self.next_deque.is_none() {
// Nothing in the queue and nothing still sending.
debug_assert!(self.queue.is_empty());
self.send(d, now);
} else if self.used + self.size(&d) <= self.capacity {
self.used += self.size(&d);
self.maxq = max(self.maxq, self.used);
self.queue.push_back(d);
} else {
qtrace!("taildrop dropping {} bytes", d.len());
self.dropped += 1;
}
}
/// If the last packet that was sending has been sent, start sending
/// the next one.
fn maybe_send(&mut self, now: Instant) {
if self.next_deque.as_ref().map_or(false, |t| *t <= now) {
if let Some(d) = self.queue.pop_front() {
self.used -= self.size(&d);
self.send(d, now);
} else {
self.next_deque = None;
self.sub_ns_delay = 0;
}
}
}
}
impl Node for TailDrop {
fn process(&mut self, d: Option<Datagram>, now: Instant) -> Output {
if let Some(dgram) = d {
self.maybe_enqueue(dgram, now);
}
self.maybe_send(now);
if let Some((t, _)) = self.on_link.front() {
if *t <= now {
let (_, d) = self.on_link.pop_front().unwrap();
self.delivered += 1;
Output::Datagram(d)
} else {
Output::Callback(*t - now)
}
} else {
Output::None
}
}
fn print_summary(&self, test_name: &str) {
println!(
"{}: taildrop: rx {} drop {} tx {} maxq {}",
test_name, self.received, self.dropped, self.delivered, self.maxq,
);
}
}
impl Debug for TailDrop {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("taildrop")
}
}

2
third_party/rust/qlog/.cargo-checksum.json поставляемый
Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"15c2606defff66515f2ded1ace2aeb729229a3558d9a026c058e51a7518e6859","README.md":"597691eb766c2cbd7a6591bda56d3e70e6836b62b6327fb73497523eabd5b53d","src/events/connectivity.rs":"116993412e200e375c97762980ffb638d2244197fd752b9569b5b20baf574308","src/events/h3.rs":"45dfa1dea722f3c8adb989f04ff24e8c39550a65a35325885b3a915cafd3a550","src/events/mod.rs":"75f57b4717fa9777e19d61b99b6a79164f0e8bca9b4681c3ab11b204320c8c55","src/events/qpack.rs":"5c7267c45e3fb947cdfa946f9f9692d3e3e36a166f70124ba293dc27534267d0","src/events/quic.rs":"88b884f5788c671ffee79a3448f367c18f95ee30531262fcc14310d80e662f4a","src/events/security.rs":"e9852d7de16851b62c3e0a886a2c1a31d237e62574ef88428ef62dd179b0b008","src/lib.rs":"bbc190a6d0f484fd723f9df6c1b2a4596f826e0282ad40ee17a0822ea28a5626","src/reader.rs":"4e0069c24aca9cb99d75075c9b784fa02855ea449d2f1528bea944a4e02a9af5","src/streamer.rs":"4774c2abde1a5b0f4448aac06c62c7927208c12f338c46981f80c98703b54074"},"package":null}
{"files":{"Cargo.toml":"66c6d85a84c84711f3abddaafb163bc6025a8505701fea8b61bfa961851be757","README.md":"597691eb766c2cbd7a6591bda56d3e70e6836b62b6327fb73497523eabd5b53d","src/events/connectivity.rs":"116993412e200e375c97762980ffb638d2244197fd752b9569b5b20baf574308","src/events/h3.rs":"4799179c4d18403a3936a327c483d110bd058d42061f9cdd39601b3e91500c1b","src/events/mod.rs":"75f57b4717fa9777e19d61b99b6a79164f0e8bca9b4681c3ab11b204320c8c55","src/events/qpack.rs":"5c7267c45e3fb947cdfa946f9f9692d3e3e36a166f70124ba293dc27534267d0","src/events/quic.rs":"88b884f5788c671ffee79a3448f367c18f95ee30531262fcc14310d80e662f4a","src/events/security.rs":"e9852d7de16851b62c3e0a886a2c1a31d237e62574ef88428ef62dd179b0b008","src/lib.rs":"bbc190a6d0f484fd723f9df6c1b2a4596f826e0282ad40ee17a0822ea28a5626","src/reader.rs":"4e0069c24aca9cb99d75075c9b784fa02855ea449d2f1528bea944a4e02a9af5","src/streamer.rs":"4774c2abde1a5b0f4448aac06c62c7927208c12f338c46981f80c98703b54074"},"package":"9c0407438c69b3d99714a796a135cbfb2d60744e4747fb2b46a87acd1c1fcd0e"}

8
third_party/rust/qlog/Cargo.toml поставляемый
Просмотреть файл

@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "qlog"
version = "0.11.0"
version = "0.12.0"
authors = ["Lucas Pardue <lucaspardue.24.7@gmail.com>"]
description = "qlog data model for QUIC and HTTP/3"
readme = "README.md"
@ -25,13 +25,13 @@ categories = ["network-programming"]
license = "BSD-2-Clause"
repository = "https://github.com/cloudflare/quiche"
[dependencies]
serde_derive = "1.0"
[dependencies.serde]
version = "1.0.139"
features = ["derive"]
[dependencies.serde_derive]
version = "1.0"
[dependencies.serde_json]
version = "1.0"
features = ["preserve_order"]

3
third_party/rust/qlog/src/events/h3.rs поставляемый
Просмотреть файл

@ -209,9 +209,8 @@ pub struct H3ParametersRestored {
pub struct H3StreamTypeSet {
pub owner: Option<H3Owner>,
pub stream_id: u64,
pub stream_type: H3StreamType,
pub stream_type_value: Option<u64>,
pub associated_push_id: Option<u64>,
}