mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 15:25:52 +00:00
Bug 1698438 - Neqo version 0.4.22 r=necko-reviewers,dragana
Differential Revision: https://phabricator.services.mozilla.com/D108750
This commit is contained in:
parent
de0da5772d
commit
cb78102ea6
@ -15,7 +15,7 @@ rev = "01c7a0da8d34059f7dae8ab9e7512529ff16347a"
|
||||
[source."https://github.com/mozilla/neqo"]
|
||||
git = "https://github.com/mozilla/neqo"
|
||||
replace-with = "vendored-sources"
|
||||
tag = "v0.4.21"
|
||||
tag = "v0.4.22"
|
||||
|
||||
[source."https://github.com/mozilla/mp4parse-rust"]
|
||||
git = "https://github.com/mozilla/mp4parse-rust"
|
||||
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -3336,8 +3336,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-common"
|
||||
version = "0.4.21"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.21#0e6040cd6385c038f8b7f604bcb09ad74d29e0d6"
|
||||
version = "0.4.22"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.22#33a8796b2606b5c37430a8804cae17e374f6dbfe"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"env_logger",
|
||||
@ -3348,8 +3348,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-crypto"
|
||||
version = "0.4.21"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.21#0e6040cd6385c038f8b7f604bcb09ad74d29e0d6"
|
||||
version = "0.4.22"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.22#33a8796b2606b5c37430a8804cae17e374f6dbfe"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"log",
|
||||
@ -3361,8 +3361,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-http3"
|
||||
version = "0.4.21"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.21#0e6040cd6385c038f8b7f604bcb09ad74d29e0d6"
|
||||
version = "0.4.22"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.22#33a8796b2606b5c37430a8804cae17e374f6dbfe"
|
||||
dependencies = [
|
||||
"log",
|
||||
"neqo-common",
|
||||
@ -3375,8 +3375,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-qpack"
|
||||
version = "0.4.21"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.21#0e6040cd6385c038f8b7f604bcb09ad74d29e0d6"
|
||||
version = "0.4.22"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.22#33a8796b2606b5c37430a8804cae17e374f6dbfe"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
@ -3389,8 +3389,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "neqo-transport"
|
||||
version = "0.4.21"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.21#0e6040cd6385c038f8b7f604bcb09ad74d29e0d6"
|
||||
version = "0.4.22"
|
||||
source = "git+https://github.com/mozilla/neqo?tag=v0.4.22#33a8796b2606b5c37430a8804cae17e374f6dbfe"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
|
@ -8,10 +8,10 @@ edition = "2018"
|
||||
name = "neqo_glue"
|
||||
|
||||
[dependencies]
|
||||
neqo-http3 = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-transport = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-qpack = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-http3 = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-transport = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-qpack = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
||||
@ -20,7 +20,7 @@ log = "0.4.0"
|
||||
qlog = "0.4.0"
|
||||
|
||||
[dependencies.neqo-crypto]
|
||||
tag = "v0.4.21"
|
||||
tag = "v0.4.22"
|
||||
git = "https://github.com/mozilla/neqo"
|
||||
default-features = false
|
||||
features = ["gecko"]
|
||||
|
@ -5,16 +5,16 @@ authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
neqo-transport = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-http3 = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-qpack = { tag = "v0.4.21", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-transport = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-common = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-http3 = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
neqo-qpack = { tag = "v0.4.22", git = "https://github.com/mozilla/neqo" }
|
||||
mio = "0.6.17"
|
||||
mio-extras = "2.0.5"
|
||||
log = "0.4.0"
|
||||
|
||||
[dependencies.neqo-crypto]
|
||||
tag = "v0.4.21"
|
||||
tag = "v0.4.22"
|
||||
git = "https://github.com/mozilla/neqo"
|
||||
default-features = false
|
||||
features = ["gecko"]
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"1c3a6822f7e9c513214ad1f0be4eafc0aa17cb6272ef38dfd716b37c93ef74f8","src/codec.rs":"1cba28857d97c1f9021941f1220cecaba736bd5d8907cee6e9a3055735c06568","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/incrdecoder.rs":"b97a40f89da6832ad92bd652cb6ceac82a0a5cc68a9b3d0c96f89d02e1ee9902","src/lib.rs":"5af4f0e7284b49d1b03b5eee78f2b814e5fa6eb9424507291e25b1955aebe007","src/log.rs":"b69e492af85e65866cb6588138e8a337dd897d3ce399cb4e9fb8cc04ac042b7f","src/qlog.rs":"a8aa4f1f0110076b401f6e5a7057ec154c7ad3677374a21ceca1209469b9c07d","src/timer.rs":"66886b3697e1b4232d9d9892a12d93afd3381812a8ff901bceac4bb48b264607","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
|
||||
{"files":{"Cargo.toml":"3a8d7b338de5c01cacba0ada4b8bda9ba4ac8ed689a99727734ff6b477d492a9","build.rs":"f6d7d76e8fbe697bd094345d14075758fc011464a5fea1521376faf361e0fb7d","src/codec.rs":"32ffe9fc505637c469c3a84dec8035e245be93b8092594b80908987b9dd40534","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/hrtime.rs":"609b38a466f0743617e8772e661e312089eb17a8df827b1893e6aadc8347e5b3","src/incrdecoder.rs":"b97a40f89da6832ad92bd652cb6ceac82a0a5cc68a9b3d0c96f89d02e1ee9902","src/lib.rs":"659d5397175c1645eab07a999b6ccf0730d02d9614b58720955af83afef0f0e4","src/log.rs":"b69e492af85e65866cb6588138e8a337dd897d3ce399cb4e9fb8cc04ac042b7f","src/qlog.rs":"e59c4e6dcf9c70553dd6f58da41ff2053ea67b008cac186742140352f5044130","src/timer.rs":"66886b3697e1b4232d9d9892a12d93afd3381812a8ff901bceac4bb48b264607","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
|
3
third_party/rust/neqo-common/Cargo.toml
vendored
3
third_party/rust/neqo-common/Cargo.toml
vendored
@ -1,9 +1,10 @@
|
||||
[package]
|
||||
name = "neqo-common"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
authors = ["Bobby Holley <bobbyholley@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
log = {version = "0.4.0", default-features = false}
|
||||
|
4
third_party/rust/neqo-common/build.rs
vendored
Normal file
4
third_party/rust/neqo-common/build.rs
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
#[cfg(windows)]
|
||||
println!("cargo:rustc-link-lib=winmm");
|
||||
}
|
5
third_party/rust/neqo-common/src/codec.rs
vendored
5
third_party/rust/neqo-common/src/codec.rs
vendored
@ -764,9 +764,8 @@ mod tests {
|
||||
enc.encode_vvec_with(|enc_inner| {
|
||||
enc_inner.encode(&[0xa5; 65]);
|
||||
});
|
||||
let mut v: Vec<u8> = enc.into();
|
||||
let _ = v.split_off(3);
|
||||
assert_eq!(v, vec![0x40, 0x41, 0xa5]);
|
||||
let v: Vec<u8> = enc.into();
|
||||
assert_eq!(&v[..3], &[0x40, 0x41, 0xa5]);
|
||||
}
|
||||
|
||||
// Test that Deref to &[u8] works for Encoder.
|
||||
|
484
third_party/rust/neqo-common/src/hrtime.rs
vendored
Normal file
484
third_party/rust/neqo-common/src/hrtime.rs
vendored
Normal file
@ -0,0 +1,484 @@
|
||||
// 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::cell::RefCell;
|
||||
use std::cmp::{max, min};
|
||||
use std::convert::TryFrom;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::time::Duration;
|
||||
|
||||
/// A quantized `Duration`. This currently just produces 16 discrete values
|
||||
/// corresponding to whole milliseconds. Future implementations might choose
|
||||
/// a different allocation, such as a logarithmic scale.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Period(u8);
|
||||
|
||||
impl Period {
|
||||
const MAX: Period = Period(16);
|
||||
const MIN: Period = Period(1);
|
||||
|
||||
#[cfg(windows)]
|
||||
fn as_uint(&self) -> win::UINT {
|
||||
win::UINT::from(self.0)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn scaled(&self, scale: f64) -> f64 {
|
||||
scale * f64::from(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Duration> for Period {
|
||||
fn from(p: Duration) -> Self {
|
||||
let rounded = u8::try_from(p.as_millis()).unwrap_or(Self::MAX.0);
|
||||
Self(max(Self::MIN.0, min(rounded, Self::MAX.0)))
|
||||
}
|
||||
}
|
||||
|
||||
/// This counts instances of `Period`, except those of `Period::MAX`.
|
||||
#[derive(Default)]
|
||||
struct PeriodSet {
|
||||
counts: [usize; (Period::MAX.0 - Period::MIN.0) as usize],
|
||||
}
|
||||
|
||||
impl PeriodSet {
|
||||
fn idx(&mut self, p: Period) -> &mut usize {
|
||||
debug_assert!(p >= Period::MIN);
|
||||
&mut self.counts[usize::from(p.0 - Period::MIN.0)]
|
||||
}
|
||||
|
||||
fn add(&mut self, p: Period) {
|
||||
if p != Period::MAX {
|
||||
*self.idx(p) += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn remove(&mut self, p: Period) {
|
||||
if p != Period::MAX {
|
||||
debug_assert_ne!(*self.idx(p), 0);
|
||||
*self.idx(p) -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn min(&self) -> Option<Period> {
|
||||
for (i, v) in self.counts.iter().enumerate() {
|
||||
if *v > 0 {
|
||||
return Some(Period(u8::try_from(i).unwrap() + Period::MIN.0));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod win {
|
||||
// These are manually extracted from the 10Mb bindings generated
|
||||
// by bindgen when provided with the simple header:
|
||||
// #include <windows.h>
|
||||
// #include <timeapi.h>
|
||||
// The complete bindings don't compile and filtering them is work.
|
||||
pub type UINT = ::std::os::raw::c_uint;
|
||||
pub type MMRESULT = UINT;
|
||||
extern "C" {
|
||||
pub fn timeBeginPeriod(uPeriod: UINT) -> MMRESULT;
|
||||
pub fn timeEndPeriod(uPeriod: UINT) -> MMRESULT;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[allow(non_camel_case_types)]
|
||||
mod mac {
|
||||
use std::mem::size_of;
|
||||
|
||||
// These are manually extracted from the many bindings generated
|
||||
// by bindgen when provided with the simple header:
|
||||
// #include <mach/mach_init.h>
|
||||
// #include <mach/mach_time.h>
|
||||
// #include <mach/thread_policy.h>
|
||||
// #include <pthread.h>
|
||||
|
||||
type __darwin_natural_t = ::std::os::raw::c_uint;
|
||||
type __darwin_mach_port_name_t = __darwin_natural_t;
|
||||
type __darwin_mach_port_t = __darwin_mach_port_name_t;
|
||||
type mach_port_t = __darwin_mach_port_t;
|
||||
type thread_t = mach_port_t;
|
||||
type natural_t = __darwin_natural_t;
|
||||
type thread_policy_flavor_t = natural_t;
|
||||
type integer_t = ::std::os::raw::c_int;
|
||||
type thread_policy_t = *mut integer_t;
|
||||
type mach_msg_type_number_t = natural_t;
|
||||
type boolean_t = ::std::os::raw::c_uint;
|
||||
type kern_return_t = ::std::os::raw::c_int;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
struct mach_timebase_info {
|
||||
numer: u32,
|
||||
denom: u32,
|
||||
}
|
||||
type mach_timebase_info_t = *mut mach_timebase_info;
|
||||
type mach_timebase_info_data_t = mach_timebase_info;
|
||||
extern "C" {
|
||||
fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct thread_time_constraint_policy {
|
||||
period: u32,
|
||||
computation: u32,
|
||||
constraint: u32,
|
||||
preemptible: boolean_t,
|
||||
}
|
||||
|
||||
const THREAD_TIME_CONSTRAINT_POLICY: thread_policy_flavor_t = 2;
|
||||
const THREAD_TIME_CONSTRAINT_POLICY_COUNT: mach_msg_type_number_t =
|
||||
(size_of::<thread_time_constraint_policy>() / size_of::<integer_t>())
|
||||
as mach_msg_type_number_t;
|
||||
|
||||
// These function definitions are taken from a comment in <thread_policy.h>.
|
||||
// Why they are inaccessible is unknown, but they work as declared.
|
||||
extern "C" {
|
||||
fn thread_policy_set(
|
||||
thread: thread_t,
|
||||
flavor: thread_policy_flavor_t,
|
||||
policy_info: thread_policy_t,
|
||||
count: mach_msg_type_number_t,
|
||||
) -> kern_return_t;
|
||||
fn thread_policy_get(
|
||||
thread: thread_t,
|
||||
flavor: thread_policy_flavor_t,
|
||||
policy_info: thread_policy_t,
|
||||
count: *mut mach_msg_type_number_t,
|
||||
get_default: *mut boolean_t,
|
||||
) -> kern_return_t;
|
||||
}
|
||||
|
||||
enum _opaque_pthread_t {} // An opaque type is fine here.
|
||||
type __darwin_pthread_t = *mut _opaque_pthread_t;
|
||||
type pthread_t = __darwin_pthread_t;
|
||||
|
||||
extern "C" {
|
||||
fn pthread_self() -> pthread_t;
|
||||
fn pthread_mach_thread_np(thread: pthread_t) -> mach_port_t;
|
||||
}
|
||||
|
||||
/// Set a thread time policy.
|
||||
pub fn set_thread_policy(mut policy: thread_time_constraint_policy) {
|
||||
let _ = unsafe {
|
||||
thread_policy_set(
|
||||
pthread_mach_thread_np(pthread_self()),
|
||||
THREAD_TIME_CONSTRAINT_POLICY,
|
||||
&mut policy as *mut thread_time_constraint_policy as *mut _,
|
||||
THREAD_TIME_CONSTRAINT_POLICY_COUNT,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_scale() -> f64 {
|
||||
const NANOS_PER_MSEC: f64 = 1_000_000.0;
|
||||
let mut timebase_info = mach_timebase_info_data_t::default();
|
||||
unsafe {
|
||||
mach_timebase_info(&mut timebase_info);
|
||||
}
|
||||
f64::from(timebase_info.denom) * NANOS_PER_MSEC / f64::from(timebase_info.numer)
|
||||
}
|
||||
|
||||
/// Create a realtime policy and set it.
|
||||
pub fn set_realtime(base: f64) {
|
||||
let policy = thread_time_constraint_policy {
|
||||
period: base as u32, // Base interval
|
||||
computation: (base * 0.5) as u32,
|
||||
constraint: (base * 1.0) as u32,
|
||||
preemptible: 1,
|
||||
};
|
||||
set_thread_policy(policy);
|
||||
}
|
||||
|
||||
/// Get the default policy.
|
||||
pub fn get_default_policy() -> thread_time_constraint_policy {
|
||||
let mut policy = thread_time_constraint_policy::default();
|
||||
let mut count = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
|
||||
let mut get_default = 0;
|
||||
let _ = unsafe {
|
||||
thread_policy_get(
|
||||
pthread_mach_thread_np(pthread_self()),
|
||||
THREAD_TIME_CONSTRAINT_POLICY,
|
||||
&mut policy as *mut thread_time_constraint_policy as *mut _,
|
||||
&mut count,
|
||||
&mut get_default,
|
||||
)
|
||||
};
|
||||
policy
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle for a high-resolution timer of a specific period.
|
||||
pub struct Handle {
|
||||
hrt: Rc<RefCell<Time>>,
|
||||
active: Period,
|
||||
hysteresis: [Period; Self::HISTORY],
|
||||
hysteresis_index: usize,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
const HISTORY: usize = 8;
|
||||
|
||||
fn new(hrt: Rc<RefCell<Time>>, active: Period) -> Self {
|
||||
Self {
|
||||
hrt,
|
||||
active,
|
||||
hysteresis: [Period::MAX; Self::HISTORY],
|
||||
hysteresis_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Update shortcut. Equivalent to dropping the current reference and
|
||||
/// calling `HrTime::get` again with the new period, except that this applies
|
||||
/// a little hysteresis that smoothes out fluctuations.
|
||||
pub fn update(&mut self, period: Duration) {
|
||||
self.hysteresis[self.hysteresis_index] = Period::from(period);
|
||||
self.hysteresis_index += 1;
|
||||
self.hysteresis_index %= self.hysteresis.len();
|
||||
|
||||
let mut first = Period::MAX;
|
||||
let mut second = Period::MAX;
|
||||
for i in &self.hysteresis {
|
||||
if *i < first {
|
||||
second = first;
|
||||
first = *i;
|
||||
} else if *i < second {
|
||||
second = *i;
|
||||
}
|
||||
}
|
||||
|
||||
if second != self.active {
|
||||
let mut b = self.hrt.borrow_mut();
|
||||
b.periods.remove(self.active);
|
||||
self.active = second;
|
||||
b.periods.add(self.active);
|
||||
b.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
self.hrt.borrow_mut().remove(self.active);
|
||||
}
|
||||
}
|
||||
|
||||
/// Holding an instance of this indicates that high resolution timers are enabled.
|
||||
pub struct Time {
|
||||
periods: PeriodSet,
|
||||
active: Option<Period>,
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
scale: f64,
|
||||
#[cfg(target_os = "macos")]
|
||||
deflt: mac::thread_time_constraint_policy,
|
||||
}
|
||||
impl Time {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
periods: PeriodSet::default(),
|
||||
active: None,
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
scale: mac::get_scale(),
|
||||
#[cfg(target_os = "macos")]
|
||||
deflt: mac::get_default_policy(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)] // Only on some platforms is it unused.
|
||||
fn start(&self) {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if let Some(p) = self.active {
|
||||
mac::set_realtime(p.scaled(self.scale));
|
||||
} else {
|
||||
mac::set_thread_policy(self.deflt.clone());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if let Some(p) = self.active {
|
||||
assert_eq!(0, unsafe { win::timeBeginPeriod(p.as_uint()) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)] // Only on some platforms is it unused.
|
||||
fn stop(&self) {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if let Some(p) = self.active {
|
||||
assert_eq!(0, unsafe { win::timeEndPeriod(p.as_uint()) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self) {
|
||||
let next = self.periods.min();
|
||||
if next != self.active {
|
||||
self.stop();
|
||||
self.active = next;
|
||||
self.start();
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, p: Period) {
|
||||
self.periods.add(p);
|
||||
self.update();
|
||||
}
|
||||
|
||||
fn remove(&mut self, p: Period) {
|
||||
self.periods.remove(p);
|
||||
self.update();
|
||||
}
|
||||
|
||||
/// Enable high resolution time. Returns a thread-bound handle that
|
||||
/// needs to be held until the high resolution time is no longer needed.
|
||||
/// The handle can also be used to update the resolution.
|
||||
#[must_use]
|
||||
pub fn get(period: Duration) -> Handle {
|
||||
thread_local! {
|
||||
static HR_TIME: RefCell<Weak<RefCell<Time>>> = RefCell::default();
|
||||
}
|
||||
|
||||
HR_TIME.with(|r| {
|
||||
let mut b = r.borrow_mut();
|
||||
let hrt = b.upgrade().unwrap_or_else(|| {
|
||||
let hrt = Rc::new(RefCell::new(Time::new()));
|
||||
*b = Rc::downgrade(&hrt);
|
||||
hrt
|
||||
});
|
||||
|
||||
let p = Period::from(period);
|
||||
hrt.borrow_mut().add(p);
|
||||
Handle::new(hrt, p)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Time {
|
||||
fn drop(&mut self) {
|
||||
self.stop();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if self.active.is_some() {
|
||||
mac::set_thread_policy(self.deflt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Time;
|
||||
use std::thread::{sleep, spawn};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
const ONE: Duration = Duration::from_millis(1);
|
||||
const ONE_AND_A_BIT: Duration = Duration::from_micros(1500);
|
||||
/// A limit for when high resolution timers are disabled.
|
||||
const GENEROUS: Duration = Duration::from_millis(30);
|
||||
|
||||
fn validate_delays(max_lag: Duration) -> Result<(), ()> {
|
||||
const DELAYS: &[u64] = &[1, 2, 3, 5, 8, 10, 12, 15, 20, 25, 30];
|
||||
let durations = DELAYS.iter().map(|&d| Duration::from_millis(d));
|
||||
|
||||
let mut s = Instant::now();
|
||||
for d in durations {
|
||||
sleep(d);
|
||||
let e = Instant::now();
|
||||
let actual = e - s;
|
||||
let lag = actual - d;
|
||||
println!("sleep({:?}) \u{2192} {:?} \u{394}{:?}", d, actual, lag);
|
||||
if lag > max_lag {
|
||||
return Err(());
|
||||
}
|
||||
s = Instant::now();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate the delays twice. Sometimes the first run can stall.
|
||||
/// Reliability in CI is more important than reliable timers.
|
||||
fn check_delays(max_lag: Duration) {
|
||||
if validate_delays(max_lag).is_err() {
|
||||
sleep(Duration::from_millis(50));
|
||||
validate_delays(max_lag).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that you have to run this test alone or other tests will
|
||||
/// grab the high resolution timer and this will run faster.
|
||||
#[test]
|
||||
fn baseline() {
|
||||
check_delays(GENEROUS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_ms() {
|
||||
let _hrt = Time::get(ONE);
|
||||
check_delays(ONE_AND_A_BIT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multithread_baseline() {
|
||||
let thr = spawn(move || {
|
||||
baseline();
|
||||
});
|
||||
baseline();
|
||||
thr.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_ms_multi() {
|
||||
let thr = spawn(move || {
|
||||
one_ms();
|
||||
});
|
||||
one_ms();
|
||||
thr.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_multi() {
|
||||
let thr = spawn(move || {
|
||||
one_ms();
|
||||
});
|
||||
let _hrt = Time::get(Duration::from_millis(4));
|
||||
check_delays(Duration::from_millis(5));
|
||||
thr.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update() {
|
||||
let mut hrt = Time::get(Duration::from_millis(4));
|
||||
check_delays(Duration::from_millis(5));
|
||||
hrt.update(ONE);
|
||||
check_delays(ONE_AND_A_BIT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_multi() {
|
||||
let thr = spawn(move || {
|
||||
update();
|
||||
});
|
||||
update();
|
||||
thr.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max() {
|
||||
let _hrt = Time::get(Duration::from_secs(1));
|
||||
check_delays(GENEROUS);
|
||||
}
|
||||
}
|
1
third_party/rust/neqo-common/src/lib.rs
vendored
1
third_party/rust/neqo-common/src/lib.rs
vendored
@ -10,6 +10,7 @@
|
||||
mod codec;
|
||||
mod datagram;
|
||||
pub mod event;
|
||||
pub mod hrtime;
|
||||
mod incrdecoder;
|
||||
pub mod log;
|
||||
pub mod qlog;
|
||||
|
12
third_party/rust/neqo-common/src/qlog.rs
vendored
12
third_party/rust/neqo-common/src/qlog.rs
vendored
@ -19,7 +19,7 @@ use qlog::{
|
||||
use crate::Role;
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct NeqoQlog {
|
||||
inner: Rc<RefCell<Option<NeqoQlogShared>>>,
|
||||
}
|
||||
@ -51,9 +51,7 @@ impl NeqoQlog {
|
||||
/// Create a disabled `NeqoQlog` configuration.
|
||||
#[must_use]
|
||||
pub fn disabled() -> Self {
|
||||
Self {
|
||||
inner: Rc::new(RefCell::new(None)),
|
||||
}
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// If logging enabled, closure may generate an event to be logged.
|
||||
@ -88,12 +86,6 @@ impl NeqoQlog {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NeqoQlog {
|
||||
fn default() -> Self {
|
||||
Self::disabled()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for NeqoQlogShared {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "NeqoQlog writing to {}", self.qlog_path.display())
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"7d7c790d2c56b305869e1c9ef96435102b2b43102a45659c2e65d3223c3d5885","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"a896b4accf5fbaf146a45a060142974bfa2f59d6a5ab18c5080753078ae39474","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":"5e7fa86d565707908611b37f9ec679d29afa33cdc4d0c589e398d4240e236f68","src/aead.rs":"e26ad34f7168f42aa87eb3a6455af3191a0e8555782b1d70032fe1d248922f98","src/agent.rs":"9dae2fa87a5a7b65dfc7fdd1b2ab1be0f75f1d9ee6704b44edd9bd406252b10a","src/agentio.rs":"cc562d09a09719b90b4e1d147fd579e3e89b683448709e920033bceaea108a61","src/auth.rs":"71ac7e297a5f872d26cf67b6bbd96e4548ea38374bdd84c1094f76a5de4ed1cb","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"c39ee506a10d685fda77c1d2ddf691b595b067b4e1044ac7a21e360119d6002b","src/err.rs":"04f38831ca62d29d8aadfe9daf95fd29e68ece184e6d3e00bfb9ee1d12744033","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"97cba23247e5f9656f27587214f7d7370a69174bae5960a012ce3e6fc99f9116","src/hkdf.rs":"40e44f4280497ef525c2b4c465f14f06d241150851668b264ee958f74321cfbe","src/hp.rs":"974844d885d23c480d5256621053d590b331067b43ee4061e519e58487f5852b","src/lib.rs":"3b22108a069c8c9f1b78e94d48c8759b17e0941b28e2def3fa343d6acace4b6d","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"0b62ee5938aefb82e8faee5aa14e990a00442cc9744e8ba22eda80b32030c42c","src/prio.rs":"2f0d86385941aaed7c710e6b82aa1f7adc6ded74b90efbbbcafba6dd9ea1ccdb","src/replay.rs":"40924865994396441a68e6009ecbdf352d6a02fdf539aa65604124e26bffb4d3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"acb5befa74e06281c6f80d7298efc58f568bb4e6d949b4225c335e3f392be741","src/selfencrypt.rs":"429cb889a4e9e2345888cc033115c0aa306d2ff90bdfe22b3067700eb1426c37","src/ssl.rs":"3e3a4f539f3c4d18bd6e774dc34fca611db0c75bba00badcd2078c975db055bf","src/time.rs":"df2b14912f70b8262c76ec7907996da6993a31fbb1682fdf6fe51b421800dcfe","tests/aead.rs":"a1d8eb69f5672e064f84dce3d214b347a396718e3de56d57ccc108ee87f1cbc1","tests/agent.rs":"d43e5b05dcc845394d3c7312974faae0fdcbc325c07c970aeb7ef30c3ade652e","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"93c478fcd07d29691007abd6dcfcd2014c10c23b0206ba2d97d01594e4d64397","tests/hkdf.rs":"539235e9dcf2a56b72961a9a04f0080409adf6bf465bfad7c30026421b2d4326","tests/hp.rs":"e52a7d2f4387f2dfe8bfe1da5867e8e0d3eb51e171c6904e18b18c4343536af8","tests/init.rs":"20aad800ac793aaf83059cf860593750509fdedeeff0c08a648e7a5cb398dae0","tests/selfencrypt.rs":"46e9a1a09c2ae577eb106d23a5cdacf762575c0dea1948aedab06ef7389ce713"},"package":null}
|
||||
{"files":{"Cargo.toml":"ccdc371597cdac7816fc8da88046e56543339c88002efd10a071d72c1eb0b20b","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"a896b4accf5fbaf146a45a060142974bfa2f59d6a5ab18c5080753078ae39474","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":"5e7fa86d565707908611b37f9ec679d29afa33cdc4d0c589e398d4240e236f68","src/aead.rs":"e26ad34f7168f42aa87eb3a6455af3191a0e8555782b1d70032fe1d248922f98","src/agent.rs":"9dae2fa87a5a7b65dfc7fdd1b2ab1be0f75f1d9ee6704b44edd9bd406252b10a","src/agentio.rs":"cc562d09a09719b90b4e1d147fd579e3e89b683448709e920033bceaea108a61","src/auth.rs":"71ac7e297a5f872d26cf67b6bbd96e4548ea38374bdd84c1094f76a5de4ed1cb","src/cert.rs":"fd3fd2bbb38754bdcee3898549feae412943c9f719032531c1ad6e61783b5394","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/err.rs":"04f38831ca62d29d8aadfe9daf95fd29e68ece184e6d3e00bfb9ee1d12744033","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"97cba23247e5f9656f27587214f7d7370a69174bae5960a012ce3e6fc99f9116","src/hkdf.rs":"40e44f4280497ef525c2b4c465f14f06d241150851668b264ee958f74321cfbe","src/hp.rs":"974844d885d23c480d5256621053d590b331067b43ee4061e519e58487f5852b","src/lib.rs":"3b22108a069c8c9f1b78e94d48c8759b17e0941b28e2def3fa343d6acace4b6d","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"a24b87855cfee4583d16e319b6b8c67b7031dede3d74c833557f48607626ebd3","src/prio.rs":"2f0d86385941aaed7c710e6b82aa1f7adc6ded74b90efbbbcafba6dd9ea1ccdb","src/replay.rs":"40924865994396441a68e6009ecbdf352d6a02fdf539aa65604124e26bffb4d3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"acb5befa74e06281c6f80d7298efc58f568bb4e6d949b4225c335e3f392be741","src/selfencrypt.rs":"429cb889a4e9e2345888cc033115c0aa306d2ff90bdfe22b3067700eb1426c37","src/ssl.rs":"3e3a4f539f3c4d18bd6e774dc34fca611db0c75bba00badcd2078c975db055bf","src/time.rs":"6e04eb590b03d8340a2db04214fd4e57980f02f984769c5ec9393f9fb2a6d876","tests/aead.rs":"a1d8eb69f5672e064f84dce3d214b347a396718e3de56d57ccc108ee87f1cbc1","tests/agent.rs":"d43e5b05dcc845394d3c7312974faae0fdcbc325c07c970aeb7ef30c3ade652e","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"93c478fcd07d29691007abd6dcfcd2014c10c23b0206ba2d97d01594e4d64397","tests/hkdf.rs":"539235e9dcf2a56b72961a9a04f0080409adf6bf465bfad7c30026421b2d4326","tests/hp.rs":"e52a7d2f4387f2dfe8bfe1da5867e8e0d3eb51e171c6904e18b18c4343536af8","tests/init.rs":"20aad800ac793aaf83059cf860593750509fdedeeff0c08a648e7a5cb398dae0","tests/selfencrypt.rs":"46e9a1a09c2ae577eb106d23a5cdacf762575c0dea1948aedab06ef7389ce713"},"package":null}
|
2
third_party/rust/neqo-crypto/Cargo.toml
vendored
2
third_party/rust/neqo-crypto/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-crypto"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
authors = ["Martin Thomson <mt@lowentropy.net>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
@ -16,11 +16,11 @@ pub type Alert = u8;
|
||||
pub type Epoch = u16;
|
||||
// TLS doesn't really have an "initial" concept that maps to QUIC so directly,
|
||||
// but this should be clear enough.
|
||||
pub const TLS_EPOCH_INITIAL: Epoch = 0 as Epoch;
|
||||
pub const TLS_EPOCH_ZERO_RTT: Epoch = 1 as Epoch;
|
||||
pub const TLS_EPOCH_HANDSHAKE: Epoch = 2 as Epoch;
|
||||
pub const TLS_EPOCH_INITIAL: Epoch = 0_u16;
|
||||
pub const TLS_EPOCH_ZERO_RTT: Epoch = 1_u16;
|
||||
pub const TLS_EPOCH_HANDSHAKE: Epoch = 2_u16;
|
||||
// Also, we don't use TLS epochs > 3.
|
||||
pub const TLS_EPOCH_APPLICATION_DATA: Epoch = 3 as Epoch;
|
||||
pub const TLS_EPOCH_APPLICATION_DATA: Epoch = 3_u16;
|
||||
|
||||
/// Rather than defining a type alias and a bunch of constants, which leads to a ton of repetition,
|
||||
/// use this macro.
|
||||
|
2
third_party/rust/neqo-crypto/src/p11.rs
vendored
2
third_party/rust/neqo-crypto/src/p11.rs
vendored
@ -70,7 +70,7 @@ impl SymKey {
|
||||
///
|
||||
/// # Errors
|
||||
/// Internal errors in case of failures in NSS.
|
||||
pub fn as_bytes<'a>(&'a self) -> Res<&'a [u8]> {
|
||||
pub fn as_bytes(&self) -> Res<&[u8]> {
|
||||
secstatus_to_res(unsafe { PK11_ExtractKeyValue(self.ptr) })?;
|
||||
|
||||
let key_item = unsafe { PK11_GetKeyData(self.ptr) };
|
||||
|
3
third_party/rust/neqo-crypto/src/time.rs
vendored
3
third_party/rust/neqo-crypto/src/time.rs
vendored
@ -120,8 +120,7 @@ impl TryInto<PRTime> for Time {
|
||||
// TODO(mt) use checked_duration_since when that is available.
|
||||
let delta = self.t.duration_since(base.instant);
|
||||
if let Ok(d) = PRTime::try_from(delta.as_micros()) {
|
||||
d.checked_add(base.prtime)
|
||||
.map_or(Err(Error::TimeTravelError), Ok)
|
||||
d.checked_add(base.prtime).ok_or(Error::TimeTravelError)
|
||||
} else {
|
||||
Err(Error::TimeTravelError)
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"9e4aed1f000f437e21143b650ebf4aa31ddcd647ad471362febcf44e4579b78c","src/client_events.rs":"87e7c323ec2ceb759da7d6f2bf24e774f6f2e3833f63454d09cc09f47fccfa8e","src/connection.rs":"7ce294aa57c4ffbdf5f849ad28ca3e38a491abbd2ebbbada2a6f272356535ab9","src/connection_client.rs":"e35e38fb4a87d0eba1e327a3029cf75f8e53de0fa4754120210c265613b53155","src/connection_server.rs":"884016ac4a0e43e0b14146b057c4d8d906f5aac94d47e05312298f76b0818e85","src/control_stream_local.rs":"2e9483d79dc00a3e5ef51ea2b0f28fda2b67348996c47729947c70a8be3007ed","src/control_stream_remote.rs":"1dfac4956a7d6971e2cef2c83963d838e73aa3bf3286b7bde97099978c41d527","src/hframe.rs":"3620c6d114e6d5b98447a2dd2a7cb6872562ebda2cc6de828177b745c8dcbf4d","src/lib.rs":"f57ddf98d38c112c52e1682d1a4c8ef244f4f0c8c463fbf371b8dc4bf5cf40a8","src/push_controller.rs":"70811f87bf0562630a3a68dc0783fce3c4694ab12de9cac835a803e1115431a5","src/push_stream.rs":"5f3a5c6d72c0a8e4d1c1c5041125f7aff9a65950fa60c77f42cd4b35c768f585","src/qlog.rs":"29c0e3c4c9571eb7fe905967edeb1c4bc236b1e35a0e0f11a4a847f1d246681d","src/recv_message.rs":"975fe666de73493501987bdd285efbdef6efce8e721e3a3411af9baf9599c4aa","src/send_message.rs":"5a0214c728f181aaeaa99121fcda804e22866e5150d2f2a3aa8abeb006f1fe14","src/server.rs":"6979eb282f6a0b27439857cd3686c2f69859f87d6d362f5f921d29fcca1f97b1","src/server_connection_events.rs":"762ddb87f700abe91ae1ae78ebbb87a88da0c0a341748b0751b01099870e9985","src/server_events.rs":"c8cdd838129ef6b1e77ba63608d20f6d297bca4e67f26a077d1c015a5e2a3b82","src/settings.rs":"127a51fa7857b870718baa14340b0461d86a67e59bf1a8cb42d7bae0240c0ef1","src/stream_type_reader.rs":"aacb2e865f79b3ac55a887fd670f2286d8ffef94f7d8b3ecfa7e0cccbfa9ec04","tests/httpconn.rs":"1a97a80f7abe11c6ba0bd9b41003be6b293049164daa21e907365d93b00a782f"},"package":null}
|
||||
{"files":{"Cargo.toml":"e1d462db91bf3876e821e168b9d45ecd64c4733a59d2fe955222d4e178cb8a86","src/client_events.rs":"87e7c323ec2ceb759da7d6f2bf24e774f6f2e3833f63454d09cc09f47fccfa8e","src/connection.rs":"bd486796ce71347aeb28f81d16a104dfc74236adf95c4ae448af3a21c52ae518","src/connection_client.rs":"111ae67649df554ef822305a65f6142eddb3c00f76599b9ad355f0524e3dc08c","src/connection_server.rs":"884016ac4a0e43e0b14146b057c4d8d906f5aac94d47e05312298f76b0818e85","src/control_stream_local.rs":"2e9483d79dc00a3e5ef51ea2b0f28fda2b67348996c47729947c70a8be3007ed","src/control_stream_remote.rs":"1dfac4956a7d6971e2cef2c83963d838e73aa3bf3286b7bde97099978c41d527","src/hframe.rs":"d6d8365a333e33d41ae37d2e774f5dffb7a9676ddfb50de56bb98a50bfe49cbb","src/lib.rs":"f57ddf98d38c112c52e1682d1a4c8ef244f4f0c8c463fbf371b8dc4bf5cf40a8","src/push_controller.rs":"fcf7873e8c41560b16d443e77f897e5e8b3fccb55f35f6d9997bac935e7744c3","src/push_stream.rs":"5f3a5c6d72c0a8e4d1c1c5041125f7aff9a65950fa60c77f42cd4b35c768f585","src/qlog.rs":"29c0e3c4c9571eb7fe905967edeb1c4bc236b1e35a0e0f11a4a847f1d246681d","src/recv_message.rs":"cb6e08fb2d479c68a21b452ba616bdb36dbc7579012b0705791d8f05550c76ba","src/send_message.rs":"7276268e5b190a1dc019d74034dad8a3c0c4b8cb409a135c733c038f9ccff6ff","src/server.rs":"5dda8eb6304be58b8b033b8a6e8f3da75d0b638c2a59c99b4e2b562cc9223137","src/server_connection_events.rs":"762ddb87f700abe91ae1ae78ebbb87a88da0c0a341748b0751b01099870e9985","src/server_events.rs":"c8cdd838129ef6b1e77ba63608d20f6d297bca4e67f26a077d1c015a5e2a3b82","src/settings.rs":"127a51fa7857b870718baa14340b0461d86a67e59bf1a8cb42d7bae0240c0ef1","src/stream_type_reader.rs":"aacb2e865f79b3ac55a887fd670f2286d8ffef94f7d8b3ecfa7e0cccbfa9ec04","tests/httpconn.rs":"1a97a80f7abe11c6ba0bd9b41003be6b293049164daa21e907365d93b00a782f"},"package":null}
|
2
third_party/rust/neqo-http3/Cargo.toml
vendored
2
third_party/rust/neqo-http3/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-http3"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
12
third_party/rust/neqo-http3/src/connection.rs
vendored
12
third_party/rust/neqo-http3/src/connection.rs
vendored
@ -54,7 +54,10 @@ pub enum Http3State {
|
||||
impl Http3State {
|
||||
#[must_use]
|
||||
pub fn active(&self) -> bool {
|
||||
matches!(self, Http3State::Connected | Http3State::GoingAway(_) | Http3State::ZeroRtt)
|
||||
matches!(
|
||||
self,
|
||||
Http3State::Connected | Http3State::GoingAway(_) | Http3State::ZeroRtt
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,7 +401,7 @@ impl Http3Connection {
|
||||
Ok(true)
|
||||
}
|
||||
State::Closing { error, .. } | State::Draining { error, .. } => {
|
||||
if matches!(self.state, Http3State::Closing(_)| Http3State::Closed(_)) {
|
||||
if matches!(self.state, Http3State::Closing(_) | Http3State::Closed(_)) {
|
||||
Ok(false)
|
||||
} else {
|
||||
self.state = Http3State::Closing(error.clone());
|
||||
@ -569,7 +572,10 @@ impl Http3Connection {
|
||||
fn handle_control_frame(&mut self, f: HFrame) -> Res<Option<HFrame>> {
|
||||
qinfo!([self], "Handle a control frame {:?}", f);
|
||||
if !matches!(f, HFrame::Settings { .. })
|
||||
&& !matches!(self.settings_state, Http3RemoteSettingsState::Received{..})
|
||||
&& !matches!(
|
||||
self.settings_state,
|
||||
Http3RemoteSettingsState::Received { .. }
|
||||
)
|
||||
{
|
||||
return Err(Error::HttpMissingSettings);
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ where
|
||||
|
||||
fn alpn_from_quic_version(version: QuicVersion) -> &'static str {
|
||||
match version {
|
||||
QuicVersion::Version1 => "h3",
|
||||
QuicVersion::Draft27 => "h3-27",
|
||||
QuicVersion::Draft28 => "h3-28",
|
||||
QuicVersion::Draft29 => "h3-29",
|
||||
@ -97,6 +98,7 @@ impl Http3Client {
|
||||
remote_addr: SocketAddr,
|
||||
conn_params: ConnectionParameters,
|
||||
http3_parameters: &Http3Parameters,
|
||||
now: Instant,
|
||||
) -> Res<Self> {
|
||||
Ok(Self::new_with_conn(
|
||||
Connection::new_client(
|
||||
@ -106,6 +108,7 @@ impl Http3Client {
|
||||
local_addr,
|
||||
remote_addr,
|
||||
conn_params,
|
||||
now,
|
||||
)?,
|
||||
http3_parameters,
|
||||
))
|
||||
@ -223,7 +226,10 @@ impl Http3Client {
|
||||
S: AsRef<str> + Display,
|
||||
{
|
||||
qinfo!([self], "Close the connection error={} msg={}.", error, msg);
|
||||
if !matches!(self.base_handler.state, Http3State::Closing(_)| Http3State::Closed(_)) {
|
||||
if !matches!(
|
||||
self.base_handler.state,
|
||||
Http3State::Closing(_) | Http3State::Closed(_)
|
||||
) {
|
||||
self.push_handler.borrow_mut().clear();
|
||||
self.conn.close(now, error, msg);
|
||||
self.base_handler.close(error);
|
||||
@ -783,6 +789,7 @@ mod tests {
|
||||
},
|
||||
max_concurrent_push_streams: 5,
|
||||
},
|
||||
now(),
|
||||
)
|
||||
.expect("create a default client")
|
||||
}
|
||||
@ -4464,28 +4471,21 @@ mod tests {
|
||||
let any_push_event = |e| {
|
||||
matches!(
|
||||
e,
|
||||
Http3ClientEvent::PushPromise{..}
|
||||
| Http3ClientEvent::PushHeaderReady{..}
|
||||
| Http3ClientEvent::PushDataReadable{..})
|
||||
Http3ClientEvent::PushPromise { .. }
|
||||
| Http3ClientEvent::PushHeaderReady { .. }
|
||||
| Http3ClientEvent::PushDataReadable { .. }
|
||||
)
|
||||
};
|
||||
client.events().any(any_push_event)
|
||||
}
|
||||
|
||||
fn check_data_readable(client: &mut Http3Client) -> bool {
|
||||
let any_data_event = |e| {
|
||||
matches!(
|
||||
e,
|
||||
Http3ClientEvent::DataReadable{..})
|
||||
};
|
||||
let any_data_event = |e| matches!(e, Http3ClientEvent::DataReadable { .. });
|
||||
client.events().any(any_data_event)
|
||||
}
|
||||
|
||||
fn check_header_ready(client: &mut Http3Client) -> bool {
|
||||
let any_event = |e| {
|
||||
matches!(
|
||||
e,
|
||||
Http3ClientEvent::HeaderReady{..})
|
||||
};
|
||||
let any_event = |e| matches!(e, Http3ClientEvent::HeaderReady { .. });
|
||||
client.events().any(any_event)
|
||||
}
|
||||
|
||||
@ -4493,8 +4493,8 @@ mod tests {
|
||||
let any_event = |e| {
|
||||
matches!(
|
||||
e,
|
||||
Http3ClientEvent::HeaderReady{..}
|
||||
| Http3ClientEvent::PushPromise{..})
|
||||
Http3ClientEvent::HeaderReady { .. } | Http3ClientEvent::PushPromise { .. }
|
||||
)
|
||||
};
|
||||
client.events().any(any_event)
|
||||
}
|
||||
@ -4740,7 +4740,7 @@ mod tests {
|
||||
send_push_promise_and_exchange_packets(&mut client, &mut server, request_stream_id_2, 5);
|
||||
|
||||
// Check that we do not have a Http3ClientEvent::PushPromise.
|
||||
let push_event = |e| matches!(e, Http3ClientEvent::PushPromise{ .. });
|
||||
let push_event = |e| matches!(e, Http3ClientEvent::PushPromise { .. });
|
||||
assert!(!client.events().any(push_event));
|
||||
}
|
||||
|
||||
|
14
third_party/rust/neqo-http3/src/hframe.rs
vendored
14
third_party/rust/neqo-http3/src/hframe.rs
vendored
@ -214,9 +214,8 @@ impl HFrameReader {
|
||||
if fin {
|
||||
if self.decoding_in_progress() {
|
||||
break Err(Error::HttpFrame);
|
||||
} else {
|
||||
break Ok((None, fin));
|
||||
}
|
||||
break Ok((None, fin));
|
||||
}
|
||||
|
||||
if !read {
|
||||
@ -266,12 +265,11 @@ impl HFrameReader {
|
||||
| H3_FRAME_TYPE_HEADERS => {
|
||||
if len == 0 {
|
||||
return Ok(Some(self.get_frame()?));
|
||||
} else {
|
||||
HFrameReaderState::GetData {
|
||||
decoder: IncrementalDecoderBuffer::new(
|
||||
usize::try_from(len).or(Err(Error::HttpFrame))?,
|
||||
),
|
||||
}
|
||||
}
|
||||
HFrameReaderState::GetData {
|
||||
decoder: IncrementalDecoderBuffer::new(
|
||||
usize::try_from(len).or(Err(Error::HttpFrame))?,
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -322,7 +322,7 @@ impl PushController {
|
||||
pub fn close(&mut self, push_id: u64) {
|
||||
qtrace!("Push stream has been closed.");
|
||||
if let Some(push_state) = self.push_streams.close(push_id) {
|
||||
debug_assert!(matches!(push_state, PushState::Active{..}));
|
||||
debug_assert!(matches!(push_state, PushState::Active { .. }));
|
||||
} else {
|
||||
debug_assert!(false, "Closing non existing push stream!");
|
||||
}
|
||||
|
@ -106,9 +106,8 @@ impl RecvMessage {
|
||||
RecvMessageState::WaitingForResponseHeaders {..} => {
|
||||
if header_block.is_empty() {
|
||||
return Err(Error::HttpGeneralProtocolStream);
|
||||
} else {
|
||||
self.state = RecvMessageState::DecodingHeaders { header_block, fin };
|
||||
}
|
||||
self.state = RecvMessageState::DecodingHeaders { header_block, fin };
|
||||
}
|
||||
RecvMessageState::WaitingForData { ..} => {
|
||||
// TODO implement trailers, for now just ignore them.
|
||||
@ -268,7 +267,9 @@ impl RecvMessage {
|
||||
if matches!(self.state, RecvMessageState::Closed) {
|
||||
break Ok(());
|
||||
}
|
||||
if fin && !matches!(self.state, RecvMessageState::DecodingHeaders{..}) {
|
||||
if fin
|
||||
&& !matches!(self.state, RecvMessageState::DecodingHeaders { .. })
|
||||
{
|
||||
break self.set_state_to_close_pending(post_readable_event);
|
||||
}
|
||||
}
|
||||
@ -334,7 +335,7 @@ impl RecvMessage {
|
||||
if let Some((_name, value)) = status {
|
||||
#[allow(clippy::map_err_ignore, clippy::unknown_clippy_lints)]
|
||||
let status_code = value.parse::<i32>().map_err(|_| Error::InvalidHeader)?;
|
||||
Ok(status_code >= 100 && status_code < 200)
|
||||
Ok((100..200).contains(&status_code))
|
||||
} else {
|
||||
Err(Error::InvalidHeader)
|
||||
}
|
||||
|
@ -271,7 +271,10 @@ impl SendMessage {
|
||||
// This method returns if they're still being sent. Request body (if any) is sent by
|
||||
// http client afterwards using `send_request_body` after receiving DataWritable event.
|
||||
pub fn has_data_to_send(&self) -> bool {
|
||||
matches!(self.state, SendMessageState::Initialized {..} | SendMessageState::SendingInitialMessage { .. } )
|
||||
matches!(
|
||||
self.state,
|
||||
SendMessageState::Initialized { .. } | SendMessageState::SendingInitialMessage { .. }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn close(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
|
20
third_party/rust/neqo-http3/src/server.rs
vendored
20
third_party/rust/neqo-http3/src/server.rs
vendored
@ -283,15 +283,27 @@ mod tests {
|
||||
}
|
||||
|
||||
fn assert_connected(hconn: &mut Http3Server) {
|
||||
let connected =
|
||||
|e| matches!(e, Http3ServerEvent::StateChange{ state: Http3State::Connected, ..} );
|
||||
let connected = |e| {
|
||||
matches!(
|
||||
e,
|
||||
Http3ServerEvent::StateChange {
|
||||
state: Http3State::Connected,
|
||||
..
|
||||
}
|
||||
)
|
||||
};
|
||||
assert!(hconn.events().any(connected));
|
||||
}
|
||||
|
||||
fn assert_not_closed(hconn: &mut Http3Server) {
|
||||
let closed = |e| {
|
||||
matches!(e,
|
||||
Http3ServerEvent::StateChange{ state: Http3State::Closing(..), .. })
|
||||
matches!(
|
||||
e,
|
||||
Http3ServerEvent::StateChange {
|
||||
state: Http3State::Closing(..),
|
||||
..
|
||||
}
|
||||
)
|
||||
};
|
||||
assert!(!hconn.events().any(closed));
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"5d4988576ac89bab7c1d2b1e521e67ce5062a68b395d553df64eeaee78ea9b29","src/decoder.rs":"1dd87823a8aeb8673d2521d2f2735cea5aaf45713a4fdc3a01b3803c7a7c30f7","src/decoder_instructions.rs":"a8e04dff5fc4c658322a10daadab947dc2e41932c00c3f8d387671a86d0516af","src/encoder.rs":"30442c457d7fb8a63bc54bd68928383adb9fdeda14d6b082c2035736389d96c5","src/encoder_instructions.rs":"1d4424bf21c0ac26b7c8fee6450b943346c5493ab86dd7ec2edc5f566454721e","src/header_block.rs":"8477281843fb9c927cbf9cda488d4586605a64157e582a71e405f2bf1852f43b","src/huffman.rs":"68fa0bada0c35d20f793980596accdcc548970214841f71789290fc334e51fc1","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"bc9d936fe126d53ff752ae7fe17e8be59bb992f48b17e82d5811f274b492af3c","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"5170b93afaf0c1609463e6c5ae4dccb1a2ce4e4407296db1bcaf06c6b5bb97ab","src/reader.rs":"4bcea0de1d7dc09ec0cdff364d8f62da54bbbe1f6db55a495f943f31369b4074","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}
|
||||
{"files":{"Cargo.toml":"063b51b1dcd6e1cfac0226a05f20a5a55826c5b5fab90483b9516048d91f40f8","src/decoder.rs":"3a069d7d224a51e19690c024ccb66c3059151dbac22a0c909b195d712b307dfc","src/decoder_instructions.rs":"a8e04dff5fc4c658322a10daadab947dc2e41932c00c3f8d387671a86d0516af","src/encoder.rs":"208ff94030866c07151be2695da4e01269783ed979830112bf15502063486534","src/encoder_instructions.rs":"1d4424bf21c0ac26b7c8fee6450b943346c5493ab86dd7ec2edc5f566454721e","src/header_block.rs":"8bf9c4890dfa07c6a2f23fb1dda9446ec9c15838dd44dc133c31800f970d1d8d","src/huffman.rs":"68fa0bada0c35d20f793980596accdcc548970214841f71789290fc334e51fc1","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"bc9d936fe126d53ff752ae7fe17e8be59bb992f48b17e82d5811f274b492af3c","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"5170b93afaf0c1609463e6c5ae4dccb1a2ce4e4407296db1bcaf06c6b5bb97ab","src/reader.rs":"8d006058e08efdd4a4b3d8c40da379e9b637aa337077bf2b74ea0a8a57c23c72","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}
|
2
third_party/rust/neqo-qpack/Cargo.toml
vendored
2
third_party/rust/neqo-qpack/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-qpack"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
4
third_party/rust/neqo-qpack/src/decoder.rs
vendored
4
third_party/rust/neqo-qpack/src/decoder.rs
vendored
@ -160,7 +160,7 @@ impl QPackDecoder {
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// May return an error in case of any transport error. TODO: define transport errors.
|
||||
/// May return an error in case of any transport error. TODO: define transport errors.
|
||||
#[allow(clippy::map_err_ignore, clippy::unknown_clippy_lints)]
|
||||
pub fn send(&mut self, conn: &mut Connection) -> Res<()> {
|
||||
// Encode increment instruction if needed.
|
||||
@ -239,7 +239,7 @@ impl QPackDecoder {
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// May return WrongStreamCount if Http3 has received multiple encoder streams.
|
||||
/// May return `WrongStreamCount` if HTTP/3 has received multiple encoder streams.
|
||||
pub fn add_recv_stream(&mut self, stream_id: u64) -> Res<()> {
|
||||
if self.remote_stream_id.is_some() {
|
||||
Err(Error::WrongStreamCount)
|
||||
|
85
third_party/rust/neqo-qpack/src/encoder.rs
vendored
85
third_party/rust/neqo-qpack/src/encoder.rs
vendored
@ -164,7 +164,7 @@ impl QPackEncoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn header_ack(&mut self, stream_id: u64) -> Res<()> {
|
||||
fn header_ack(&mut self, stream_id: u64) {
|
||||
self.stats.header_acks_recv += 1;
|
||||
let mut new_acked = self.table.get_acked_inserts_cnt();
|
||||
if let Some(hb_list) = self.unacked_header_blocks.get_mut(&stream_id) {
|
||||
@ -186,10 +186,9 @@ impl QPackEncoder {
|
||||
self.insert_count_instruction(new_acked - self.table.get_acked_inserts_cnt())
|
||||
.expect("This should neve happen");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stream_cancellation(&mut self, stream_id: u64) -> Res<()> {
|
||||
fn stream_cancellation(&mut self, stream_id: u64) {
|
||||
self.stats.stream_cancelled_recv += 1;
|
||||
let mut was_blocker = false;
|
||||
if let Some(mut hb_list) = self.unacked_header_blocks.remove(&stream_id) {
|
||||
@ -205,7 +204,6 @@ impl QPackEncoder {
|
||||
debug_assert!(self.blocked_stream_cnt > 0);
|
||||
self.blocked_stream_cnt -= 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call_instruction(
|
||||
@ -224,9 +222,13 @@ impl QPackEncoder {
|
||||
|
||||
self.insert_count_instruction(increment)
|
||||
}
|
||||
DecoderInstruction::HeaderAck { stream_id } => self.header_ack(stream_id),
|
||||
DecoderInstruction::HeaderAck { stream_id } => {
|
||||
self.header_ack(stream_id);
|
||||
Ok(())
|
||||
}
|
||||
DecoderInstruction::StreamCancellation { stream_id } => {
|
||||
self.stream_cancellation(stream_id)
|
||||
self.stream_cancellation(stream_id);
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
@ -529,9 +531,8 @@ fn map_stream_send_atomic_error(err: &TransportError) -> Error {
|
||||
mod tests {
|
||||
use super::{Connection, Error, Header, QPackEncoder, Res};
|
||||
use crate::QpackSettings;
|
||||
use neqo_transport::tparams::{self, TransportParameter};
|
||||
use neqo_transport::StreamType;
|
||||
use test_fixture::{default_client, default_server, handshake, now};
|
||||
use neqo_transport::{ConnectionParameters, StreamType};
|
||||
use test_fixture::{configure_server, default_client, default_server, handshake, now};
|
||||
|
||||
struct TestEncoder {
|
||||
encoder: QPackEncoder,
|
||||
@ -584,13 +585,17 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn connect_generic<F>(huffman: bool, f: F) -> TestEncoder
|
||||
where
|
||||
F: FnOnce(&mut Connection, &mut Connection),
|
||||
{
|
||||
fn connect_generic(huffman: bool, max_data: Option<u64>) -> TestEncoder {
|
||||
let mut conn = default_client();
|
||||
let mut peer_conn = default_server();
|
||||
f(&mut conn, &mut peer_conn);
|
||||
let mut peer_conn = max_data.map_or_else(default_server, |max| {
|
||||
configure_server(
|
||||
ConnectionParameters::default()
|
||||
.max_stream_data(StreamType::UniDi, true, max)
|
||||
.max_stream_data(StreamType::BiDi, true, max)
|
||||
.max_stream_data(StreamType::BiDi, false, max),
|
||||
)
|
||||
});
|
||||
handshake(&mut conn, &mut peer_conn);
|
||||
|
||||
// create a stream
|
||||
let recv_stream_id = peer_conn.stream_create(StreamType::UniDi).unwrap();
|
||||
@ -617,22 +622,11 @@ mod tests {
|
||||
}
|
||||
|
||||
fn connect(huffman: bool) -> TestEncoder {
|
||||
connect_generic(huffman, |client, server| {
|
||||
handshake(client, server);
|
||||
})
|
||||
connect_generic(huffman, None)
|
||||
}
|
||||
|
||||
fn connect_flow_control(max_data: u64) -> TestEncoder {
|
||||
connect_generic(true, |client, server| {
|
||||
server
|
||||
.set_local_tparam(
|
||||
tparams::INITIAL_MAX_DATA,
|
||||
TransportParameter::Integer(max_data),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
handshake(client, server);
|
||||
})
|
||||
connect_generic(true, Some(max_data))
|
||||
}
|
||||
|
||||
fn recv_instruction(encoder: &mut TestEncoder, decoder_instruction: &[u8]) {
|
||||
@ -1584,17 +1578,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn encoder_flow_controlled_blocked() {
|
||||
const SMALL_MAX_DATA: u64 = 900;
|
||||
const STREAM_DATA_LEN: usize = 900 - 20;
|
||||
const STREAM_DATA: &[u8] = &[0; STREAM_DATA_LEN];
|
||||
const ONE_INSTRUCTION: &[u8] = &[
|
||||
const SMALL_MAX_DATA: u64 = 20;
|
||||
const ONE_INSTRUCTION_1: &[u8] = &[
|
||||
0x67, 0x41, 0xe9, 0x2a, 0x67, 0x35, 0x53, 0x7f, 0x83, 0x8, 0x99, 0x6b,
|
||||
];
|
||||
const TWO_INSTRUCTION: &[u8] = &[
|
||||
0x67, 0x41, 0xe9, 0x2a, 0x67, 0x35, 0x53, 0x37, 0x83, 0x8, 0x99, 0x6b, 0x67, 0x41,
|
||||
0xe9, 0x2a, 0x67, 0x35, 0x53, 0x39, 0x88, 0x8, 0x99, 0x69, 0xb7, 0x1d, 0x79, 0xf0,
|
||||
0x83,
|
||||
const ONE_INSTRUCTION_2: &[u8] = &[
|
||||
0x67, 0x41, 0xe9, 0x2a, 0x67, 0x35, 0x53, 0x37, 0x83, 0x8, 0x99, 0x6b,
|
||||
];
|
||||
|
||||
let mut encoder = connect_flow_control(SMALL_MAX_DATA);
|
||||
|
||||
// change capacity to 1000 and max_block streams to 20.
|
||||
@ -1602,13 +1593,6 @@ mod tests {
|
||||
assert!(encoder.encoder.set_max_capacity(1000).is_ok());
|
||||
encoder.send_instructions(CAP_INSTRUCTION_1000);
|
||||
|
||||
// Write some data to fill the flow control allowance.
|
||||
let stream_id = encoder.conn.stream_create(StreamType::UniDi).unwrap();
|
||||
assert_eq!(
|
||||
encoder.conn.stream_send(stream_id, STREAM_DATA).unwrap(),
|
||||
STREAM_DATA_LEN
|
||||
);
|
||||
|
||||
// Encode a header block with 2 headers. The first header will be added to the dynamic table.
|
||||
// The second will not be added to the dynamic table, because the corresponding instruction
|
||||
// cannot be written immediately due to the flow control limit.
|
||||
@ -1644,7 +1628,11 @@ mod tests {
|
||||
assert_eq!(buf2[2] & 0xf0, 0x20);
|
||||
|
||||
// Ensure that we have sent only one instruction for (String::from("something"), String::from("1234"))
|
||||
encoder.send_instructions(ONE_INSTRUCTION);
|
||||
encoder.send_instructions(ONE_INSTRUCTION_1);
|
||||
|
||||
// exchange a flow control update.
|
||||
let out = encoder.peer_conn.process(None, now());
|
||||
let _ = encoder.conn.process(out.dgram(), now());
|
||||
|
||||
// Try writing a new header block. Now, headers will be added to the dynamic table again, because
|
||||
// instructions can be sent.
|
||||
@ -1659,12 +1647,13 @@ mod tests {
|
||||
3,
|
||||
)
|
||||
.unwrap();
|
||||
// Assert that both headers are encoded as an index to the dynamic table (a post form).
|
||||
// Assert that the first header is encoded as an index to the dynamic table (a post form).
|
||||
assert_eq!(buf3[2], 0x10);
|
||||
assert_eq!(buf3[3], 0x11);
|
||||
// Assert that the second header is encoded as a literal with a name literal
|
||||
assert_eq!(buf3[3] & 0xf0, 0x20);
|
||||
|
||||
// Asset that 2 instruction has been sent
|
||||
encoder.send_instructions(TWO_INSTRUCTION);
|
||||
// Asset that one instruction has been sent
|
||||
encoder.send_instructions(ONE_INSTRUCTION_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -316,9 +316,8 @@ impl<'a> HeaderDecoder<'a> {
|
||||
if req_insert_cnt > max_value {
|
||||
if req_insert_cnt < full_range {
|
||||
return Err(Error::DecompressionFailed);
|
||||
} else {
|
||||
req_insert_cnt -= full_range;
|
||||
}
|
||||
req_insert_cnt -= full_range;
|
||||
}
|
||||
Ok(req_insert_cnt)
|
||||
}
|
||||
|
6
third_party/rust/neqo-qpack/src/reader.rs
vendored
6
third_party/rust/neqo-qpack/src/reader.rs
vendored
@ -290,12 +290,10 @@ impl LiteralReader {
|
||||
self.state = LiteralReaderState::Done;
|
||||
if self.use_huffman {
|
||||
break Ok(decode_huffman(&self.literal)?);
|
||||
} else {
|
||||
break Ok(mem::replace(&mut self.literal, Vec::new()));
|
||||
}
|
||||
} else {
|
||||
break Err(Error::NeedMoreData);
|
||||
break Ok(mem::replace(&mut self.literal, Vec::new()));
|
||||
}
|
||||
break Err(Error::NeedMoreData);
|
||||
}
|
||||
LiteralReaderState::Done => {
|
||||
panic!("Should not call read() in this state.");
|
||||
|
File diff suppressed because one or more lines are too long
2
third_party/rust/neqo-transport/Cargo.toml
vendored
2
third_party/rust/neqo-transport/Cargo.toml
vendored
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neqo-transport"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
authors = ["EKR <ekr@rtfm.com>", "Andy Grover <agrover@mozilla.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
@ -246,7 +246,7 @@ impl<T: WindowAdjustment> CongestionControl for ClassicCongestionControl<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
for pkt in lost_packets.iter().filter(|pkt| pkt.ack_eliciting()) {
|
||||
for pkt in lost_packets.iter().filter(|pkt| pkt.cc_in_flight()) {
|
||||
assert!(self.bytes_in_flight >= pkt.size);
|
||||
self.bytes_in_flight -= pkt.size;
|
||||
}
|
||||
@ -278,6 +278,14 @@ impl<T: WindowAdjustment> CongestionControl for ClassicCongestionControl<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn discard_in_flight(&mut self) {
|
||||
self.bytes_in_flight = 0;
|
||||
qlog::metrics_updated(
|
||||
&mut self.qlog,
|
||||
&[QlogMetric::BytesInFlight(self.bytes_in_flight)],
|
||||
);
|
||||
}
|
||||
|
||||
fn on_packet_sent(&mut self, pkt: &SentPacket) {
|
||||
// Record the recovery time and exit any transient state.
|
||||
if self.state.transient() {
|
||||
@ -285,7 +293,7 @@ impl<T: WindowAdjustment> CongestionControl for ClassicCongestionControl<T> {
|
||||
self.state.update();
|
||||
}
|
||||
|
||||
if !pkt.ack_eliciting() {
|
||||
if !pkt.cc_in_flight() {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -304,7 +312,6 @@ impl<T: WindowAdjustment> CongestionControl for ClassicCongestionControl<T> {
|
||||
}
|
||||
|
||||
/// Whether a packet can be sent immediately as a result of entering recovery.
|
||||
#[must_use]
|
||||
fn recovery_packet(&self) -> bool {
|
||||
self.state == State::RecoveryStart
|
||||
}
|
||||
@ -399,7 +406,7 @@ impl<T: WindowAdjustment> ClassicCongestionControl<T> {
|
||||
start = None;
|
||||
}
|
||||
last_pn = p.pn;
|
||||
if !p.ack_eliciting() {
|
||||
if !p.cc_in_flight() {
|
||||
// Not interesting, keep looking.
|
||||
continue;
|
||||
}
|
||||
@ -482,10 +489,11 @@ mod tests {
|
||||
};
|
||||
use crate::cc::cubic::{Cubic, CUBIC_BETA_USIZE_DIVISOR, CUBIC_BETA_USIZE_QUOTIENT};
|
||||
use crate::cc::new_reno::NewReno;
|
||||
use crate::cc::{CongestionControl, CWND_INITIAL_PKTS, MAX_DATAGRAM_SIZE};
|
||||
use crate::cc::{
|
||||
CongestionControl, CongestionControlAlgorithm, CWND_INITIAL_PKTS, MAX_DATAGRAM_SIZE,
|
||||
};
|
||||
use crate::packet::{PacketNumber, PacketType};
|
||||
use crate::tracking::SentPacket;
|
||||
use crate::CongestionControlAlgorithm;
|
||||
use std::convert::TryFrom;
|
||||
use std::time::{Duration, Instant};
|
||||
use test_fixture::now;
|
||||
|
21
third_party/rust/neqo-transport/src/cc/mod.rs
vendored
21
third_party/rust/neqo-transport/src/cc/mod.rs
vendored
@ -9,9 +9,11 @@
|
||||
|
||||
use crate::path::PATH_MTU_V6;
|
||||
use crate::tracking::SentPacket;
|
||||
use crate::Error;
|
||||
use neqo_common::qlog::NeqoQlog;
|
||||
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::str::FromStr;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
mod classic_cc;
|
||||
@ -29,10 +31,13 @@ pub const MAX_DATAGRAM_SIZE_F64: f64 = 1337.0;
|
||||
pub trait CongestionControl: Display + Debug {
|
||||
fn set_qlog(&mut self, qlog: NeqoQlog);
|
||||
|
||||
#[must_use]
|
||||
fn cwnd(&self) -> usize;
|
||||
|
||||
#[must_use]
|
||||
fn bytes_in_flight(&self) -> usize;
|
||||
|
||||
#[must_use]
|
||||
fn cwnd_avail(&self) -> usize;
|
||||
|
||||
fn on_packets_acked(&mut self, acked_pkts: &[SentPacket], min_rtt: Duration, now: Instant);
|
||||
@ -45,11 +50,14 @@ pub trait CongestionControl: Display + Debug {
|
||||
lost_packets: &[SentPacket],
|
||||
);
|
||||
|
||||
#[must_use]
|
||||
fn recovery_packet(&self) -> bool;
|
||||
|
||||
fn discard(&mut self, pkt: &SentPacket);
|
||||
|
||||
fn on_packet_sent(&mut self, pkt: &SentPacket);
|
||||
|
||||
fn discard_in_flight(&mut self);
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@ -58,5 +66,18 @@ pub enum CongestionControlAlgorithm {
|
||||
Cubic,
|
||||
}
|
||||
|
||||
// A `FromStr` implementation so that this can be used in command-line interfaces.
|
||||
impl FromStr for CongestionControlAlgorithm {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.trim().to_ascii_lowercase().as_str() {
|
||||
"newreno" | "reno" => Ok(Self::NewReno),
|
||||
"cubic" => Ok(Self::Cubic),
|
||||
_ => Err(Error::InvalidInput),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::connection::{ConnectionIdManager, Role, LOCAL_ACTIVE_CID_LIMIT, LOCAL_IDLE_TIMEOUT};
|
||||
use crate::recv_stream::RECV_BUFFER_SIZE;
|
||||
use crate::stream_id::{StreamIndex, StreamType};
|
||||
use crate::tparams::PreferredAddress;
|
||||
use crate::{CongestionControlAlgorithm, QuicVersion};
|
||||
use crate::tparams::{self, PreferredAddress, TransportParameter, TransportParametersHandler};
|
||||
use crate::{CongestionControlAlgorithm, QuicVersion, Res};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
const LOCAL_MAX_DATA: u64 = 0x3FFF_FFFF_FFFF_FFFF; // 2^62-1
|
||||
const LOCAL_STREAM_LIMIT_BIDI: StreamIndex = StreamIndex::new(16);
|
||||
const LOCAL_STREAM_LIMIT_UNI: StreamIndex = StreamIndex::new(16);
|
||||
|
||||
@ -23,12 +27,23 @@ pub enum PreferredAddressConfig {
|
||||
}
|
||||
|
||||
/// ConnectionParameters use for setting intitial value for QUIC parameters.
|
||||
/// This collect like initial limits, protocol version and congestion control.
|
||||
/// This collects configuration like initial limits, protocol version, and
|
||||
/// congestion control algorithm.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConnectionParameters {
|
||||
quic_version: QuicVersion,
|
||||
cc_algorithm: CongestionControlAlgorithm,
|
||||
/// Initial connection-level flow control limit.
|
||||
max_data: u64,
|
||||
/// Initial flow control limit for receiving data on bidirectional streams that the peer creates.
|
||||
max_stream_data_bidi_remote: u64,
|
||||
/// Initial flow control limit for receiving data on bidirectional streams that this endpoint creates.
|
||||
max_stream_data_bidi_local: u64,
|
||||
/// Initial flow control limit for receiving data on unidirectional streams that the peer creates.
|
||||
max_stream_data_uni: u64,
|
||||
/// Initial limit on bidirectional streams that the peer creates.
|
||||
max_streams_bidi: StreamIndex,
|
||||
/// Initial limit on unidirectional streams that this endpoint creates.
|
||||
max_streams_uni: StreamIndex,
|
||||
preferred_address: PreferredAddressConfig,
|
||||
}
|
||||
@ -38,6 +53,10 @@ impl Default for ConnectionParameters {
|
||||
Self {
|
||||
quic_version: QuicVersion::default(),
|
||||
cc_algorithm: CongestionControlAlgorithm::NewReno,
|
||||
max_data: LOCAL_MAX_DATA,
|
||||
max_stream_data_bidi_remote: u64::try_from(RECV_BUFFER_SIZE).unwrap(),
|
||||
max_stream_data_bidi_local: u64::try_from(RECV_BUFFER_SIZE).unwrap(),
|
||||
max_stream_data_uni: u64::try_from(RECV_BUFFER_SIZE).unwrap(),
|
||||
max_streams_bidi: LOCAL_STREAM_LIMIT_BIDI,
|
||||
max_streams_uni: LOCAL_STREAM_LIMIT_UNI,
|
||||
preferred_address: PreferredAddressConfig::Default,
|
||||
@ -64,6 +83,15 @@ impl ConnectionParameters {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_max_data(&self) -> u64 {
|
||||
self.max_data
|
||||
}
|
||||
|
||||
pub fn max_data(mut self, v: u64) -> Self {
|
||||
self.max_data = v;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_max_streams(&self, stream_type: StreamType) -> StreamIndex {
|
||||
match stream_type {
|
||||
StreamType::BiDi => self.max_streams_bidi,
|
||||
@ -84,6 +112,39 @@ impl ConnectionParameters {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the maximum stream data that we will accept on different types of streams.
|
||||
/// Asserts if `StreamType::UniDi` and `false` are passed as that is not a valid combination.
|
||||
pub fn get_max_stream_data(&self, stream_type: StreamType, remote: bool) -> u64 {
|
||||
match (stream_type, remote) {
|
||||
(StreamType::BiDi, false) => self.max_stream_data_bidi_local,
|
||||
(StreamType::BiDi, true) => self.max_stream_data_bidi_remote,
|
||||
(StreamType::UniDi, false) => {
|
||||
panic!("Can't get receive limit on a stream that can only be sent.")
|
||||
}
|
||||
(StreamType::UniDi, true) => self.max_stream_data_uni,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the maximum stream data that we will accept on different types of streams.
|
||||
/// Asserts if `StreamType::UniDi` and `false` are passed as that is not a valid combination.
|
||||
pub fn max_stream_data(mut self, stream_type: StreamType, remote: bool, v: u64) -> Self {
|
||||
match (stream_type, remote) {
|
||||
(StreamType::BiDi, false) => {
|
||||
self.max_stream_data_bidi_local = v;
|
||||
}
|
||||
(StreamType::BiDi, true) => {
|
||||
self.max_stream_data_bidi_remote = v;
|
||||
}
|
||||
(StreamType::UniDi, false) => {
|
||||
panic!("Can't set receive limit on a stream that can only be sent.")
|
||||
}
|
||||
(StreamType::UniDi, true) => {
|
||||
self.max_stream_data_uni = v;
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a preferred address (which only has an effect for a server).
|
||||
pub fn preferred_address(mut self, preferred: PreferredAddress) -> Self {
|
||||
self.preferred_address = PreferredAddressConfig::Address(preferred);
|
||||
@ -99,4 +160,62 @@ impl ConnectionParameters {
|
||||
pub fn get_preferred_address(&self) -> &PreferredAddressConfig {
|
||||
&self.preferred_address
|
||||
}
|
||||
|
||||
pub fn create_transport_parameter(
|
||||
&self,
|
||||
role: Role,
|
||||
cid_manager: &mut ConnectionIdManager,
|
||||
) -> Res<TransportParametersHandler> {
|
||||
let mut tps = TransportParametersHandler::default();
|
||||
// default parameters
|
||||
tps.local.set_integer(
|
||||
tparams::IDLE_TIMEOUT,
|
||||
u64::try_from(LOCAL_IDLE_TIMEOUT.as_millis()).unwrap(),
|
||||
);
|
||||
tps.local.set_integer(
|
||||
tparams::ACTIVE_CONNECTION_ID_LIMIT,
|
||||
u64::try_from(LOCAL_ACTIVE_CID_LIMIT).unwrap(),
|
||||
);
|
||||
tps.local.set_empty(tparams::DISABLE_MIGRATION);
|
||||
tps.local.set_empty(tparams::GREASE_QUIC_BIT);
|
||||
|
||||
// set configurable parameters
|
||||
tps.local
|
||||
.set_integer(tparams::INITIAL_MAX_DATA, self.max_data);
|
||||
tps.local.set_integer(
|
||||
tparams::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
|
||||
self.max_stream_data_bidi_local,
|
||||
);
|
||||
tps.local.set_integer(
|
||||
tparams::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
|
||||
self.max_stream_data_bidi_remote,
|
||||
);
|
||||
tps.local.set_integer(
|
||||
tparams::INITIAL_MAX_STREAM_DATA_UNI,
|
||||
self.max_stream_data_uni,
|
||||
);
|
||||
tps.local.set_integer(
|
||||
tparams::INITIAL_MAX_STREAMS_BIDI,
|
||||
self.max_streams_bidi.as_u64(),
|
||||
);
|
||||
tps.local.set_integer(
|
||||
tparams::INITIAL_MAX_STREAMS_UNI,
|
||||
self.max_streams_uni.as_u64(),
|
||||
);
|
||||
if let PreferredAddressConfig::Address(preferred) = &self.preferred_address {
|
||||
if role == Role::Server {
|
||||
let (cid, srt) = cid_manager.preferred_address_cid()?;
|
||||
tps.local.set(
|
||||
tparams::PREFERRED_ADDRESS,
|
||||
TransportParameter::PreferredAddress {
|
||||
v4: preferred.ipv4(),
|
||||
v6: preferred.ipv6(),
|
||||
cid,
|
||||
srt,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(tps)
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,10 @@ impl State {
|
||||
|
||||
#[must_use]
|
||||
pub fn closed(&self) -> bool {
|
||||
matches!(self, Self::Closing { .. } | Self::Draining { .. } | Self::Closed(_))
|
||||
matches!(
|
||||
self,
|
||||
Self::Closing { .. } | Self::Draining { .. } | Self::Closed(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,17 @@ use crate::tracking::MAX_UNACKED_PKTS;
|
||||
|
||||
use neqo_common::{qdebug, qinfo, qtrace, Datagram};
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
// Get the current congestion window for the connection.
|
||||
fn cwnd(c: &Connection) -> usize {
|
||||
c.paths.primary().borrow().sender().cwnd()
|
||||
}
|
||||
fn cwnd_avail(c: &Connection) -> usize {
|
||||
c.paths.primary().borrow().sender().cwnd_avail()
|
||||
}
|
||||
|
||||
fn induce_persistent_congestion(
|
||||
client: &mut Connection,
|
||||
server: &mut Connection,
|
||||
@ -69,7 +78,7 @@ fn induce_persistent_congestion(
|
||||
client.process_input(dgram, now);
|
||||
}
|
||||
|
||||
assert_eq!(client.loss_recovery.cwnd(), CWND_MIN);
|
||||
assert_eq!(cwnd(client), CWND_MIN);
|
||||
now
|
||||
}
|
||||
|
||||
@ -115,7 +124,7 @@ fn cc_slow_start() {
|
||||
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||
let (c_tx_dgrams, _) = fill_cwnd(&mut client, stream_id, now);
|
||||
assert_full_cwnd(&c_tx_dgrams, POST_HANDSHAKE_CWND);
|
||||
assert!(client.loss_recovery.cwnd_avail() < ACK_ONLY_SIZE_LIMIT);
|
||||
assert!(cwnd_avail(&client) < ACK_ONLY_SIZE_LIMIT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -206,7 +215,7 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
|
||||
client.process_input(dgram, now);
|
||||
}
|
||||
|
||||
let cwnd1 = client.loss_recovery.cwnd();
|
||||
let cwnd1 = cwnd(&client);
|
||||
|
||||
// Generate ACK for more received packets
|
||||
let s_tx_dgram = ack_bytes(&mut server, 0, c_tx_dgrams2, now);
|
||||
@ -218,7 +227,7 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
|
||||
|
||||
// cwnd should not have changed since ACKed packets were sent before
|
||||
// recovery period expired
|
||||
let cwnd2 = client.loss_recovery.cwnd();
|
||||
let cwnd2 = cwnd(&client);
|
||||
assert_eq!(cwnd1, cwnd2);
|
||||
}
|
||||
|
||||
@ -239,7 +248,7 @@ fn single_packet_on_recovery() {
|
||||
// Now fill the congestion window.
|
||||
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
|
||||
let (_, now) = fill_cwnd(&mut client, 0, now);
|
||||
assert!(client.loss_recovery.cwnd_avail() < ACK_ONLY_SIZE_LIMIT);
|
||||
assert!(cwnd_avail(&client) < ACK_ONLY_SIZE_LIMIT);
|
||||
|
||||
// Acknowledge just one packet and cause one packet to be declared lost.
|
||||
// The length is the amount of credit the client should have.
|
||||
@ -249,7 +258,7 @@ fn single_packet_on_recovery() {
|
||||
// The client should see the loss and enter recovery.
|
||||
// As there are many outstanding packets, there should be no available cwnd.
|
||||
client.process_input(ack.unwrap(), now);
|
||||
assert_eq!(client.loss_recovery.cwnd_avail(), 0);
|
||||
assert_eq!(cwnd_avail(&client), 0);
|
||||
|
||||
// The client should send one packet, ignoring the cwnd.
|
||||
let dgram = client.process_output(now).dgram();
|
||||
@ -285,15 +294,12 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||
|
||||
// Should be in CARP now.
|
||||
now += DEFAULT_RTT / 2;
|
||||
qinfo!(
|
||||
"moving to congestion avoidance {}",
|
||||
client.loss_recovery.cwnd()
|
||||
);
|
||||
qinfo!("moving to congestion avoidance {}", cwnd(&client));
|
||||
|
||||
// Now make sure that we increase congestion window according to the
|
||||
// accurate byte counting version of congestion avoidance.
|
||||
// Check over several increases to be sure.
|
||||
let mut expected_cwnd = client.loss_recovery.cwnd();
|
||||
let mut expected_cwnd = cwnd(&client);
|
||||
// Fill cwnd.
|
||||
let (mut c_tx_dgrams, next_now) = fill_cwnd(&mut client, 0, now);
|
||||
now = next_now;
|
||||
@ -304,7 +310,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||
qinfo!(
|
||||
"client sending {} bytes into cwnd of {}",
|
||||
c_tx_size,
|
||||
client.loss_recovery.cwnd()
|
||||
cwnd(&client)
|
||||
);
|
||||
assert_eq!(c_tx_size, expected_cwnd);
|
||||
|
||||
@ -318,7 +324,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||
let most = c_tx_dgrams.len() - MAX_UNACKED_PKTS - 1;
|
||||
let s_tx_dgram = ack_bytes(&mut server, 0, c_tx_dgrams.drain(..most), now);
|
||||
for dgram in s_tx_dgram {
|
||||
assert_eq!(client.loss_recovery.cwnd(), expected_cwnd);
|
||||
assert_eq!(cwnd(&client), expected_cwnd);
|
||||
client.process_input(dgram, now);
|
||||
// make sure to fill cwnd again.
|
||||
let (mut new_pkts, next_now) = fill_cwnd(&mut client, 0, now);
|
||||
@ -327,7 +333,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||
}
|
||||
let s_tx_dgram = ack_bytes(&mut server, 0, c_tx_dgrams, now);
|
||||
for dgram in s_tx_dgram {
|
||||
assert_eq!(client.loss_recovery.cwnd(), expected_cwnd);
|
||||
assert_eq!(cwnd(&client), expected_cwnd);
|
||||
client.process_input(dgram, now);
|
||||
// make sure to fill cwnd again.
|
||||
let (mut new_pkts, next_now) = fill_cwnd(&mut client, 0, now);
|
||||
@ -335,7 +341,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||
next_c_tx_dgrams.append(&mut new_pkts);
|
||||
}
|
||||
expected_cwnd += MAX_DATAGRAM_SIZE;
|
||||
assert_eq!(client.loss_recovery.cwnd(), expected_cwnd);
|
||||
assert_eq!(cwnd(&client), expected_cwnd);
|
||||
c_tx_dgrams = next_c_tx_dgrams;
|
||||
}
|
||||
}
|
||||
@ -356,7 +362,7 @@ fn cc_slow_start_to_persistent_congestion_no_acks() {
|
||||
|
||||
// Server: Receive and generate ack
|
||||
now += DEFAULT_RTT / 2;
|
||||
let _ = ack_bytes(&mut server, 0, c_tx_dgrams, now);
|
||||
mem::drop(ack_bytes(&mut server, 0, c_tx_dgrams, now));
|
||||
|
||||
// ACK lost.
|
||||
induce_persistent_congestion(&mut client, &mut server, now);
|
||||
@ -409,7 +415,7 @@ fn cc_persistent_congestion_to_slow_start() {
|
||||
|
||||
// Server: Receive and generate ack
|
||||
now += Duration::from_millis(10);
|
||||
let _ = ack_bytes(&mut server, 0, c_tx_dgrams, now);
|
||||
mem::drop(ack_bytes(&mut server, 0, c_tx_dgrams, now));
|
||||
|
||||
// ACK lost.
|
||||
|
||||
|
@ -15,11 +15,15 @@ use crate::events::ConnectionEvent;
|
||||
use crate::path::PATH_MTU_V6;
|
||||
use crate::server::ValidateAddress;
|
||||
use crate::tparams::TransportParameter;
|
||||
use crate::{ConnectionError, ConnectionParameters, EmptyConnectionIdGenerator, Error, StreamType};
|
||||
use crate::{
|
||||
ConnectionError, ConnectionParameters, EmptyConnectionIdGenerator, Error, QuicVersion,
|
||||
StreamType,
|
||||
};
|
||||
|
||||
use neqo_common::{event::Provider, qdebug, Datagram};
|
||||
use neqo_crypto::{constants::TLS_CHACHA20_POLY1305_SHA256, AuthenticationStatus};
|
||||
use std::cell::RefCell;
|
||||
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
use test_fixture::{self, addr, assertions, fixture_init, now, split_datagram};
|
||||
@ -108,6 +112,7 @@ fn no_alpn() {
|
||||
addr(),
|
||||
addr(),
|
||||
ConnectionParameters::default(),
|
||||
now(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut server = default_server();
|
||||
@ -236,6 +241,7 @@ fn chacha20poly1305() {
|
||||
addr(),
|
||||
addr(),
|
||||
ConnectionParameters::default(),
|
||||
now(),
|
||||
)
|
||||
.expect("create a default client");
|
||||
client.set_ciphers(&[TLS_CHACHA20_POLY1305_SHA256]).unwrap();
|
||||
@ -379,12 +385,12 @@ fn reorder_05rtt_with_0rtt() {
|
||||
maybe_authenticate(&mut client);
|
||||
let c4 = client.process(None, now).dgram();
|
||||
assert_eq!(*client.state(), State::Connected);
|
||||
assert_eq!(client.loss_recovery.rtt(), RTT);
|
||||
assert_eq!(client.paths.rtt(), RTT);
|
||||
|
||||
now += RTT / 2;
|
||||
server.process_input(c4.unwrap(), now);
|
||||
assert_eq!(*server.state(), State::Confirmed);
|
||||
assert_eq!(server.loss_recovery.rtt(), RTT);
|
||||
assert_eq!(server.paths.rtt(), RTT);
|
||||
}
|
||||
|
||||
/// Test that a server that coalesces 0.5 RTT with handshake packets
|
||||
@ -508,12 +514,12 @@ fn reorder_handshake() {
|
||||
now += RTT / 2;
|
||||
let s3 = server.process(c3, now).dgram();
|
||||
assert_eq!(*server.state(), State::Confirmed);
|
||||
assert_eq!(server.loss_recovery.rtt(), RTT);
|
||||
assert_eq!(server.paths.rtt(), RTT);
|
||||
|
||||
now += RTT / 2;
|
||||
client.process_input(s3.unwrap(), now);
|
||||
assert_eq!(*client.state(), State::Confirmed);
|
||||
assert_eq!(client.loss_recovery.rtt(), RTT);
|
||||
assert_eq!(client.paths.rtt(), RTT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -558,11 +564,11 @@ fn reorder_1rtt() {
|
||||
assert_eq!(server.stats().saved_datagrams, PACKETS);
|
||||
assert_eq!(server.stats().dropped_rx, 1);
|
||||
assert_eq!(*server.state(), State::Confirmed);
|
||||
assert_eq!(server.loss_recovery.rtt(), RTT);
|
||||
assert_eq!(server.paths.rtt(), RTT);
|
||||
|
||||
now += RTT / 2;
|
||||
client.process_input(s2.unwrap(), now);
|
||||
assert_eq!(client.loss_recovery.rtt(), RTT);
|
||||
assert_eq!(client.paths.rtt(), RTT);
|
||||
|
||||
// All the stream data that was sent should now be available.
|
||||
let streams = server
|
||||
@ -698,6 +704,63 @@ fn extra_initial_invalid_cid() {
|
||||
assert!(nothing.is_none());
|
||||
}
|
||||
|
||||
fn connect_version(version: QuicVersion) {
|
||||
fixture_init();
|
||||
let mut client = Connection::new_client(
|
||||
test_fixture::DEFAULT_SERVER_NAME,
|
||||
test_fixture::DEFAULT_ALPN,
|
||||
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
|
||||
addr(),
|
||||
addr(),
|
||||
ConnectionParameters::default().quic_version(version),
|
||||
now(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut server = Connection::new_server(
|
||||
test_fixture::DEFAULT_KEYS,
|
||||
test_fixture::DEFAULT_ALPN,
|
||||
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
|
||||
ConnectionParameters::default().quic_version(version),
|
||||
)
|
||||
.unwrap();
|
||||
connect_force_idle(&mut client, &mut server);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connect_v1() {
|
||||
connect_version(QuicVersion::Version1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connect_27() {
|
||||
connect_version(QuicVersion::Draft27);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connect_28() {
|
||||
connect_version(QuicVersion::Draft28);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connect_29() {
|
||||
connect_version(QuicVersion::Draft29);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connect_30() {
|
||||
connect_version(QuicVersion::Draft30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connect_31() {
|
||||
connect_version(QuicVersion::Draft31);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connect_32() {
|
||||
connect_version(QuicVersion::Draft32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anti_amplification() {
|
||||
let mut client = default_client();
|
||||
@ -715,6 +778,12 @@ fn anti_amplification() {
|
||||
assert_eq!(s_init1.len(), PATH_MTU_V6);
|
||||
let s_init2 = server.process_output(now).dgram().unwrap();
|
||||
assert_eq!(s_init2.len(), PATH_MTU_V6);
|
||||
|
||||
// Skip the gap for pacing here.
|
||||
let s_pacing = server.process_output(now).callback();
|
||||
assert_ne!(s_pacing, Duration::new(0, 0));
|
||||
now += s_pacing;
|
||||
|
||||
let s_init3 = server.process_output(now).dgram().unwrap();
|
||||
assert_eq!(s_init3.len(), PATH_MTU_V6);
|
||||
let cb = server.process_output(now).callback();
|
||||
@ -746,3 +815,64 @@ fn anti_amplification() {
|
||||
server.process_input(fin.unwrap(), now);
|
||||
assert_eq!(*server.state(), State::Confirmed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn garbage_initial() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
|
||||
let dgram = client.process_output(now()).dgram().unwrap();
|
||||
let (initial, rest) = split_datagram(&dgram);
|
||||
let mut corrupted = Vec::from(&initial[..initial.len() - 1]);
|
||||
corrupted.push(initial[initial.len() - 1] ^ 0xb7);
|
||||
corrupted.extend_from_slice(rest.as_ref().map_or(&[], |r| &r[..]));
|
||||
let garbage = Datagram::new(addr(), addr(), corrupted);
|
||||
assert_eq!(Output::None, server.process(Some(garbage), now()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_initial_packet_from_wrong_address() {
|
||||
let mut client = default_client();
|
||||
let out = client.process(None, now());
|
||||
assert!(out.as_dgram_ref().is_some());
|
||||
|
||||
let mut server = default_server();
|
||||
let out = server.process(out.dgram(), now());
|
||||
assert!(out.as_dgram_ref().is_some());
|
||||
|
||||
let p = out.dgram().unwrap();
|
||||
let dgram = Datagram::new(
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 2)), 443),
|
||||
p.destination(),
|
||||
&p[..],
|
||||
);
|
||||
|
||||
let out = client.process(Some(dgram), now());
|
||||
assert!(out.as_dgram_ref().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_handshake_packet_from_wrong_address() {
|
||||
let mut client = default_client();
|
||||
let out = client.process(None, now());
|
||||
assert!(out.as_dgram_ref().is_some());
|
||||
|
||||
let mut server = default_server();
|
||||
let out = server.process(out.dgram(), now());
|
||||
assert!(out.as_dgram_ref().is_some());
|
||||
|
||||
let (s_in, s_hs) = split_datagram(&out.dgram().unwrap());
|
||||
|
||||
// Pass the initial packet.
|
||||
let _ = client.process(Some(s_in), now()).dgram();
|
||||
|
||||
let p = s_hs.unwrap();
|
||||
let dgram = Datagram::new(
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 2)), 443),
|
||||
p.destination(),
|
||||
&p[..],
|
||||
);
|
||||
|
||||
let out = client.process(Some(dgram), now());
|
||||
assert!(out.as_dgram_ref().is_none());
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use super::{
|
||||
maybe_authenticate, send_something, AT_LEAST_PTO,
|
||||
};
|
||||
use crate::packet::PacketBuilder;
|
||||
use crate::stats::FrameStats;
|
||||
use crate::tparams::{self, TransportParameter};
|
||||
use crate::tracking::PNSpace;
|
||||
use crate::StreamType;
|
||||
@ -250,18 +251,30 @@ fn idle_caching() {
|
||||
let ping_before_s = server.stats().frame_rx.ping;
|
||||
server.process_input(dgram.unwrap(), middle);
|
||||
assert_eq!(server.stats().frame_rx.ping, ping_before_s + 1);
|
||||
let crypto = server
|
||||
let mut tokens = Vec::new();
|
||||
server
|
||||
.crypto
|
||||
.streams
|
||||
.write_frame(PNSpace::Initial, &mut builder)
|
||||
.write_frame(
|
||||
PNSpace::Initial,
|
||||
&mut builder,
|
||||
&mut tokens,
|
||||
&mut FrameStats::default(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(crypto.is_some());
|
||||
let crypto = server
|
||||
assert_eq!(tokens.len(), 1);
|
||||
tokens.clear();
|
||||
server
|
||||
.crypto
|
||||
.streams
|
||||
.write_frame(PNSpace::Initial, &mut builder)
|
||||
.write_frame(
|
||||
PNSpace::Initial,
|
||||
&mut builder,
|
||||
&mut tokens,
|
||||
&mut FrameStats::default(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(crypto.is_none());
|
||||
assert!(tokens.is_empty());
|
||||
let dgram = server.process_output(middle).dgram();
|
||||
|
||||
// Now only allow the Initial packet from the server through;
|
||||
|
@ -277,9 +277,13 @@ fn exhaust_read_keys() {
|
||||
));
|
||||
|
||||
client.process_input(dgram.unwrap(), now());
|
||||
assert!(matches!(client.state(), State::Draining {
|
||||
error: ConnectionError::Transport(Error::PeerError(ERROR_AEAD_LIMIT_REACHED)), ..
|
||||
}));
|
||||
assert!(matches!(
|
||||
client.state(),
|
||||
State::Draining {
|
||||
error: ConnectionError::Transport(Error::PeerError(ERROR_AEAD_LIMIT_REACHED)),
|
||||
..
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -17,7 +17,7 @@ use neqo_common::Datagram;
|
||||
use std::cell::RefCell;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
use test_fixture::{self, addr, fixture_init, now};
|
||||
|
||||
/// This should be a valid-seeming transport parameter.
|
||||
@ -74,6 +74,14 @@ fn assert_v6_path(dgram: &Datagram, padded: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
/// As these tests use a new path, that path often has a non-zero RTT.
|
||||
/// Pacing can be a problem when testing that path. This skips time forward.
|
||||
fn skip_pacing(c: &mut Connection, now: Instant) -> Instant {
|
||||
let pacing = c.process_output(now).callback();
|
||||
assert_ne!(pacing, Duration::new(0, 0));
|
||||
now + pacing
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rebinding_port() {
|
||||
let mut client = default_client();
|
||||
@ -101,18 +109,19 @@ fn path_forwarding_attack() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
connect_force_idle(&mut client, &mut server);
|
||||
let mut now = now();
|
||||
|
||||
let dgram = send_something(&mut client, now());
|
||||
let dgram = send_something(&mut client, now);
|
||||
let dgram = change_path(&dgram, addr_v4());
|
||||
server.process_input(dgram, now());
|
||||
server.process_input(dgram, now);
|
||||
|
||||
// The server now probes the new (primary) path.
|
||||
let new_probe = server.process_output(now()).dgram().unwrap();
|
||||
let new_probe = server.process_output(now).dgram().unwrap();
|
||||
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
||||
assert_v4_path(&new_probe, false); // Can't be padded.
|
||||
|
||||
// The server also probes the old path.
|
||||
let old_probe = server.process_output(now()).dgram().unwrap();
|
||||
let old_probe = server.process_output(now).dgram().unwrap();
|
||||
assert_eq!(server.stats().frame_tx.path_challenge, 2);
|
||||
assert_v6_path(&old_probe, true);
|
||||
|
||||
@ -120,56 +129,57 @@ fn path_forwarding_attack() {
|
||||
// now constrained by the amplification limit.
|
||||
let stream_id = server.stream_create(StreamType::UniDi).unwrap();
|
||||
server.stream_close_send(stream_id).unwrap();
|
||||
assert!(server.process_output(now()).dgram().is_none());
|
||||
assert!(server.process_output(now).dgram().is_none());
|
||||
|
||||
// The client should respond to the challenge on the new path.
|
||||
// The server couldn't pad, so the client is also amplification limited.
|
||||
let new_resp = client.process(Some(new_probe), now()).dgram().unwrap();
|
||||
let new_resp = client.process(Some(new_probe), now).dgram().unwrap();
|
||||
assert_eq!(client.stats().frame_rx.path_challenge, 1);
|
||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||
assert_eq!(client.stats().frame_tx.path_response, 1);
|
||||
assert_v4_path(&new_resp, false);
|
||||
|
||||
// The client also responds to probes on the old path.
|
||||
let old_resp = client.process(Some(old_probe), now()).dgram().unwrap();
|
||||
let old_resp = client.process(Some(old_probe), now).dgram().unwrap();
|
||||
assert_eq!(client.stats().frame_rx.path_challenge, 2);
|
||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||
assert_eq!(client.stats().frame_tx.path_response, 2);
|
||||
assert_v6_path(&old_resp, true);
|
||||
|
||||
// But the client still sends data on the old path.
|
||||
let client_data1 = send_something(&mut client, now());
|
||||
let client_data1 = send_something(&mut client, now);
|
||||
assert_v6_path(&client_data1, false); // Just data.
|
||||
|
||||
// Receiving the PATH_RESPONSE from the client opens the amplification
|
||||
// limit enough for the server to respond.
|
||||
// This is padded because it includes PATH_CHALLENGE.
|
||||
let server_data1 = server.process(Some(new_resp), now()).dgram().unwrap();
|
||||
let server_data1 = server.process(Some(new_resp), now).dgram().unwrap();
|
||||
assert_v4_path(&server_data1, true);
|
||||
assert_eq!(server.stats().frame_tx.path_challenge, 3);
|
||||
|
||||
// The client responds to this probe on the new path.
|
||||
client.process_input(server_data1, now());
|
||||
client.process_input(server_data1, now);
|
||||
let stream_before = client.stats().frame_tx.stream;
|
||||
let padded_resp = send_something(&mut client, now());
|
||||
let padded_resp = send_something(&mut client, now);
|
||||
assert_eq!(stream_before, client.stats().frame_tx.stream);
|
||||
assert_v4_path(&padded_resp, true); // This is padded!
|
||||
|
||||
// But new data from the client stays on the old path.
|
||||
let client_data2 = client.process_output(now()).dgram().unwrap();
|
||||
let client_data2 = client.process_output(now).dgram().unwrap();
|
||||
assert_v6_path(&client_data2, false);
|
||||
|
||||
// The server keeps sending on the new path.
|
||||
let server_data2 = send_something(&mut server, now());
|
||||
now = skip_pacing(&mut server, now);
|
||||
let server_data2 = send_something(&mut server, now);
|
||||
assert_v4_path(&server_data2, false);
|
||||
|
||||
// Until new data is received from the client on the old path.
|
||||
server.process_input(client_data2, now());
|
||||
server.process_input(client_data2, now);
|
||||
// The server sends a probe on the "old" path.
|
||||
let server_data3 = send_something(&mut server, now());
|
||||
let server_data3 = send_something(&mut server, now);
|
||||
assert_v4_path(&server_data3, true);
|
||||
// But switches data transmission to the "new" path.
|
||||
let server_data4 = server.process_output(now()).dgram().unwrap();
|
||||
let server_data4 = server.process_output(now).dgram().unwrap();
|
||||
assert_v6_path(&server_data4, false);
|
||||
}
|
||||
|
||||
@ -178,35 +188,37 @@ fn migrate_immediate() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
connect_force_idle(&mut client, &mut server);
|
||||
let mut now = now();
|
||||
|
||||
client
|
||||
.migrate(Some(addr_v4()), Some(addr_v4()), true, now())
|
||||
.migrate(Some(addr_v4()), Some(addr_v4()), true, now)
|
||||
.unwrap();
|
||||
|
||||
let client1 = send_something(&mut client, now());
|
||||
let client1 = send_something(&mut client, now);
|
||||
assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
|
||||
let client2 = send_something(&mut client, now());
|
||||
let client2 = send_something(&mut client, now);
|
||||
assert_v4_path(&client2, false); // Doesn't.
|
||||
|
||||
let server_delayed = send_something(&mut server, now());
|
||||
let server_delayed = send_something(&mut server, now);
|
||||
|
||||
// The server accepts the first packet and migrates (but probes).
|
||||
let server1 = server.process(Some(client1), now()).dgram().unwrap();
|
||||
let server1 = server.process(Some(client1), now).dgram().unwrap();
|
||||
assert_v4_path(&server1, true);
|
||||
let server2 = server.process_output(now()).dgram().unwrap();
|
||||
let server2 = server.process_output(now).dgram().unwrap();
|
||||
assert_v6_path(&server2, true);
|
||||
|
||||
// The second packet has no real effect, it just elicits an ACK.
|
||||
let all_before = server.stats().frame_tx.all;
|
||||
let ack_before = server.stats().frame_tx.ack;
|
||||
let server3 = server.process(Some(client2), now()).dgram();
|
||||
let server3 = server.process(Some(client2), now).dgram();
|
||||
assert!(server3.is_some());
|
||||
assert_eq!(server.stats().frame_tx.all, all_before + 1);
|
||||
assert_eq!(server.stats().frame_tx.ack, ack_before + 1);
|
||||
|
||||
// Receiving a packet sent by the server before migration doesn't change path.
|
||||
client.process_input(server_delayed, now());
|
||||
let client3 = send_something(&mut client, now());
|
||||
client.process_input(server_delayed, now);
|
||||
now = skip_pacing(&mut client, now);
|
||||
let client3 = send_something(&mut client, now);
|
||||
assert_v4_path(&client3, false);
|
||||
}
|
||||
|
||||
@ -391,7 +403,11 @@ fn migration(mut client: Connection) {
|
||||
let client_confirmation = client.process_output(now).dgram().unwrap();
|
||||
assert_v4_path(&client_confirmation, false);
|
||||
|
||||
let server_confirmation = send_something(&mut server, now);
|
||||
// The server has now sent 2 packets, so it is blocked on the pacer. Wait.
|
||||
let server_pacing = server.process_output(now).callback();
|
||||
assert_ne!(server_pacing, Duration::new(0, 0));
|
||||
// ... then confirm that the server sends on the new path still.
|
||||
let server_confirmation = send_something(&mut server, now + server_pacing);
|
||||
assert_v4_path(&server_confirmation, false);
|
||||
}
|
||||
|
||||
@ -411,6 +427,7 @@ fn migration_client_empty_cid() {
|
||||
addr(),
|
||||
addr(),
|
||||
ConnectionParameters::default(),
|
||||
now(),
|
||||
)
|
||||
.unwrap();
|
||||
migration(client);
|
||||
@ -470,6 +487,7 @@ fn preferred_address(hs_client: SocketAddr, hs_server: SocketAddr, preferred: So
|
||||
hs_client,
|
||||
hs_server,
|
||||
ConnectionParameters::default(),
|
||||
now(),
|
||||
)
|
||||
.unwrap();
|
||||
let spa = if preferred.ip().is_ipv6() {
|
||||
|
@ -33,6 +33,7 @@ mod handshake;
|
||||
mod idle;
|
||||
mod keys;
|
||||
mod migration;
|
||||
mod priority;
|
||||
mod recovery;
|
||||
mod resumption;
|
||||
mod stream;
|
||||
@ -96,6 +97,7 @@ pub fn new_client(params: ConnectionParameters) -> Connection {
|
||||
addr(),
|
||||
addr(),
|
||||
params,
|
||||
now(),
|
||||
)
|
||||
.expect("create a default client")
|
||||
}
|
||||
@ -144,7 +146,12 @@ fn handshake(
|
||||
let mut now = now;
|
||||
|
||||
let mut input = None;
|
||||
let is_done = |c: &mut Connection| matches!(c.state(), State::Confirmed | State::Closing { .. } | State::Closed(..));
|
||||
let is_done = |c: &mut Connection| {
|
||||
matches!(
|
||||
c.state(),
|
||||
State::Confirmed | State::Closing { .. } | State::Closed(..)
|
||||
)
|
||||
};
|
||||
|
||||
while !is_done(a) {
|
||||
let _ = maybe_authenticate(a);
|
||||
@ -181,8 +188,8 @@ fn connect_with_rtt(
|
||||
assert_eq!(*client.state(), State::Confirmed);
|
||||
assert_eq!(*server.state(), State::Confirmed);
|
||||
|
||||
assert_eq!(client.loss_recovery.rtt(), rtt);
|
||||
assert_eq!(server.loss_recovery.rtt(), rtt);
|
||||
assert_eq!(client.paths.rtt(), rtt);
|
||||
assert_eq!(server.paths.rtt(), rtt);
|
||||
now
|
||||
}
|
||||
|
||||
@ -262,6 +269,7 @@ fn connect_rtt_idle(client: &mut Connection, server: &mut Connection, rtt: Durat
|
||||
// Drain events from both as well.
|
||||
let _ = client.events().count();
|
||||
let _ = server.events().count();
|
||||
qtrace!("----- connected and idle with RTT {:?}", rtt);
|
||||
now
|
||||
}
|
||||
|
||||
@ -275,36 +283,33 @@ fn connect_force_idle(client: &mut Connection, server: &mut Connection) {
|
||||
/// from the return value whether a timeout is an ACK delay, PTO, or
|
||||
/// pacing, this looks at the congestion window to tell when to stop.
|
||||
/// Returns a list of datagrams and the new time.
|
||||
fn fill_cwnd(src: &mut Connection, stream: u64, mut now: Instant) -> (Vec<Datagram>, Instant) {
|
||||
fn fill_cwnd(c: &mut Connection, stream: u64, mut now: Instant) -> (Vec<Datagram>, Instant) {
|
||||
const BLOCK_SIZE: usize = 4_096;
|
||||
let mut total_dgrams = Vec::new();
|
||||
// Train wreck function to get the remaining congestion window on the primary path.
|
||||
fn cwnd(c: &Connection) -> usize {
|
||||
c.paths.primary().borrow().sender().cwnd_avail()
|
||||
}
|
||||
|
||||
qtrace!(
|
||||
"fill_cwnd starting cwnd: {}",
|
||||
src.loss_recovery.cwnd_avail()
|
||||
);
|
||||
qtrace!("fill_cwnd starting cwnd: {}", cwnd(c));
|
||||
|
||||
loop {
|
||||
let bytes_sent = src.stream_send(stream, &[0x42; BLOCK_SIZE]).unwrap();
|
||||
let bytes_sent = c.stream_send(stream, &[0x42; BLOCK_SIZE]).unwrap();
|
||||
qtrace!("fill_cwnd wrote {} bytes", bytes_sent);
|
||||
if bytes_sent < BLOCK_SIZE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut total_dgrams = Vec::new();
|
||||
loop {
|
||||
let pkt = src.process_output(now);
|
||||
qtrace!(
|
||||
"fill_cwnd cwnd remaining={}, output: {:?}",
|
||||
src.loss_recovery.cwnd_avail(),
|
||||
pkt
|
||||
);
|
||||
let pkt = c.process_output(now);
|
||||
qtrace!("fill_cwnd cwnd remaining={}, output: {:?}", cwnd(c), pkt);
|
||||
match pkt {
|
||||
Output::Datagram(dgram) => {
|
||||
total_dgrams.push(dgram);
|
||||
}
|
||||
Output::Callback(t) => {
|
||||
if src.loss_recovery.cwnd_avail() < ACK_ONLY_SIZE_LIMIT {
|
||||
if cwnd(c) < ACK_ONLY_SIZE_LIMIT {
|
||||
break;
|
||||
}
|
||||
now += t;
|
||||
@ -313,6 +318,10 @@ fn fill_cwnd(src: &mut Connection, stream: u64, mut now: Instant) -> (Vec<Datagr
|
||||
}
|
||||
}
|
||||
|
||||
qtrace!(
|
||||
"fill_cwnd sent {} bytes",
|
||||
total_dgrams.iter().map(|d| d.len()).sum::<usize>()
|
||||
);
|
||||
(total_dgrams, now)
|
||||
}
|
||||
|
||||
|
401
third_party/rust/neqo-transport/src/connection/tests/priority.rs
vendored
Normal file
401
third_party/rust/neqo-transport/src/connection/tests/priority.rs
vendored
Normal file
@ -0,0 +1,401 @@
|
||||
// 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::super::{Connection, Error, Output};
|
||||
use super::{connect, default_client, default_server, fill_cwnd, maybe_authenticate};
|
||||
use crate::addr_valid::{AddressValidation, ValidateAddress};
|
||||
use crate::send_stream::{RetransmissionPriority, TransmissionPriority};
|
||||
use crate::{ConnectionEvent, StreamType};
|
||||
|
||||
use neqo_common::event::Provider;
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use test_fixture::{self, now};
|
||||
|
||||
const BLOCK_SIZE: usize = 4_096;
|
||||
|
||||
fn fill_stream(c: &mut Connection, id: u64) {
|
||||
loop {
|
||||
if c.stream_send(id, &[0x42; BLOCK_SIZE]).unwrap() < BLOCK_SIZE {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A receive stream cannot be prioritized (yet).
|
||||
#[test]
|
||||
fn receive_stream() {
|
||||
const MESSAGE: &[u8] = b"hello";
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
connect(&mut client, &mut server);
|
||||
|
||||
let id = client.stream_create(StreamType::UniDi).unwrap();
|
||||
assert_eq!(MESSAGE.len(), client.stream_send(id, MESSAGE).unwrap());
|
||||
let dgram = client.process_output(now()).dgram();
|
||||
|
||||
server.process_input(dgram.unwrap(), now());
|
||||
assert_eq!(
|
||||
server
|
||||
.stream_priority(
|
||||
id,
|
||||
TransmissionPriority::default(),
|
||||
RetransmissionPriority::default()
|
||||
)
|
||||
.unwrap_err(),
|
||||
Error::InvalidStreamId,
|
||||
"Priority doesn't apply to inbound unidirectional streams"
|
||||
);
|
||||
|
||||
// But the stream does exist and can be read.
|
||||
let mut buf = [0; 10];
|
||||
let (len, end) = server.stream_recv(id, &mut buf).unwrap();
|
||||
assert_eq!(MESSAGE, &buf[..len]);
|
||||
assert!(!end);
|
||||
}
|
||||
|
||||
/// Higher priority streams get sent ahead of lower ones, even when
|
||||
/// the higher priority stream is written to later.
|
||||
#[test]
|
||||
fn relative() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
connect(&mut client, &mut server);
|
||||
|
||||
// id_normal is created first, but it is lower priority.
|
||||
let id_normal = client.stream_create(StreamType::UniDi).unwrap();
|
||||
fill_stream(&mut client, id_normal);
|
||||
let high = client.stream_create(StreamType::UniDi).unwrap();
|
||||
fill_stream(&mut client, high);
|
||||
client
|
||||
.stream_priority(
|
||||
high,
|
||||
TransmissionPriority::High,
|
||||
RetransmissionPriority::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let dgram = client.process_output(now()).dgram();
|
||||
server.process_input(dgram.unwrap(), now());
|
||||
|
||||
// The "id_normal" stream will get a `NewStream` event, but no data.
|
||||
for e in server.events() {
|
||||
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
|
||||
assert_ne!(stream_id, id_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that changing priority has effect on the next packet that is sent.
|
||||
#[test]
|
||||
fn reprioritize() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
connect(&mut client, &mut server);
|
||||
|
||||
// id_normal is created first, but it is lower priority.
|
||||
let id_normal = client.stream_create(StreamType::UniDi).unwrap();
|
||||
fill_stream(&mut client, id_normal);
|
||||
let id_high = client.stream_create(StreamType::UniDi).unwrap();
|
||||
fill_stream(&mut client, id_high);
|
||||
client
|
||||
.stream_priority(
|
||||
id_high,
|
||||
TransmissionPriority::High,
|
||||
RetransmissionPriority::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let dgram = client.process_output(now()).dgram();
|
||||
server.process_input(dgram.unwrap(), now());
|
||||
|
||||
// The "id_normal" stream will get a `NewStream` event, but no data.
|
||||
for e in server.events() {
|
||||
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
|
||||
assert_ne!(stream_id, id_normal);
|
||||
}
|
||||
}
|
||||
|
||||
// When the high priority stream drops in priority, the streams are equal
|
||||
// priority and so their stream ID determines what is sent.
|
||||
client
|
||||
.stream_priority(
|
||||
id_high,
|
||||
TransmissionPriority::Normal,
|
||||
RetransmissionPriority::default(),
|
||||
)
|
||||
.unwrap();
|
||||
let dgram = client.process_output(now()).dgram();
|
||||
server.process_input(dgram.unwrap(), now());
|
||||
|
||||
for e in server.events() {
|
||||
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
|
||||
assert_ne!(stream_id, id_high);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Retransmission can be prioritized differently (usually higher).
|
||||
#[test]
|
||||
fn repairing_loss() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
connect(&mut client, &mut server);
|
||||
let mut now = now();
|
||||
|
||||
// Send a few packets at low priority, lose one.
|
||||
let id_low = client.stream_create(StreamType::UniDi).unwrap();
|
||||
fill_stream(&mut client, id_low);
|
||||
client
|
||||
.stream_priority(
|
||||
id_low,
|
||||
TransmissionPriority::Low,
|
||||
RetransmissionPriority::Higher,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let _lost = client.process_output(now).dgram();
|
||||
for _ in 0..5 {
|
||||
match client.process_output(now) {
|
||||
Output::Datagram(d) => server.process_input(d, now),
|
||||
Output::Callback(delay) => now += delay,
|
||||
Output::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Generate an ACK. The first packet is now considered lost.
|
||||
let ack = server.process_output(now).dgram();
|
||||
let _ = server.events().count(); // Drain events.
|
||||
|
||||
let id_normal = client.stream_create(StreamType::UniDi).unwrap();
|
||||
fill_stream(&mut client, id_normal);
|
||||
|
||||
let dgram = client.process(ack, now).dgram();
|
||||
assert_eq!(client.stats().lost, 1); // Client should have noticed the loss.
|
||||
server.process_input(dgram.unwrap(), now);
|
||||
|
||||
// Only the low priority stream has data as the retransmission of the data from
|
||||
// the lost packet is now more important than new data from the high priority stream.
|
||||
for e in server.events() {
|
||||
println!("Event: {:?}", e);
|
||||
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
|
||||
assert_eq!(stream_id, id_low);
|
||||
}
|
||||
}
|
||||
|
||||
// However, only the retransmission is prioritized.
|
||||
// Though this might contain some retransmitted data, as other frames might push
|
||||
// the retransmitted data into a second packet, it will also contain data from the
|
||||
// normal priority stream.
|
||||
let dgram = client.process_output(now).dgram();
|
||||
server.process_input(dgram.unwrap(), now);
|
||||
assert!(server.events().any(
|
||||
|e| matches!(e, ConnectionEvent::RecvStreamReadable { stream_id } if stream_id == id_normal),
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn critical() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
let now = now();
|
||||
|
||||
// Rather than connect, send stream data in 0.5-RTT.
|
||||
// That allows this to test that critical streams pre-empt most frame types.
|
||||
let dgram = client.process_output(now).dgram();
|
||||
let dgram = server.process(dgram, now).dgram();
|
||||
client.process_input(dgram.unwrap(), now);
|
||||
maybe_authenticate(&mut client);
|
||||
|
||||
let id = server.stream_create(StreamType::UniDi).unwrap();
|
||||
server
|
||||
.stream_priority(
|
||||
id,
|
||||
TransmissionPriority::Critical,
|
||||
RetransmissionPriority::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Can't use fill_cwnd here because the server is blocked on the amplification
|
||||
// limit, so it can't fill the congestion window.
|
||||
while server.stream_create(StreamType::UniDi).is_ok() {}
|
||||
|
||||
fill_stream(&mut server, id);
|
||||
let stats_before = server.stats().frame_tx;
|
||||
let dgram = server.process_output(now).dgram();
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto);
|
||||
assert_eq!(stats_after.streams_blocked, 0);
|
||||
assert_eq!(stats_after.new_connection_id, 0);
|
||||
assert_eq!(stats_after.new_token, 0);
|
||||
assert_eq!(stats_after.handshake_done, 0);
|
||||
|
||||
// Complete the handshake.
|
||||
let dgram = client.process(dgram, now).dgram();
|
||||
server.process_input(dgram.unwrap(), now);
|
||||
|
||||
// Critical beats everything but HANDSHAKE_DONE.
|
||||
let stats_before = server.stats().frame_tx;
|
||||
mem::drop(fill_cwnd(&mut server, id, now));
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto);
|
||||
assert_eq!(stats_after.streams_blocked, 0);
|
||||
assert_eq!(stats_after.new_connection_id, 0);
|
||||
assert_eq!(stats_after.new_token, 0);
|
||||
assert_eq!(stats_after.handshake_done, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn important() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
let now = now();
|
||||
|
||||
// Rather than connect, send stream data in 0.5-RTT.
|
||||
// That allows this to test that important streams pre-empt most frame types.
|
||||
let dgram = client.process_output(now).dgram();
|
||||
let dgram = server.process(dgram, now).dgram();
|
||||
client.process_input(dgram.unwrap(), now);
|
||||
maybe_authenticate(&mut client);
|
||||
|
||||
let id = server.stream_create(StreamType::UniDi).unwrap();
|
||||
server
|
||||
.stream_priority(
|
||||
id,
|
||||
TransmissionPriority::Important,
|
||||
RetransmissionPriority::default(),
|
||||
)
|
||||
.unwrap();
|
||||
fill_stream(&mut server, id);
|
||||
|
||||
// Important beats everything but flow control.
|
||||
// Make enough streams to get a STREAMS_BLOCKED frame out.
|
||||
while server.stream_create(StreamType::UniDi).is_ok() {}
|
||||
|
||||
let stats_before = server.stats().frame_tx;
|
||||
let dgram = server.process_output(now).dgram();
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto);
|
||||
assert_eq!(stats_after.streams_blocked, 1);
|
||||
assert_eq!(stats_after.new_connection_id, 0);
|
||||
assert_eq!(stats_after.new_token, 0);
|
||||
assert_eq!(stats_after.handshake_done, 0);
|
||||
assert_eq!(stats_after.stream, stats_before.stream + 1);
|
||||
|
||||
// Complete the handshake.
|
||||
let dgram = client.process(dgram, now).dgram();
|
||||
server.process_input(dgram.unwrap(), now);
|
||||
|
||||
// Important beats everything but flow control.
|
||||
let stats_before = server.stats().frame_tx;
|
||||
mem::drop(fill_cwnd(&mut server, id, now));
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto);
|
||||
assert_eq!(stats_after.streams_blocked, 1);
|
||||
assert_eq!(stats_after.new_connection_id, 0);
|
||||
assert_eq!(stats_after.new_token, 0);
|
||||
assert_eq!(stats_after.handshake_done, 1);
|
||||
assert!(stats_after.stream > stats_before.stream);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn high_normal() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
let now = now();
|
||||
|
||||
// Rather than connect, send stream data in 0.5-RTT.
|
||||
// That allows this to test that important streams pre-empt most frame types.
|
||||
let dgram = client.process_output(now).dgram();
|
||||
let dgram = server.process(dgram, now).dgram();
|
||||
client.process_input(dgram.unwrap(), now);
|
||||
maybe_authenticate(&mut client);
|
||||
|
||||
let id = server.stream_create(StreamType::UniDi).unwrap();
|
||||
server
|
||||
.stream_priority(
|
||||
id,
|
||||
TransmissionPriority::High,
|
||||
RetransmissionPriority::default(),
|
||||
)
|
||||
.unwrap();
|
||||
fill_stream(&mut server, id);
|
||||
|
||||
// Important beats everything but flow control.
|
||||
// Make enough streams to get a STREAMS_BLOCKED frame out.
|
||||
while server.stream_create(StreamType::UniDi).is_ok() {}
|
||||
|
||||
let stats_before = server.stats().frame_tx;
|
||||
let dgram = server.process_output(now).dgram();
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto);
|
||||
assert_eq!(stats_after.streams_blocked, 1);
|
||||
assert_eq!(stats_after.new_connection_id, 0);
|
||||
assert_eq!(stats_after.new_token, 0);
|
||||
assert_eq!(stats_after.handshake_done, 0);
|
||||
assert_eq!(stats_after.stream, stats_before.stream + 1);
|
||||
|
||||
// Complete the handshake.
|
||||
let dgram = client.process(dgram, now).dgram();
|
||||
server.process_input(dgram.unwrap(), now);
|
||||
|
||||
// High or Normal doesn't beat NEW_CONNECTION_ID,
|
||||
// but they beat CRYPTO/NEW_TOKEN.
|
||||
let stats_before = server.stats().frame_tx;
|
||||
server.send_ticket(now, &[]).unwrap();
|
||||
mem::drop(fill_cwnd(&mut server, id, now));
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto);
|
||||
assert_eq!(stats_after.streams_blocked, 1);
|
||||
assert_ne!(stats_after.new_connection_id, 0); // Note: > 0
|
||||
assert_eq!(stats_after.new_token, 0);
|
||||
assert_eq!(stats_after.handshake_done, 1);
|
||||
assert!(stats_after.stream > stats_before.stream);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn low() {
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
let now = now();
|
||||
// Use address validation; note that we need to hold a strong reference
|
||||
// as the server will only hold a weak reference.
|
||||
let validation = Rc::new(RefCell::new(
|
||||
AddressValidation::new(now, ValidateAddress::Never).unwrap(),
|
||||
));
|
||||
server.set_validation(Rc::clone(&validation));
|
||||
connect(&mut client, &mut server);
|
||||
|
||||
let id = server.stream_create(StreamType::UniDi).unwrap();
|
||||
server
|
||||
.stream_priority(
|
||||
id,
|
||||
TransmissionPriority::Low,
|
||||
RetransmissionPriority::default(),
|
||||
)
|
||||
.unwrap();
|
||||
fill_stream(&mut server, id);
|
||||
|
||||
// Send a session ticket and make it big enough to require a whole packet.
|
||||
// The resulting CRYPTO frame beats out the stream data.
|
||||
let stats_before = server.stats().frame_tx;
|
||||
server.send_ticket(now, &[0; 2048]).unwrap();
|
||||
let _ = server.process_output(now);
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto + 1);
|
||||
assert_eq!(stats_after.stream, stats_before.stream);
|
||||
|
||||
// The above can't test if NEW_TOKEN wins because once that fits in a packet,
|
||||
// it is very hard to ensure that the STREAM frame won't also fit.
|
||||
// However, we can ensure that the next packet doesn't consist of just STREAM.
|
||||
let stats_before = server.stats().frame_tx;
|
||||
let _ = server.process_output(now);
|
||||
let stats_after = server.stats().frame_tx;
|
||||
assert_eq!(stats_after.crypto, stats_before.crypto + 1);
|
||||
assert_eq!(stats_after.new_token, 1);
|
||||
assert_eq!(stats_after.stream, stats_before.stream + 1);
|
||||
}
|
@ -4,14 +4,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::super::{Output, State, LOCAL_IDLE_TIMEOUT};
|
||||
use super::super::{Connection, Output, State, LOCAL_IDLE_TIMEOUT};
|
||||
use super::{
|
||||
assert_full_cwnd, connect, connect_force_idle, connect_rtt_idle, connect_with_rtt,
|
||||
default_client, default_server, fill_cwnd, maybe_authenticate, send_and_receive,
|
||||
send_something, AT_LEAST_PTO, DEFAULT_RTT, POST_HANDSHAKE_CWND,
|
||||
};
|
||||
use crate::path::PATH_MTU_V6;
|
||||
use crate::recovery::PTO_PACKET_COUNT;
|
||||
use crate::recovery::{MAX_OUTSTANDING_UNACK, MIN_OUTSTANDING_UNACK, PTO_PACKET_COUNT};
|
||||
use crate::stats::MAX_PTO_COUNTS;
|
||||
use crate::tparams::TransportParameter;
|
||||
use crate::tracking::ACK_DELAY;
|
||||
@ -19,7 +19,7 @@ use crate::StreamType;
|
||||
|
||||
use neqo_common::qdebug;
|
||||
use neqo_crypto::AuthenticationStatus;
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
use test_fixture::{self, now, split_datagram};
|
||||
|
||||
#[test]
|
||||
@ -77,11 +77,11 @@ fn pto_works_full_cwnd() {
|
||||
assert_eq!(dgrams.len(), 2);
|
||||
assert_eq!(dgrams[0].len(), PATH_MTU_V6);
|
||||
|
||||
// Both datagrams contain a STREAM frame.
|
||||
// Both datagrams contain one or more STREAM frames.
|
||||
for d in dgrams {
|
||||
let stream_before = server.stats().frame_rx.stream;
|
||||
server.process_input(d, now);
|
||||
assert_eq!(server.stats().frame_rx.stream, stream_before + 1);
|
||||
assert!(server.stats().frame_rx.stream > stream_before);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ fn pto_works_ping() {
|
||||
|
||||
// Nothing to do, should return callback
|
||||
let cb = client.process(None, now).callback();
|
||||
assert_eq!(cb, Duration::from_millis(45));
|
||||
assert_eq!(cb, Duration::from_millis(26)); // MAX_ACK_DELAY + GRANULARITY
|
||||
|
||||
// Process these by server, skipping pkt0
|
||||
let srv0 = server.process(Some(pkt1), now).dgram();
|
||||
@ -614,3 +614,91 @@ fn loss_time_past_largest_acked() {
|
||||
assert_ne!(delay, Duration::from_secs(0));
|
||||
assert!(delay > lr_time);
|
||||
}
|
||||
|
||||
/// `sender` sends a little, `receiver` acknowledges it.
|
||||
/// Repeat until `count` acknowledgements are sent.
|
||||
/// Returns the last packet containing acknowledgements, if any.
|
||||
fn trickle(sender: &mut Connection, receiver: &mut Connection, mut count: usize, now: Instant) {
|
||||
let id = sender.stream_create(StreamType::UniDi).unwrap();
|
||||
let mut maybe_ack = None;
|
||||
while count > 0 {
|
||||
qdebug!("trickle: remaining={}", count);
|
||||
assert_eq!(sender.stream_send(id, &[9]).unwrap(), 1);
|
||||
let dgram = sender.process(maybe_ack, now).dgram();
|
||||
|
||||
maybe_ack = receiver.process(dgram, now).dgram();
|
||||
count -= usize::from(maybe_ack.is_some());
|
||||
}
|
||||
sender.process_input(maybe_ack.unwrap(), now);
|
||||
}
|
||||
|
||||
/// Ensure that a PING frame is sent with ACK sometimes.
|
||||
/// `fast` allows testing of when `MAX_OUTSTANDING_UNACK` packets are
|
||||
/// outstanding (`fast` is `true`) within 1 PTO and when only
|
||||
/// `MIN_OUTSTANDING_UNACK` packets arrive after 2 PTOs (`fast` is `false`).
|
||||
fn ping_with_ack(fast: bool) {
|
||||
let mut sender = default_client();
|
||||
let mut receiver = default_server();
|
||||
let mut now = now();
|
||||
connect_force_idle(&mut sender, &mut receiver);
|
||||
let sender_acks_before = sender.stats().frame_tx.ack;
|
||||
let receiver_acks_before = receiver.stats().frame_tx.ack;
|
||||
let count = if fast {
|
||||
MAX_OUTSTANDING_UNACK
|
||||
} else {
|
||||
MIN_OUTSTANDING_UNACK
|
||||
};
|
||||
trickle(&mut sender, &mut receiver, count, now);
|
||||
assert_eq!(sender.stats().frame_tx.ack, sender_acks_before);
|
||||
assert_eq!(receiver.stats().frame_tx.ack, receiver_acks_before + count);
|
||||
assert_eq!(receiver.stats().frame_tx.ping, 0);
|
||||
|
||||
if !fast {
|
||||
// Wait at least one PTO, from the reciever's perspective.
|
||||
// A receiver that hasn't received MAX_OUTSTANDING_UNACK won't send PING.
|
||||
now += receiver.pto() + Duration::from_micros(1);
|
||||
trickle(&mut sender, &mut receiver, 1, now);
|
||||
assert_eq!(receiver.stats().frame_tx.ping, 0);
|
||||
}
|
||||
|
||||
// After a second PTO (or the first if fast), new acknowledgements come
|
||||
// with a PING frame and cause an ACK to be sent by the sender.
|
||||
now += receiver.pto() + Duration::from_micros(1);
|
||||
trickle(&mut sender, &mut receiver, 1, now);
|
||||
assert_eq!(receiver.stats().frame_tx.ping, 1);
|
||||
if let Output::Callback(t) = sender.process_output(now) {
|
||||
assert_eq!(t, ACK_DELAY);
|
||||
assert!(sender.process_output(now + t).dgram().is_some());
|
||||
}
|
||||
assert_eq!(sender.stats().frame_tx.ack, sender_acks_before + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ping_with_ack_fast() {
|
||||
ping_with_ack(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ping_with_ack_slow() {
|
||||
ping_with_ack(false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ping_with_ack_min() {
|
||||
const COUNT: usize = MIN_OUTSTANDING_UNACK - 2;
|
||||
let mut sender = default_client();
|
||||
let mut receiver = default_server();
|
||||
let mut now = now();
|
||||
connect_force_idle(&mut sender, &mut receiver);
|
||||
let sender_acks_before = sender.stats().frame_tx.ack;
|
||||
let receiver_acks_before = receiver.stats().frame_tx.ack;
|
||||
trickle(&mut sender, &mut receiver, COUNT, now);
|
||||
assert_eq!(sender.stats().frame_tx.ack, sender_acks_before);
|
||||
assert_eq!(receiver.stats().frame_tx.ack, receiver_acks_before + COUNT);
|
||||
assert_eq!(receiver.stats().frame_tx.ping, 0);
|
||||
|
||||
// After 3 PTO, no PING because there are too few outstanding packets.
|
||||
now += receiver.pto() * 3 + Duration::from_micros(1);
|
||||
trickle(&mut sender, &mut receiver, 1, now);
|
||||
assert_eq!(receiver.stats().frame_tx.ping, 0);
|
||||
}
|
||||
|
@ -41,21 +41,21 @@ fn remember_smoothed_rtt() {
|
||||
let mut server = default_server();
|
||||
|
||||
let now = connect_with_rtt(&mut client, &mut server, now(), RTT1);
|
||||
assert_eq!(client.loss_recovery.rtt(), RTT1);
|
||||
assert_eq!(client.paths.rtt(), RTT1);
|
||||
|
||||
let token = exchange_ticket(&mut client, &mut server, now);
|
||||
let mut client = default_client();
|
||||
let mut server = default_server();
|
||||
client.enable_resumption(now, token).unwrap();
|
||||
assert_eq!(
|
||||
client.loss_recovery.rtt(),
|
||||
client.paths.rtt(),
|
||||
RTT1,
|
||||
"client should remember previous RTT"
|
||||
);
|
||||
|
||||
connect_with_rtt(&mut client, &mut server, now, RTT2);
|
||||
assert_eq!(
|
||||
client.loss_recovery.rtt(),
|
||||
client.paths.rtt(),
|
||||
RTT2,
|
||||
"previous RTT should be completely erased"
|
||||
);
|
||||
@ -114,19 +114,19 @@ fn two_tickets_on_timer() {
|
||||
|
||||
// We need to wait for release_resumption_token_timer to expire. The timer will be
|
||||
// set to 3 * PTO
|
||||
let mut now = now() + 3 * client.get_pto();
|
||||
let mut now = now() + 3 * client.pto();
|
||||
let _ = client.process(None, now);
|
||||
let mut recv_tokens = get_tokens(&mut client);
|
||||
assert_eq!(recv_tokens.len(), 1);
|
||||
let token1 = recv_tokens.pop().unwrap();
|
||||
// Wai for anottheer 3 * PTO to get the nex okeen.
|
||||
now += 3 * client.get_pto();
|
||||
now += 3 * client.pto();
|
||||
let _ = client.process(None, now);
|
||||
let mut recv_tokens = get_tokens(&mut client);
|
||||
assert_eq!(recv_tokens.len(), 1);
|
||||
let token2 = recv_tokens.pop().unwrap();
|
||||
// Wait for 3 * PTO, but now there are no more tokens.
|
||||
now += 3 * client.get_pto();
|
||||
now += 3 * client.pto();
|
||||
let _ = client.process(None, now);
|
||||
assert_eq!(get_tokens(&mut client).len(), 0);
|
||||
assert_ne!(token1.as_ref(), token2.as_ref());
|
||||
|
@ -11,7 +11,7 @@ use super::{
|
||||
};
|
||||
use crate::events::ConnectionEvent;
|
||||
use crate::recv_stream::RECV_BUFFER_SIZE;
|
||||
use crate::send_stream::SEND_BUFFER_SIZE;
|
||||
use crate::send_stream::{SendStreamState, SEND_BUFFER_SIZE};
|
||||
use crate::tparams::{self, TransportParameter};
|
||||
use crate::tracking::MAX_UNACKED_PKTS;
|
||||
use crate::{Error, StreamId, StreamType};
|
||||
@ -130,7 +130,7 @@ fn report_fin_when_stream_closed_wo_data() {
|
||||
server.stream_close_send(stream_id).unwrap();
|
||||
let out = server.process(None, now());
|
||||
let _ = client.process(out.dgram(), now());
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable {..});
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
||||
assert!(client.events().any(stream_readable));
|
||||
}
|
||||
|
||||
@ -203,7 +203,10 @@ fn max_data() {
|
||||
|
||||
let evts = client.events().collect::<Vec<_>>();
|
||||
assert_eq!(evts.len(), 1);
|
||||
assert!(matches!(evts[0], ConnectionEvent::SendStreamWritable{..}));
|
||||
assert!(matches!(
|
||||
evts[0],
|
||||
ConnectionEvent::SendStreamWritable { .. }
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -221,7 +224,7 @@ fn do_not_accept_data_after_stop_sending() {
|
||||
let out = client.process(None, now());
|
||||
let _ = server.process(out.dgram(), now());
|
||||
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable {..});
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
||||
assert!(server.events().any(stream_readable));
|
||||
|
||||
// Send one more packet from client. The packet should arrive after the server
|
||||
@ -386,28 +389,36 @@ fn stream_data_blocked_generates_max_stream_data() {
|
||||
|
||||
let now = now();
|
||||
|
||||
// Send some data and include STREAM_DATA_BLOCKED with any value.
|
||||
// Send some data and consume some flow control.
|
||||
let stream_id = server.stream_create(StreamType::UniDi).unwrap();
|
||||
let _ = server.stream_send(stream_id, DEFAULT_STREAM_DATA).unwrap();
|
||||
server.flow_mgr.borrow_mut().stream_data_blocked(
|
||||
StreamId::from(stream_id),
|
||||
u64::try_from(DEFAULT_STREAM_DATA.len()).unwrap(),
|
||||
);
|
||||
|
||||
let dgram = server.process(None, now).dgram();
|
||||
assert!(dgram.is_some());
|
||||
|
||||
let sdb_before = client.stats().frame_rx.stream_data_blocked;
|
||||
client.process_input(dgram.unwrap(), now);
|
||||
assert_eq!(client.stats().frame_rx.stream_data_blocked, sdb_before + 1);
|
||||
|
||||
// Consume the data.
|
||||
client.process_input(dgram.unwrap(), now);
|
||||
let mut buf = [0; 10];
|
||||
let (count, end) = client.stream_recv(stream_id, &mut buf[..]).unwrap();
|
||||
assert_eq!(count, DEFAULT_STREAM_DATA.len());
|
||||
assert!(!end);
|
||||
|
||||
let dgram = client.process_output(now).dgram();
|
||||
// Now send `STREAM_DATA_BLOCKED`.
|
||||
let internal_stream = server
|
||||
.send_streams
|
||||
.get_mut(StreamId::from(stream_id))
|
||||
.unwrap();
|
||||
if let SendStreamState::Send { fc, .. } = internal_stream.state() {
|
||||
fc.blocked();
|
||||
} else {
|
||||
panic!("unexpected stream state");
|
||||
}
|
||||
let dgram = server.process_output(now).dgram();
|
||||
assert!(dgram.is_some());
|
||||
|
||||
let sdb_before = client.stats().frame_rx.stream_data_blocked;
|
||||
let dgram = client.process(dgram, now).dgram();
|
||||
assert_eq!(client.stats().frame_rx.stream_data_blocked, sdb_before + 1);
|
||||
assert!(dgram.is_some());
|
||||
|
||||
// Client should have sent a MAX_STREAM_DATA frame with just a small increase
|
||||
// on the default window size.
|
||||
@ -415,7 +426,7 @@ fn stream_data_blocked_generates_max_stream_data() {
|
||||
server.process_input(dgram.unwrap(), now);
|
||||
assert_eq!(server.stats().frame_rx.max_stream_data, msd_before + 1);
|
||||
|
||||
// Test that more space is available, but that it is small.
|
||||
// Test that the entirety of the receive buffer is available now.
|
||||
let mut written = 0;
|
||||
loop {
|
||||
const LARGE_BUFFER: &[u8] = &[0; 1024];
|
||||
@ -425,7 +436,7 @@ fn stream_data_blocked_generates_max_stream_data() {
|
||||
}
|
||||
written += amount;
|
||||
}
|
||||
assert_eq!(written, RECV_BUFFER_SIZE - DEFAULT_STREAM_DATA.len());
|
||||
assert_eq!(written, RECV_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/// See <https://github.com/mozilla/neqo/issues/871>
|
||||
@ -496,7 +507,7 @@ fn no_dupdata_readable_events() {
|
||||
let _ = server.process(out.dgram(), now());
|
||||
|
||||
// We have a data_readable event.
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable {..});
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
||||
assert!(server.events().any(stream_readable));
|
||||
|
||||
// Send one more data frame from client. The previous stream data has not been read yet,
|
||||
@ -528,7 +539,7 @@ fn no_dupdata_readable_events_empty_last_frame() {
|
||||
let _ = server.process(out.dgram(), now());
|
||||
|
||||
// We have a data_readable event.
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable {..});
|
||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
||||
assert!(server.events().any(stream_readable));
|
||||
|
||||
// An empty frame with a fin will not produce a new DataReadable event, because
|
||||
|
@ -6,7 +6,8 @@
|
||||
|
||||
use super::super::Connection;
|
||||
use super::{
|
||||
connect, default_client, default_server, exchange_ticket, CountingConnectionIdGenerator,
|
||||
connect, default_client, default_server, exchange_ticket, new_server,
|
||||
CountingConnectionIdGenerator,
|
||||
};
|
||||
use crate::events::ConnectionEvent;
|
||||
use crate::{ConnectionParameters, Error, StreamType};
|
||||
@ -196,3 +197,62 @@ fn zero_rtt_send_reject() {
|
||||
server.process_input(client_after_reject.unwrap(), now());
|
||||
assert!(server.events().any(recvd_stream_evt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_rtt_update_flow_control() {
|
||||
const LOW: u64 = 3;
|
||||
const HIGH: u64 = 10;
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
const MESSAGE: &[u8] = &[0; HIGH as usize];
|
||||
|
||||
let mut client = default_client();
|
||||
let mut server = new_server(
|
||||
ConnectionParameters::default()
|
||||
.max_stream_data(StreamType::UniDi, true, LOW)
|
||||
.max_stream_data(StreamType::BiDi, true, LOW),
|
||||
);
|
||||
connect(&mut client, &mut server);
|
||||
|
||||
let token = exchange_ticket(&mut client, &mut server, now());
|
||||
let mut client = default_client();
|
||||
client
|
||||
.enable_resumption(now(), token)
|
||||
.expect("should set token");
|
||||
let mut server = new_server(
|
||||
ConnectionParameters::default()
|
||||
.max_stream_data(StreamType::UniDi, true, HIGH)
|
||||
.max_stream_data(StreamType::BiDi, true, HIGH),
|
||||
);
|
||||
|
||||
// Stream limits should be low for 0-RTT.
|
||||
let client_hs = client.process(None, now()).dgram();
|
||||
let uni_stream = client.stream_create(StreamType::UniDi).unwrap();
|
||||
assert!(!client.stream_send_atomic(uni_stream, MESSAGE).unwrap());
|
||||
let bidi_stream = client.stream_create(StreamType::BiDi).unwrap();
|
||||
assert!(!client.stream_send_atomic(bidi_stream, MESSAGE).unwrap());
|
||||
|
||||
// Now get the server transport parameters.
|
||||
let server_hs = server.process(client_hs, now()).dgram();
|
||||
client.process_input(server_hs.unwrap(), now());
|
||||
|
||||
// The streams should report a writeable event.
|
||||
let mut uni_stream_event = false;
|
||||
let mut bidi_stream_event = false;
|
||||
for e in client.events() {
|
||||
if let ConnectionEvent::SendStreamWritable { stream_id } = e {
|
||||
if stream_id.is_uni() {
|
||||
uni_stream_event = true;
|
||||
} else {
|
||||
bidi_stream_event = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(uni_stream_event);
|
||||
assert!(bidi_stream_event);
|
||||
// But no MAX_STREAM_DATA frame was received.
|
||||
assert_eq!(client.stats().frame_rx.max_stream_data, 0);
|
||||
|
||||
// And the new limit applies.
|
||||
assert!(client.stream_send_atomic(uni_stream, MESSAGE).unwrap());
|
||||
assert!(client.stream_send_atomic(bidi_stream, MESSAGE).unwrap());
|
||||
}
|
||||
|
57
third_party/rust/neqo-transport/src/crypto.rs
vendored
57
third_party/rust/neqo-transport/src/crypto.rs
vendored
@ -25,6 +25,7 @@ use crate::packet::{PacketBuilder, PacketNumber, QuicVersion};
|
||||
use crate::recovery::RecoveryToken;
|
||||
use crate::recv_stream::RxStreamOrderer;
|
||||
use crate::send_stream::TxBuffer;
|
||||
use crate::stats::FrameStats;
|
||||
use crate::tparams::{TpZeroRttChecker, TransportParameters, TransportParametersHandler};
|
||||
use crate::tracking::PNSpace;
|
||||
use crate::{Error, Res};
|
||||
@ -54,7 +55,12 @@ pub struct Crypto {
|
||||
type TpHandler = Rc<RefCell<TransportParametersHandler>>;
|
||||
|
||||
impl Crypto {
|
||||
pub fn new(mut agent: Agent, protocols: &[impl AsRef<str>], tphandler: TpHandler) -> Res<Self> {
|
||||
pub fn new(
|
||||
version: QuicVersion,
|
||||
mut agent: Agent,
|
||||
protocols: &[impl AsRef<str>],
|
||||
tphandler: TpHandler,
|
||||
) -> Res<Self> {
|
||||
agent.set_version_range(TLS_VERSION_1_3, TLS_VERSION_1_3)?;
|
||||
agent.set_ciphers(&[
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
@ -68,7 +74,16 @@ impl Crypto {
|
||||
if let Agent::Client(c) = &mut agent {
|
||||
c.enable_0rtt()?;
|
||||
}
|
||||
agent.extension_handler(0xffa5, tphandler)?;
|
||||
let extension = match version {
|
||||
QuicVersion::Version1 => 0x39,
|
||||
QuicVersion::Draft27
|
||||
| QuicVersion::Draft28
|
||||
| QuicVersion::Draft29
|
||||
| QuicVersion::Draft30
|
||||
| QuicVersion::Draft31
|
||||
| QuicVersion::Draft32 => 0xffa5,
|
||||
};
|
||||
agent.extension_handler(extension, tphandler)?;
|
||||
Ok(Self {
|
||||
tls: agent,
|
||||
streams: Default::default(),
|
||||
@ -225,6 +240,16 @@ impl Crypto {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_frame(
|
||||
&mut self,
|
||||
space: PNSpace,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
self.streams.write_frame(space, builder, tokens, stats)
|
||||
}
|
||||
|
||||
pub fn acked(&mut self, token: &CryptoRecoveryToken) {
|
||||
qinfo!(
|
||||
"Acked crypto frame space={} offset={} length={}",
|
||||
@ -358,7 +383,10 @@ impl CryptoDxState {
|
||||
label: &str,
|
||||
dcid: &[u8],
|
||||
) -> Self {
|
||||
qtrace!("new_initial for {:?}", quic_version);
|
||||
const INITIAL_SALT_V1: &[u8] = &[
|
||||
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
|
||||
0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
|
||||
];
|
||||
const INITIAL_SALT_27: &[u8] = &[
|
||||
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4,
|
||||
0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
|
||||
@ -367,7 +395,9 @@ impl CryptoDxState {
|
||||
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
|
||||
0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99,
|
||||
];
|
||||
qtrace!("new_initial for {:?}", quic_version);
|
||||
let salt = match quic_version {
|
||||
QuicVersion::Version1 => INITIAL_SALT_V1,
|
||||
QuicVersion::Draft27 | QuicVersion::Draft28 => INITIAL_SALT_27,
|
||||
QuicVersion::Draft29
|
||||
| QuicVersion::Draft30
|
||||
@ -549,7 +579,10 @@ impl CryptoDxState {
|
||||
hex(body)
|
||||
);
|
||||
// The numbers in `Self::limit` assume a maximum packet size of 2^11.
|
||||
assert!(body.len() <= 2048);
|
||||
if body.len() > 2048 {
|
||||
debug_assert!(false);
|
||||
return Err(Error::InternalError(12));
|
||||
}
|
||||
self.invoked()?;
|
||||
|
||||
let size = body.len() + MAX_AUTH_TAG;
|
||||
@ -1149,7 +1182,7 @@ impl CryptoStreams {
|
||||
*self = Self::ApplicationData {
|
||||
application: mem::take(application),
|
||||
};
|
||||
} else if matches!(self, Self::Initial {..}) {
|
||||
} else if matches!(self, Self::Initial { .. }) {
|
||||
panic!("Discarding handshake before initial discarded");
|
||||
}
|
||||
}
|
||||
@ -1241,14 +1274,16 @@ impl CryptoStreams {
|
||||
&mut self,
|
||||
space: PNSpace,
|
||||
builder: &mut PacketBuilder,
|
||||
) -> Res<Option<RecoveryToken>> {
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
let cs = self.get_mut(space).unwrap();
|
||||
if let Some((offset, data)) = cs.tx.next_bytes() {
|
||||
let mut header_len = 1 + Encoder::varint_len(offset) + 1;
|
||||
|
||||
// Don't bother if there isn't room for the header and some data.
|
||||
if builder.remaining() < header_len + 1 {
|
||||
return Ok(None);
|
||||
return Ok(());
|
||||
}
|
||||
// Calculate length of data based on the minimum of:
|
||||
// - available data
|
||||
@ -1268,14 +1303,14 @@ impl CryptoStreams {
|
||||
cs.tx.mark_as_sent(offset, length);
|
||||
|
||||
qdebug!("CRYPTO for {} offset={}, len={}", space, offset, length);
|
||||
Ok(Some(RecoveryToken::Crypto(CryptoRecoveryToken {
|
||||
tokens.push(RecoveryToken::Crypto(CryptoRecoveryToken {
|
||||
space,
|
||||
offset,
|
||||
length,
|
||||
})))
|
||||
} else {
|
||||
Ok(None)
|
||||
}));
|
||||
stats.crypto += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
441
third_party/rust/neqo-transport/src/fc.rs
vendored
Normal file
441
third_party/rust/neqo-transport/src/fc.rs
vendored
Normal file
@ -0,0 +1,441 @@
|
||||
// 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.
|
||||
|
||||
// Tracks possibly-redundant flow control signals from other code and converts
|
||||
// into flow control frames needing to be sent to the remote.
|
||||
|
||||
use crate::frame::{
|
||||
write_varint_frame, FRAME_TYPE_DATA_BLOCKED, FRAME_TYPE_MAX_DATA, FRAME_TYPE_MAX_STREAM_DATA,
|
||||
FRAME_TYPE_STREAM_DATA_BLOCKED,
|
||||
};
|
||||
use crate::packet::PacketBuilder;
|
||||
use crate::recovery::RecoveryToken;
|
||||
use crate::stats::FrameStats;
|
||||
use crate::stream_id::StreamId;
|
||||
use crate::Res;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SenderFlowControl<T>
|
||||
where
|
||||
T: Debug + Sized,
|
||||
{
|
||||
/// The thing that we're counting for.
|
||||
subject: T,
|
||||
/// The limit.
|
||||
limit: u64,
|
||||
/// How much of that limit we've used.
|
||||
used: u64,
|
||||
/// The point at which blocking occurred. This is updated each time
|
||||
/// the sender decides that it is blocked. It only ever changes
|
||||
/// when blocking occurs. This ensures that blocking at any given limit
|
||||
/// is only reported once.
|
||||
/// Note: All values are one greater than the corresponding `limit` to
|
||||
/// allow distinguishing between blocking at a limit of 0 and no blocking.
|
||||
blocked_at: u64,
|
||||
/// Whether a blocked frame should be sent.
|
||||
blocked_frame: bool,
|
||||
}
|
||||
|
||||
impl<T> SenderFlowControl<T>
|
||||
where
|
||||
T: Debug + Sized,
|
||||
{
|
||||
/// Make a new instance with the initial value and subject.
|
||||
pub fn new(subject: T, initial: u64) -> Self {
|
||||
Self {
|
||||
subject,
|
||||
limit: initial,
|
||||
used: 0,
|
||||
blocked_at: 0,
|
||||
blocked_frame: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the maximum. Returns `true` if the change was an increase.
|
||||
pub fn update(&mut self, limit: u64) -> bool {
|
||||
debug_assert!(limit < u64::MAX);
|
||||
if limit > self.limit {
|
||||
self.limit = limit;
|
||||
self.blocked_frame = false;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume flow control.
|
||||
pub fn consume(&mut self, count: usize) {
|
||||
let amt = u64::try_from(count).unwrap();
|
||||
debug_assert!(self.used + amt <= self.limit);
|
||||
self.used += amt;
|
||||
}
|
||||
|
||||
/// Get available flow control.
|
||||
pub fn available(&self) -> usize {
|
||||
usize::try_from(self.limit - self.used).unwrap_or(usize::MAX)
|
||||
}
|
||||
|
||||
/// How much data has been written.
|
||||
pub fn used(&self) -> u64 {
|
||||
self.used
|
||||
}
|
||||
|
||||
/// Mark flow control as blocked.
|
||||
/// This only does something if the current limit exceeds the last reported blocking limit.
|
||||
pub fn blocked(&mut self) {
|
||||
if self.limit >= self.blocked_at {
|
||||
self.blocked_at = self.limit + 1;
|
||||
self.blocked_frame = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether a blocking frame needs to be sent.
|
||||
/// This is `Some` with the active limit if `blocked` has been called,
|
||||
/// if a blocking frame has not been sent (or it has been lost), and
|
||||
/// if the blocking condition remains.
|
||||
fn blocked_needed(&self) -> Option<u64> {
|
||||
if self.blocked_frame && self.limit < self.blocked_at {
|
||||
Some(self.blocked_at - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the need to send a blocked frame.
|
||||
fn blocked_sent(&mut self) {
|
||||
self.blocked_frame = false;
|
||||
}
|
||||
|
||||
/// Mark a blocked frame as having been lost.
|
||||
/// Only send again if value of `self.blocked_at` hasn't increased since sending.
|
||||
/// That would imply that the limit has since increased.
|
||||
pub fn lost(&mut self, limit: u64) {
|
||||
if self.blocked_at == limit + 1 {
|
||||
self.blocked_frame = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SenderFlowControl<()> {
|
||||
pub fn write_frames(
|
||||
&mut self,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
if let Some(limit) = self.blocked_needed() {
|
||||
if write_varint_frame(builder, &[FRAME_TYPE_DATA_BLOCKED, limit])? {
|
||||
stats.data_blocked += 1;
|
||||
tokens.push(RecoveryToken::DataBlocked(limit));
|
||||
self.blocked_sent();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SenderFlowControl<StreamId> {
|
||||
pub fn write_frames(
|
||||
&mut self,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
if let Some(limit) = self.blocked_needed() {
|
||||
if write_varint_frame(
|
||||
builder,
|
||||
&[FRAME_TYPE_STREAM_DATA_BLOCKED, self.subject.as_u64(), limit],
|
||||
)? {
|
||||
stats.stream_data_blocked += 1;
|
||||
tokens.push(RecoveryToken::StreamDataBlocked {
|
||||
stream_id: self.subject,
|
||||
limit,
|
||||
});
|
||||
self.blocked_sent();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReceiverFlowControl<T>
|
||||
where
|
||||
T: Debug + Sized,
|
||||
{
|
||||
/// The thing that we're counting for.
|
||||
subject: T,
|
||||
/// The maximum amount of items that can be active (e.g., the size of the receive buffer).
|
||||
max_active: u64,
|
||||
// Last max data sent.
|
||||
max_data: u64,
|
||||
// Retired bytes.
|
||||
retired: u64,
|
||||
frame_pending: bool,
|
||||
}
|
||||
|
||||
impl<T> ReceiverFlowControl<T>
|
||||
where
|
||||
T: Debug + Sized,
|
||||
{
|
||||
/// Make a new instance with the initial value and subject.
|
||||
pub fn new(subject: T, max_bytes: u64) -> Self {
|
||||
Self {
|
||||
subject,
|
||||
max_active: max_bytes,
|
||||
max_data: max_bytes,
|
||||
retired: 0,
|
||||
frame_pending: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if received data exceeds the allowed flow control limit.
|
||||
pub fn check_allowed(&self, new_end: u64) -> bool {
|
||||
new_end <= self.max_data
|
||||
}
|
||||
|
||||
/// Some data has been read, retired them and maybe send flow control
|
||||
/// update.
|
||||
pub fn retired(&mut self, retired: u64) {
|
||||
if retired <= self.retired {
|
||||
return;
|
||||
}
|
||||
|
||||
self.retired = retired;
|
||||
if self.retired + self.max_active / 2 > self.max_data {
|
||||
self.frame_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// This function is called when STREAM_DATA_BLOCKED frame is received.
|
||||
/// The flow control willl try to send an update if possible.
|
||||
pub fn send_flowc_update(&mut self) {
|
||||
if self.retired + self.max_active > self.max_data {
|
||||
self.frame_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_data_needed(&self) -> Option<u64> {
|
||||
if self.frame_pending {
|
||||
Some(self.retired + self.max_active)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lost(&mut self, maximum_data: u64) {
|
||||
if maximum_data == self.max_data {
|
||||
self.frame_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn max_data_sent(&mut self, new_max: u64) {
|
||||
self.max_data = new_max;
|
||||
self.frame_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl ReceiverFlowControl<()> {
|
||||
pub fn write_frames(
|
||||
&mut self,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
if let Some(max_data) = self.max_data_needed() {
|
||||
if write_varint_frame(builder, &[FRAME_TYPE_MAX_DATA, max_data])? {
|
||||
stats.max_data += 1;
|
||||
tokens.push(RecoveryToken::MaxData(max_data));
|
||||
self.max_data_sent(max_data);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ReceiverFlowControl<StreamId> {
|
||||
pub fn write_frames(
|
||||
&mut self,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
if let Some(max_data) = self.max_data_needed() {
|
||||
if write_varint_frame(
|
||||
builder,
|
||||
&[FRAME_TYPE_MAX_STREAM_DATA, self.subject.as_u64(), max_data],
|
||||
)? {
|
||||
stats.max_stream_data += 1;
|
||||
tokens.push(RecoveryToken::MaxStreamData {
|
||||
stream_id: self.subject,
|
||||
max_data,
|
||||
});
|
||||
self.max_data_sent(max_data);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{ReceiverFlowControl, SenderFlowControl};
|
||||
|
||||
#[test]
|
||||
fn blocked_at_zero() {
|
||||
let mut fc = SenderFlowControl::new((), 0);
|
||||
fc.blocked();
|
||||
assert_eq!(fc.blocked_needed(), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocked() {
|
||||
let mut fc = SenderFlowControl::new((), 10);
|
||||
fc.blocked();
|
||||
assert_eq!(fc.blocked_needed(), Some(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_consume() {
|
||||
let mut fc = SenderFlowControl::new((), 10);
|
||||
fc.consume(10);
|
||||
assert_eq!(fc.available(), 0);
|
||||
fc.update(5); // An update lower than the current limit does nothing.
|
||||
assert_eq!(fc.available(), 0);
|
||||
fc.update(15);
|
||||
assert_eq!(fc.available(), 5);
|
||||
fc.consume(3);
|
||||
assert_eq!(fc.available(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_clears_blocked() {
|
||||
let mut fc = SenderFlowControl::new((), 10);
|
||||
fc.blocked();
|
||||
assert_eq!(fc.blocked_needed(), Some(10));
|
||||
fc.update(5); // An update lower than the current limit does nothing.
|
||||
assert_eq!(fc.blocked_needed(), Some(10));
|
||||
fc.update(11);
|
||||
assert_eq!(fc.blocked_needed(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lost_blocked_resent() {
|
||||
let mut fc = SenderFlowControl::new((), 10);
|
||||
fc.blocked();
|
||||
fc.blocked_sent();
|
||||
assert_eq!(fc.blocked_needed(), None);
|
||||
fc.lost(10);
|
||||
assert_eq!(fc.blocked_needed(), Some(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lost_after_increase() {
|
||||
let mut fc = SenderFlowControl::new((), 10);
|
||||
fc.blocked();
|
||||
fc.blocked_sent();
|
||||
assert_eq!(fc.blocked_needed(), None);
|
||||
fc.update(11);
|
||||
fc.lost(10);
|
||||
assert_eq!(fc.blocked_needed(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lost_after_higher_blocked() {
|
||||
let mut fc = SenderFlowControl::new((), 10);
|
||||
fc.blocked();
|
||||
fc.blocked_sent();
|
||||
fc.update(11);
|
||||
fc.blocked();
|
||||
assert_eq!(fc.blocked_needed(), Some(11));
|
||||
fc.blocked_sent();
|
||||
fc.lost(10);
|
||||
assert_eq!(fc.blocked_needed(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn do_no_need_max_data_frame_at_start() {
|
||||
let fc = ReceiverFlowControl::new((), 0);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_data_after_bytes_retired() {
|
||||
let mut fc = ReceiverFlowControl::new((), 100);
|
||||
fc.retired(49);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
fc.retired(51);
|
||||
assert_eq!(fc.max_data_needed(), Some(151));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn need_max_data_frame_after_loss() {
|
||||
let mut fc = ReceiverFlowControl::new((), 100);
|
||||
fc.retired(100);
|
||||
assert_eq!(fc.max_data_needed(), Some(200));
|
||||
fc.max_data_sent(200);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
fc.lost(200);
|
||||
assert_eq!(fc.max_data_needed(), Some(200));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_max_data_frame_after_old_loss() {
|
||||
let mut fc = ReceiverFlowControl::new((), 100);
|
||||
fc.retired(51);
|
||||
assert_eq!(fc.max_data_needed(), Some(151));
|
||||
fc.max_data_sent(151);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
fc.retired(102);
|
||||
assert_eq!(fc.max_data_needed(), Some(202));
|
||||
fc.max_data_sent(202);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
fc.lost(151);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn force_send_max_data() {
|
||||
let mut fc = ReceiverFlowControl::new((), 100);
|
||||
fc.retired(10);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_retries_after_frame_pending_is_set() {
|
||||
let mut fc = ReceiverFlowControl::new((), 100);
|
||||
fc.retired(51);
|
||||
assert_eq!(fc.max_data_needed(), Some(151));
|
||||
fc.retired(61);
|
||||
assert_eq!(fc.max_data_needed(), Some(161));
|
||||
fc.retired(88);
|
||||
assert_eq!(fc.max_data_needed(), Some(188));
|
||||
fc.retired(90);
|
||||
assert_eq!(fc.max_data_needed(), Some(190));
|
||||
fc.max_data_sent(190);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
fc.retired(141);
|
||||
assert_eq!(fc.max_data_needed(), Some(241));
|
||||
fc.max_data_sent(241);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_retired_before_loss() {
|
||||
let mut fc = ReceiverFlowControl::new((), 100);
|
||||
fc.retired(51);
|
||||
assert_eq!(fc.max_data_needed(), Some(151));
|
||||
fc.max_data_sent(151);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
fc.retired(62);
|
||||
assert_eq!(fc.max_data_needed(), None);
|
||||
fc.lost(151);
|
||||
assert_eq!(fc.max_data_needed(), Some(162));
|
||||
}
|
||||
}
|
281
third_party/rust/neqo-transport/src/flow_mgr.rs
vendored
281
third_party/rust/neqo-transport/src/flow_mgr.rs
vendored
@ -10,136 +10,27 @@
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
|
||||
use neqo_common::{qinfo, qwarn, Encoder};
|
||||
use neqo_common::qwarn;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::frame::Frame;
|
||||
use crate::frame::{write_varint_frame, Frame};
|
||||
use crate::packet::PacketBuilder;
|
||||
use crate::recovery::RecoveryToken;
|
||||
use crate::recv_stream::RecvStreams;
|
||||
use crate::send_stream::SendStreams;
|
||||
use crate::stats::FrameStats;
|
||||
use crate::stream_id::{StreamId, StreamIndex, StreamIndexes, StreamType};
|
||||
use crate::{AppError, Error, Res};
|
||||
use crate::stream_id::{StreamIndex, StreamIndexes, StreamType};
|
||||
use crate::Res;
|
||||
|
||||
type FlowFrame = Frame<'static>;
|
||||
pub type FlowControlRecoveryToken = FlowFrame;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FlowMgr {
|
||||
// Discriminant as key ensures only 1 of every frame type will be queued.
|
||||
from_conn: HashMap<mem::Discriminant<FlowFrame>, FlowFrame>,
|
||||
|
||||
// (id, discriminant) as key ensures only 1 of every frame type per stream
|
||||
// will be queued.
|
||||
from_streams: HashMap<(StreamId, mem::Discriminant<FlowFrame>), FlowFrame>,
|
||||
|
||||
// (stream_type, discriminant) as key ensures only 1 of every frame type
|
||||
// per stream type will be queued.
|
||||
from_stream_types: HashMap<(StreamType, mem::Discriminant<FlowFrame>), FlowFrame>,
|
||||
|
||||
used_data: u64,
|
||||
max_data: u64,
|
||||
}
|
||||
|
||||
impl FlowMgr {
|
||||
pub fn conn_credit_avail(&self) -> u64 {
|
||||
self.max_data - self.used_data
|
||||
}
|
||||
|
||||
pub fn conn_increase_credit_used(&mut self, amount: u64) {
|
||||
self.used_data += amount;
|
||||
assert!(self.used_data <= self.max_data)
|
||||
}
|
||||
|
||||
// Dummy DataBlocked frame for discriminant use below
|
||||
|
||||
/// Returns whether max credit was actually increased.
|
||||
pub fn conn_increase_max_credit(&mut self, new: u64) -> bool {
|
||||
const DB_FRAME: FlowFrame = Frame::DataBlocked { data_limit: 0 };
|
||||
|
||||
if new > self.max_data {
|
||||
self.max_data = new;
|
||||
self.from_conn.remove(&mem::discriminant(&DB_FRAME));
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// -- frames scoped on connection --
|
||||
|
||||
pub fn data_blocked(&mut self) {
|
||||
let frame = Frame::DataBlocked {
|
||||
data_limit: self.max_data,
|
||||
};
|
||||
self.from_conn.insert(mem::discriminant(&frame), frame);
|
||||
}
|
||||
|
||||
pub fn max_data(&mut self, maximum_data: u64) {
|
||||
let frame = Frame::MaxData { maximum_data };
|
||||
self.from_conn.insert(mem::discriminant(&frame), frame);
|
||||
}
|
||||
|
||||
// -- frames scoped on stream --
|
||||
|
||||
/// Indicate to receiving remote the stream is reset
|
||||
pub fn stream_reset(
|
||||
&mut self,
|
||||
stream_id: StreamId,
|
||||
application_error_code: AppError,
|
||||
final_size: u64,
|
||||
) {
|
||||
let frame = Frame::ResetStream {
|
||||
stream_id,
|
||||
application_error_code,
|
||||
final_size,
|
||||
};
|
||||
self.from_streams
|
||||
.insert((stream_id, mem::discriminant(&frame)), frame);
|
||||
}
|
||||
|
||||
/// Indicate to sending remote we are no longer interested in the stream
|
||||
pub fn stop_sending(&mut self, stream_id: StreamId, application_error_code: AppError) {
|
||||
let frame = Frame::StopSending {
|
||||
stream_id,
|
||||
application_error_code,
|
||||
};
|
||||
self.from_streams
|
||||
.insert((stream_id, mem::discriminant(&frame)), frame);
|
||||
}
|
||||
|
||||
/// Update sending remote with more credits
|
||||
pub fn max_stream_data(&mut self, stream_id: StreamId, maximum_stream_data: u64) {
|
||||
let frame = Frame::MaxStreamData {
|
||||
stream_id,
|
||||
maximum_stream_data,
|
||||
};
|
||||
self.from_streams
|
||||
.insert((stream_id, mem::discriminant(&frame)), frame);
|
||||
}
|
||||
|
||||
/// Don't send stream data updates if no more data is coming
|
||||
pub fn clear_max_stream_data(&mut self, stream_id: StreamId) {
|
||||
let frame = Frame::MaxStreamData {
|
||||
stream_id,
|
||||
maximum_stream_data: 0,
|
||||
};
|
||||
self.from_streams
|
||||
.remove(&(stream_id, mem::discriminant(&frame)));
|
||||
}
|
||||
|
||||
/// Indicate to receiving remote we need more credits
|
||||
pub fn stream_data_blocked(&mut self, stream_id: StreamId, stream_data_limit: u64) {
|
||||
let frame = Frame::StreamDataBlocked {
|
||||
stream_id,
|
||||
stream_data_limit,
|
||||
};
|
||||
self.from_streams
|
||||
.insert((stream_id, mem::discriminant(&frame)), frame);
|
||||
}
|
||||
|
||||
// -- frames scoped on stream type --
|
||||
|
||||
pub fn max_streams(&mut self, stream_limit: StreamIndex, stream_type: StreamType) {
|
||||
@ -161,67 +52,14 @@ impl FlowMgr {
|
||||
}
|
||||
|
||||
pub fn peek(&self) -> Option<&Frame> {
|
||||
if let Some(key) = self.from_conn.keys().next() {
|
||||
self.from_conn.get(key)
|
||||
} else if let Some(key) = self.from_streams.keys().next() {
|
||||
self.from_streams.get(key)
|
||||
} else if let Some(key) = self.from_stream_types.keys().next() {
|
||||
self.from_stream_types.get(key)
|
||||
} else {
|
||||
None
|
||||
if let Some(key) = self.from_stream_types.keys().next() {
|
||||
return self.from_stream_types.get(key);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn acked(
|
||||
&mut self,
|
||||
token: &FlowControlRecoveryToken,
|
||||
send_streams: &mut SendStreams,
|
||||
) {
|
||||
const RESET_STREAM: &Frame = &Frame::ResetStream {
|
||||
stream_id: StreamId::new(0),
|
||||
application_error_code: 0,
|
||||
final_size: 0,
|
||||
};
|
||||
|
||||
if let Frame::ResetStream { stream_id, .. } = token {
|
||||
qinfo!("Reset received stream={}", stream_id.as_u64());
|
||||
|
||||
if self
|
||||
.from_streams
|
||||
.remove(&(*stream_id, mem::discriminant(RESET_STREAM)))
|
||||
.is_some()
|
||||
{
|
||||
qinfo!("Removed RESET_STREAM frame for {}", stream_id.as_u64());
|
||||
}
|
||||
|
||||
send_streams.reset_acked(*stream_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lost(
|
||||
&mut self,
|
||||
token: &FlowControlRecoveryToken,
|
||||
send_streams: &mut SendStreams,
|
||||
recv_streams: &mut RecvStreams,
|
||||
indexes: &mut StreamIndexes,
|
||||
) {
|
||||
pub(crate) fn lost(&mut self, token: &FlowControlRecoveryToken, indexes: &mut StreamIndexes) {
|
||||
match *token {
|
||||
// Always resend ResetStream if lost
|
||||
Frame::ResetStream {
|
||||
stream_id,
|
||||
application_error_code,
|
||||
final_size,
|
||||
} => {
|
||||
qinfo!(
|
||||
"Reset lost stream={} err={} final_size={}",
|
||||
stream_id.as_u64(),
|
||||
application_error_code,
|
||||
final_size
|
||||
);
|
||||
if send_streams.get(stream_id).is_ok() {
|
||||
self.stream_reset(stream_id, application_error_code, final_size);
|
||||
}
|
||||
}
|
||||
// Resend MaxStreams if lost (with updated value)
|
||||
Frame::MaxStreams { stream_type, .. } => {
|
||||
let local_max = match stream_type {
|
||||
@ -232,18 +70,6 @@ impl FlowMgr {
|
||||
self.max_streams(*local_max, stream_type)
|
||||
}
|
||||
// Only resend "*Blocked" frames if still blocked
|
||||
Frame::DataBlocked { .. } => {
|
||||
if self.conn_credit_avail() == 0 {
|
||||
self.data_blocked()
|
||||
}
|
||||
}
|
||||
Frame::StreamDataBlocked { stream_id, .. } => {
|
||||
if let Ok(ss) = send_streams.get(stream_id) {
|
||||
if ss.credit_avail() == 0 {
|
||||
self.stream_data_blocked(stream_id, ss.max_stream_data())
|
||||
}
|
||||
}
|
||||
}
|
||||
Frame::StreamsBlocked { stream_type, .. } => match stream_type {
|
||||
StreamType::UniDi => {
|
||||
if indexes.remote_next_stream_uni >= indexes.remote_max_stream_uni {
|
||||
@ -256,18 +82,6 @@ impl FlowMgr {
|
||||
}
|
||||
}
|
||||
},
|
||||
// Resend StopSending
|
||||
Frame::StopSending {
|
||||
stream_id,
|
||||
application_error_code,
|
||||
} => self.stop_sending(stream_id, application_error_code),
|
||||
Frame::MaxStreamData { stream_id, .. } => {
|
||||
if let Some(rs) = recv_streams.get_mut(&stream_id) {
|
||||
if let Some(msd) = rs.max_stream_data() {
|
||||
self.max_stream_data(stream_id, msd)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => qwarn!("Unexpected Flow frame {:?} lost, not re-sent", token),
|
||||
}
|
||||
}
|
||||
@ -281,77 +95,21 @@ impl FlowMgr {
|
||||
while let Some(frame) = self.peek() {
|
||||
// All these frames are bags of varints, so we can just extract the
|
||||
// varints and use common code for writing.
|
||||
let values: SmallVec<[_; 3]> = match frame {
|
||||
Frame::ResetStream {
|
||||
stream_id,
|
||||
application_error_code,
|
||||
final_size,
|
||||
} => {
|
||||
stats.reset_stream += 1;
|
||||
smallvec![stream_id.as_u64(), *application_error_code, *final_size]
|
||||
}
|
||||
Frame::StopSending {
|
||||
stream_id,
|
||||
application_error_code,
|
||||
} => {
|
||||
stats.stop_sending += 1;
|
||||
smallvec![stream_id.as_u64(), *application_error_code]
|
||||
}
|
||||
|
||||
let (mut values, stat): (SmallVec<[_; 3]>, _) = match frame {
|
||||
Frame::MaxStreams {
|
||||
maximum_streams, ..
|
||||
} => {
|
||||
stats.max_streams += 1;
|
||||
smallvec![maximum_streams.as_u64()]
|
||||
}
|
||||
} => (smallvec![maximum_streams.as_u64()], &mut stats.max_streams),
|
||||
Frame::StreamsBlocked { stream_limit, .. } => {
|
||||
stats.streams_blocked += 1;
|
||||
smallvec![stream_limit.as_u64()]
|
||||
(smallvec![stream_limit.as_u64()], &mut stats.streams_blocked)
|
||||
}
|
||||
|
||||
Frame::MaxData { maximum_data } => {
|
||||
stats.max_data += 1;
|
||||
smallvec![*maximum_data]
|
||||
}
|
||||
Frame::DataBlocked { data_limit } => {
|
||||
stats.data_blocked += 1;
|
||||
smallvec![*data_limit]
|
||||
}
|
||||
|
||||
Frame::MaxStreamData {
|
||||
stream_id,
|
||||
maximum_stream_data,
|
||||
} => {
|
||||
stats.max_stream_data += 1;
|
||||
smallvec![stream_id.as_u64(), *maximum_stream_data]
|
||||
}
|
||||
Frame::StreamDataBlocked {
|
||||
stream_id,
|
||||
stream_data_limit,
|
||||
} => {
|
||||
stats.stream_data_blocked += 1;
|
||||
smallvec![stream_id.as_u64(), *stream_data_limit]
|
||||
}
|
||||
|
||||
_ => unreachable!("{:?}", frame),
|
||||
};
|
||||
values.insert(0, frame.get_type());
|
||||
debug_assert!(!values.spilled());
|
||||
|
||||
if builder.remaining()
|
||||
>= Encoder::varint_len(frame.get_type())
|
||||
+ values
|
||||
.iter()
|
||||
.map(|&v| Encoder::varint_len(v))
|
||||
.sum::<usize>()
|
||||
{
|
||||
builder.encode_varint(frame.get_type());
|
||||
for v in values {
|
||||
builder.encode_varint(v);
|
||||
}
|
||||
if builder.len() > builder.limit() {
|
||||
return Err(Error::InternalError(16));
|
||||
}
|
||||
if write_varint_frame(builder, &values)? {
|
||||
tokens.push(RecoveryToken::Flow(self.next().unwrap()));
|
||||
*stat += 1;
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
@ -365,21 +123,10 @@ impl Iterator for FlowMgr {
|
||||
|
||||
/// Used by generator to get a flow control frame.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let first_key = self.from_conn.keys().next();
|
||||
if let Some(&first_key) = first_key {
|
||||
return self.from_conn.remove(&first_key);
|
||||
}
|
||||
|
||||
let first_key = self.from_streams.keys().next();
|
||||
if let Some(&first_key) = first_key {
|
||||
return self.from_streams.remove(&first_key);
|
||||
}
|
||||
|
||||
let first_key = self.from_stream_types.keys().next();
|
||||
if let Some(&first_key) = first_key {
|
||||
return self.from_stream_types.remove(&first_key);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
63
third_party/rust/neqo-transport/src/frame.rs
vendored
63
third_party/rust/neqo-transport/src/frame.rs
vendored
@ -6,10 +6,10 @@
|
||||
|
||||
// Directly relating to QUIC frames.
|
||||
|
||||
use neqo_common::{qtrace, Decoder};
|
||||
use neqo_common::{qtrace, Decoder, Encoder};
|
||||
|
||||
use crate::cid::MAX_CONNECTION_ID_LEN;
|
||||
use crate::packet::PacketType;
|
||||
use crate::packet::{PacketBuilder, PacketType};
|
||||
use crate::stream_id::{StreamId, StreamIndex, StreamType};
|
||||
use crate::{AppError, ConnectionError, Error, Res, TransportError};
|
||||
|
||||
@ -23,20 +23,20 @@ const FRAME_TYPE_PADDING: FrameType = 0x0;
|
||||
pub const FRAME_TYPE_PING: FrameType = 0x1;
|
||||
pub const FRAME_TYPE_ACK: FrameType = 0x2;
|
||||
const FRAME_TYPE_ACK_ECN: FrameType = 0x3;
|
||||
const FRAME_TYPE_RST_STREAM: FrameType = 0x4;
|
||||
const FRAME_TYPE_STOP_SENDING: FrameType = 0x5;
|
||||
pub const FRAME_TYPE_RESET_STREAM: FrameType = 0x4;
|
||||
pub const FRAME_TYPE_STOP_SENDING: FrameType = 0x5;
|
||||
pub const FRAME_TYPE_CRYPTO: FrameType = 0x6;
|
||||
pub const FRAME_TYPE_NEW_TOKEN: FrameType = 0x7;
|
||||
const FRAME_TYPE_STREAM: FrameType = 0x8;
|
||||
const FRAME_TYPE_STREAM_MAX: FrameType = 0xf;
|
||||
const FRAME_TYPE_MAX_DATA: FrameType = 0x10;
|
||||
const FRAME_TYPE_MAX_STREAM_DATA: FrameType = 0x11;
|
||||
const FRAME_TYPE_MAX_STREAMS_BIDI: FrameType = 0x12;
|
||||
const FRAME_TYPE_MAX_STREAMS_UNIDI: FrameType = 0x13;
|
||||
const FRAME_TYPE_DATA_BLOCKED: FrameType = 0x14;
|
||||
const FRAME_TYPE_STREAM_DATA_BLOCKED: FrameType = 0x15;
|
||||
const FRAME_TYPE_STREAMS_BLOCKED_BIDI: FrameType = 0x16;
|
||||
const FRAME_TYPE_STREAMS_BLOCKED_UNIDI: FrameType = 0x17;
|
||||
pub const FRAME_TYPE_MAX_DATA: FrameType = 0x10;
|
||||
pub const FRAME_TYPE_MAX_STREAM_DATA: FrameType = 0x11;
|
||||
pub const FRAME_TYPE_MAX_STREAMS_BIDI: FrameType = 0x12;
|
||||
pub const FRAME_TYPE_MAX_STREAMS_UNIDI: FrameType = 0x13;
|
||||
pub const FRAME_TYPE_DATA_BLOCKED: FrameType = 0x14;
|
||||
pub const FRAME_TYPE_STREAM_DATA_BLOCKED: FrameType = 0x15;
|
||||
pub const FRAME_TYPE_STREAMS_BLOCKED_BIDI: FrameType = 0x16;
|
||||
pub const FRAME_TYPE_STREAMS_BLOCKED_UNIDI: FrameType = 0x17;
|
||||
pub const FRAME_TYPE_NEW_CONNECTION_ID: FrameType = 0x18;
|
||||
pub const FRAME_TYPE_RETIRE_CONNECTION_ID: FrameType = 0x19;
|
||||
pub const FRAME_TYPE_PATH_CHALLENGE: FrameType = 0x1a;
|
||||
@ -93,6 +93,26 @@ pub struct AckRange {
|
||||
pub(crate) range: u64,
|
||||
}
|
||||
|
||||
/// A lot of frames here are just a collection of varints.
|
||||
/// This helper functions writes a frame like that safely, returning `true` if
|
||||
/// a frame was written.
|
||||
pub fn write_varint_frame(builder: &mut PacketBuilder, values: &[u64]) -> Res<bool> {
|
||||
let write = builder.remaining()
|
||||
>= values
|
||||
.iter()
|
||||
.map(|&v| Encoder::varint_len(v))
|
||||
.sum::<usize>();
|
||||
if write {
|
||||
for v in values {
|
||||
builder.encode_varint(*v);
|
||||
}
|
||||
if builder.len() > builder.limit() {
|
||||
return Err(Error::InternalError(16));
|
||||
}
|
||||
};
|
||||
Ok(write)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Frame<'a> {
|
||||
Padding,
|
||||
@ -194,7 +214,7 @@ impl<'a> Frame<'a> {
|
||||
Self::Padding => FRAME_TYPE_PADDING,
|
||||
Self::Ping => FRAME_TYPE_PING,
|
||||
Self::Ack { .. } => FRAME_TYPE_ACK, // We don't do ACK ECN.
|
||||
Self::ResetStream { .. } => FRAME_TYPE_RST_STREAM,
|
||||
Self::ResetStream { .. } => FRAME_TYPE_RESET_STREAM,
|
||||
Self::StopSending { .. } => FRAME_TYPE_STOP_SENDING,
|
||||
Self::Crypto { .. } => FRAME_TYPE_CRYPTO,
|
||||
Self::NewToken { .. } => FRAME_TYPE_NEW_TOKEN,
|
||||
@ -239,17 +259,22 @@ impl<'a> Frame<'a> {
|
||||
/// If the frame causes a recipient to generate an ACK within its
|
||||
/// advertised maximum acknowledgement delay.
|
||||
pub fn ack_eliciting(&self) -> bool {
|
||||
!matches!(self, Self::Ack { .. } | Self::Padding | Self::ConnectionClose { .. })
|
||||
!matches!(
|
||||
self,
|
||||
Self::Ack { .. } | Self::Padding | Self::ConnectionClose { .. }
|
||||
)
|
||||
}
|
||||
|
||||
/// If the frame can be sent in a path probe
|
||||
/// without initiating migration to that path.
|
||||
pub fn path_probing(&self) -> bool {
|
||||
matches!(self,
|
||||
matches!(
|
||||
self,
|
||||
Self::Padding
|
||||
| Self::NewConnectionId { .. }
|
||||
| Self::PathChallenge { .. }
|
||||
| Self::PathResponse { .. })
|
||||
| Self::NewConnectionId { .. }
|
||||
| Self::PathChallenge { .. }
|
||||
| Self::PathResponse { .. }
|
||||
)
|
||||
}
|
||||
|
||||
/// Converts AckRanges as encoded in a ACK frame (see -transport
|
||||
@ -348,7 +373,7 @@ impl<'a> Frame<'a> {
|
||||
match t {
|
||||
FRAME_TYPE_PADDING => Ok(Self::Padding),
|
||||
FRAME_TYPE_PING => Ok(Self::Ping),
|
||||
FRAME_TYPE_RST_STREAM => Ok(Self::ResetStream {
|
||||
FRAME_TYPE_RESET_STREAM => Ok(Self::ResetStream {
|
||||
stream_id: StreamId::from(dv(dec)?),
|
||||
application_error_code: d(dec.decode_varint())?,
|
||||
final_size: match dec.decode_varint() {
|
||||
|
3
third_party/rust/neqo-transport/src/lib.rs
vendored
3
third_party/rust/neqo-transport/src/lib.rs
vendored
@ -16,6 +16,7 @@ mod connection;
|
||||
mod crypto;
|
||||
mod dump;
|
||||
mod events;
|
||||
mod fc;
|
||||
mod flow_mgr;
|
||||
mod frame;
|
||||
mod pace;
|
||||
@ -24,6 +25,7 @@ mod path;
|
||||
mod qlog;
|
||||
mod recovery;
|
||||
mod recv_stream;
|
||||
mod rtt;
|
||||
mod send_stream;
|
||||
mod sender;
|
||||
pub mod server;
|
||||
@ -41,7 +43,6 @@ pub use self::connection::{params::ConnectionParameters, Connection, Output, Sta
|
||||
pub use self::events::{ConnectionEvent, ConnectionEvents};
|
||||
pub use self::frame::CloseError;
|
||||
pub use self::packet::QuicVersion;
|
||||
pub use self::sender::PacketSender;
|
||||
pub use self::stats::Stats;
|
||||
pub use self::stream_id::{StreamId, StreamType};
|
||||
|
||||
|
8
third_party/rust/neqo-transport/src/pace.rs
vendored
8
third_party/rust/neqo-transport/src/pace.rs
vendored
@ -37,14 +37,14 @@ pub struct Pacer {
|
||||
}
|
||||
|
||||
impl Pacer {
|
||||
/// Create a new `Pacer`. This takes the current time and the
|
||||
/// initial congestion window.
|
||||
/// Create a new `Pacer`. This takes the current time, the maximum burst size,
|
||||
/// and the packet size.
|
||||
///
|
||||
/// The value of `m` is the maximum capacity. `m` primes the pacer
|
||||
/// The value of `m` is the maximum capacity in bytes. `m` primes the pacer
|
||||
/// with credit and determines the burst size. `m` must not exceed
|
||||
/// the initial congestion window, but it should probably be lower.
|
||||
///
|
||||
/// The value of `p` is the packet size, which determines the minimum
|
||||
/// The value of `p` is the packet size in bytes, which determines the minimum
|
||||
/// credit needed before a packet is sent. This should be a substantial
|
||||
/// fraction of the maximum packet size, if not the packet size.
|
||||
pub fn new(now: Instant, m: usize, p: usize) -> Self {
|
||||
|
208
third_party/rust/neqo-transport/src/packet/mod.rs
vendored
208
third_party/rust/neqo-transport/src/packet/mod.rs
vendored
@ -91,6 +91,7 @@ impl From<CryptoSpace> for PacketType {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum QuicVersion {
|
||||
Version1,
|
||||
Draft27,
|
||||
Draft28,
|
||||
Draft29,
|
||||
@ -102,6 +103,7 @@ pub enum QuicVersion {
|
||||
impl QuicVersion {
|
||||
pub fn as_u32(self) -> Version {
|
||||
match self {
|
||||
Self::Version1 => 1,
|
||||
Self::Draft27 => 0xff00_0000 + 27,
|
||||
Self::Draft28 => 0xff00_0000 + 28,
|
||||
Self::Draft29 => 0xff00_0000 + 29,
|
||||
@ -114,7 +116,7 @@ impl QuicVersion {
|
||||
|
||||
impl Default for QuicVersion {
|
||||
fn default() -> Self {
|
||||
Self::Draft29
|
||||
Self::Version1
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +124,9 @@ impl TryFrom<Version> for QuicVersion {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(ver: Version) -> Res<Self> {
|
||||
if ver == 0xff00_0000 + 27 {
|
||||
if ver == 1 {
|
||||
Ok(Self::Version1)
|
||||
} else if ver == 0xff00_0000 + 27 {
|
||||
Ok(Self::Draft27)
|
||||
} else if ver == 0xff00_0000 + 28 {
|
||||
Ok(Self::Draft28)
|
||||
@ -157,6 +161,8 @@ pub struct PacketBuilder {
|
||||
header: Range<usize>,
|
||||
offsets: PacketBuilderOffsets,
|
||||
limit: usize,
|
||||
/// Whether to pad the packet before construction.
|
||||
padding: bool,
|
||||
}
|
||||
|
||||
impl PacketBuilder {
|
||||
@ -169,13 +175,28 @@ impl PacketBuilder {
|
||||
}
|
||||
|
||||
/// Start building a short header packet.
|
||||
///
|
||||
/// This doesn't fail if there isn't enough space; instead it returns a builder that
|
||||
/// has no available space left. This allows the caller to extract the encoder
|
||||
/// and any packets that might have been added before as adding a packet header is
|
||||
/// only likely to fail if there are other packets already written.
|
||||
///
|
||||
/// If, after calling this method, `remaining()` returns 0, then call `abort()` to get
|
||||
/// the encoder back.
|
||||
#[allow(clippy::unknown_clippy_lints)] // Until we require rust 1.45.
|
||||
#[allow(clippy::reversed_empty_ranges)]
|
||||
pub fn short(mut encoder: Encoder, key_phase: bool, dcid: impl AsRef<[u8]>) -> Self {
|
||||
let mut limit = Self::infer_limit(&encoder);
|
||||
let header_start = encoder.len();
|
||||
encoder.encode_byte(PACKET_BIT_SHORT | PACKET_BIT_FIXED_QUIC | (u8::from(key_phase) << 2));
|
||||
encoder.encode(dcid.as_ref());
|
||||
let limit = Self::infer_limit(&encoder);
|
||||
// Check that there is enough space for the header.
|
||||
// 5 = 1 (first byte) + 4 (packet number)
|
||||
if limit > encoder.len() && 5 + dcid.as_ref().len() < limit - encoder.len() {
|
||||
encoder
|
||||
.encode_byte(PACKET_BIT_SHORT | PACKET_BIT_FIXED_QUIC | (u8::from(key_phase) << 2));
|
||||
encoder.encode(dcid.as_ref());
|
||||
} else {
|
||||
limit = 0;
|
||||
}
|
||||
Self {
|
||||
encoder,
|
||||
pn: u64::max_value(),
|
||||
@ -186,12 +207,15 @@ impl PacketBuilder {
|
||||
len: 0,
|
||||
},
|
||||
limit,
|
||||
padding: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Start building a long header packet.
|
||||
/// For an Initial packet you will need to call initial_token(),
|
||||
/// even if the token is empty.
|
||||
///
|
||||
/// See `short()` for more on how to handle this in cases where there is no space.
|
||||
#[allow(clippy::unknown_clippy_lints)] // Until we require rust 1.45.
|
||||
#[allow(clippy::reversed_empty_ranges)] // For initializing an empty range.
|
||||
pub fn long(
|
||||
@ -201,12 +225,21 @@ impl PacketBuilder {
|
||||
dcid: impl AsRef<[u8]>,
|
||||
scid: impl AsRef<[u8]>,
|
||||
) -> Self {
|
||||
let mut limit = Self::infer_limit(&encoder);
|
||||
let header_start = encoder.len();
|
||||
encoder.encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC | pt.code() << 4);
|
||||
encoder.encode_uint(4, quic_version.as_u32());
|
||||
encoder.encode_vec(1, dcid.as_ref());
|
||||
encoder.encode_vec(1, scid.as_ref());
|
||||
let limit = Self::infer_limit(&encoder);
|
||||
// Check that there is enough space for the header.
|
||||
// 11 = 1 (first byte) + 4 (version) + 2 (dcid+scid length) + 4 (packet number)
|
||||
if limit > encoder.len()
|
||||
&& 11 + dcid.as_ref().len() + scid.as_ref().len() < limit - encoder.len()
|
||||
{
|
||||
encoder.encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC | pt.code() << 4);
|
||||
encoder.encode_uint(4, quic_version.as_u32());
|
||||
encoder.encode_vec(1, dcid.as_ref());
|
||||
encoder.encode_vec(1, scid.as_ref());
|
||||
} else {
|
||||
limit = 0;
|
||||
}
|
||||
|
||||
Self {
|
||||
encoder,
|
||||
pn: u64::max_value(),
|
||||
@ -217,6 +250,7 @@ impl PacketBuilder {
|
||||
len: 0,
|
||||
},
|
||||
limit,
|
||||
padding: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,22 +272,29 @@ impl PacketBuilder {
|
||||
/// How many bytes remain against the size limit for the builder.
|
||||
#[must_use]
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.limit - self.encoder.len()
|
||||
self.limit.saturating_sub(self.encoder.len())
|
||||
}
|
||||
|
||||
/// Pad with "PADDING" frames.
|
||||
pub fn pad(&mut self) -> Res<()> {
|
||||
self.encoder.pad_to(self.limit, 0);
|
||||
if self.len() > self.limit {
|
||||
qwarn!("Packet contents are more than the limit");
|
||||
debug_assert!(false);
|
||||
return Err(Error::InternalError(17));
|
||||
/// Mark the packet as needing padding (or not).
|
||||
pub fn enable_padding(&mut self, needs_padding: bool) {
|
||||
self.padding = needs_padding;
|
||||
}
|
||||
|
||||
/// Maybe pad with "PADDING" frames.
|
||||
/// Only does so if padding was needed and this is a short packet.
|
||||
/// Returns true if padding was added.
|
||||
pub fn pad(&mut self) -> bool {
|
||||
if self.padding && !self.is_long() {
|
||||
self.encoder.pad_to(self.limit, 0);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add unpredictable values for unprotected parts of the packet.
|
||||
pub fn scramble(&mut self, quic_bit: bool) {
|
||||
debug_assert!(self.len() > self.header.start);
|
||||
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;
|
||||
@ -262,25 +303,29 @@ impl PacketBuilder {
|
||||
|
||||
/// For an Initial packet, encode the token.
|
||||
/// If you fail to do this, then you will not get a valid packet.
|
||||
pub fn initial_token(&mut self, token: &[u8]) -> Res<()> {
|
||||
pub fn initial_token(&mut self, token: &[u8]) {
|
||||
debug_assert_eq!(
|
||||
self.encoder[self.header.start] & 0xb0,
|
||||
PACKET_BIT_LONG | PACKET_TYPE_INITIAL << 4
|
||||
);
|
||||
self.encoder.encode_vvec(token);
|
||||
|
||||
if self.len() > self.limit {
|
||||
qwarn!("Packet contents are more than the limit");
|
||||
debug_assert!(false);
|
||||
return Err(Error::InternalError(18));
|
||||
if Encoder::vvec_len(token.len()) < self.remaining() {
|
||||
self.encoder.encode_vvec(token);
|
||||
} else {
|
||||
self.limit = 0;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a packet number of the given size.
|
||||
/// For a long header packet, this also inserts a dummy length.
|
||||
/// The length is filled in after calling `build`.
|
||||
pub fn pn(&mut self, pn: PacketNumber, pn_len: usize) -> Res<()> {
|
||||
/// Does nothing if there isn't 4 bytes available other than render this builder
|
||||
/// unusable; if `remaining()` returns 0 at any point, call `abort()`.
|
||||
pub fn pn(&mut self, pn: PacketNumber, pn_len: usize) {
|
||||
if self.remaining() < 4 {
|
||||
self.limit = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reserve space for a length in long headers.
|
||||
if self.is_long() {
|
||||
self.offsets.len = self.encoder.len();
|
||||
@ -299,13 +344,6 @@ impl PacketBuilder {
|
||||
self.encoder[self.header.start] |= u8::try_from(pn_len - 1).unwrap();
|
||||
self.header.end = self.encoder.len();
|
||||
self.pn = pn;
|
||||
|
||||
if self.len() > self.limit {
|
||||
qwarn!("Packet contents are more than the limit");
|
||||
debug_assert!(false);
|
||||
return Err(Error::InternalError(19));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_len(&mut self, expansion: usize) {
|
||||
@ -424,6 +462,7 @@ impl PacketBuilder {
|
||||
encoder.encode(&[0; 4]); // Zero version == VN.
|
||||
encoder.encode_vec(1, dcid);
|
||||
encoder.encode_vec(1, scid);
|
||||
encoder.encode_uint(4, QuicVersion::Version1.as_u32());
|
||||
encoder.encode_uint(4, QuicVersion::Draft27.as_u32());
|
||||
encoder.encode_uint(4, QuicVersion::Draft28.as_u32());
|
||||
encoder.encode_uint(4, QuicVersion::Draft29.as_u32());
|
||||
@ -850,15 +889,15 @@ mod tests {
|
||||
0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
|
||||
];
|
||||
const SAMPLE_INITIAL: &[u8] = &[
|
||||
0xc7, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0x00, 0x40, 0x75, 0xfb, 0x12, 0xff, 0x07, 0x82, 0x3a, 0x5d, 0x24, 0x53, 0x4d, 0x90, 0x6c,
|
||||
0xe4, 0xc7, 0x67, 0x82, 0xa2, 0x16, 0x7e, 0x34, 0x79, 0xc0, 0xf7, 0xf6, 0x39, 0x5d, 0xc2,
|
||||
0xc9, 0x16, 0x76, 0x30, 0x2f, 0xe6, 0xd7, 0x0b, 0xb7, 0xcb, 0xeb, 0x11, 0x7b, 0x4d, 0xdb,
|
||||
0x7d, 0x17, 0x34, 0x98, 0x44, 0xfd, 0x61, 0xda, 0xe2, 0x00, 0xb8, 0x33, 0x8e, 0x1b, 0x93,
|
||||
0x29, 0x76, 0xb6, 0x1d, 0x91, 0xe6, 0x4a, 0x02, 0xe9, 0xe0, 0xee, 0x72, 0xe3, 0xa6, 0xf6,
|
||||
0x3a, 0xba, 0x4c, 0xee, 0xee, 0xc5, 0xbe, 0x2f, 0x24, 0xf2, 0xd8, 0x60, 0x27, 0x57, 0x29,
|
||||
0x43, 0x53, 0x38, 0x46, 0xca, 0xa1, 0x3e, 0x6f, 0x16, 0x3f, 0xb2, 0x57, 0x47, 0x3d, 0xcc,
|
||||
0xa2, 0x53, 0x96, 0xe8, 0x87, 0x24, 0xf1, 0xe5, 0xd9, 0x64, 0xde, 0xde, 0xe9, 0xb6, 0x33,
|
||||
0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0x00, 0x40, 0x75, 0xc0, 0xd9, 0x5a, 0x48, 0x2c, 0xd0, 0x99, 0x1c, 0xd2, 0x5b, 0x0a, 0xac,
|
||||
0x40, 0x6a, 0x58, 0x16, 0xb6, 0x39, 0x41, 0x00, 0xf3, 0x7a, 0x1c, 0x69, 0x79, 0x75, 0x54,
|
||||
0x78, 0x0b, 0xb3, 0x8c, 0xc5, 0xa9, 0x9f, 0x5e, 0xde, 0x4c, 0xf7, 0x3c, 0x3e, 0xc2, 0x49,
|
||||
0x3a, 0x18, 0x39, 0xb3, 0xdb, 0xcb, 0xa3, 0xf6, 0xea, 0x46, 0xc5, 0xb7, 0x68, 0x4d, 0xf3,
|
||||
0x54, 0x8e, 0x7d, 0xde, 0xb9, 0xc3, 0xbf, 0x9c, 0x73, 0xcc, 0x3f, 0x3b, 0xde, 0xd7, 0x4b,
|
||||
0x56, 0x2b, 0xfb, 0x19, 0xfb, 0x84, 0x02, 0x2f, 0x8e, 0xf4, 0xcd, 0xd9, 0x37, 0x95, 0xd7,
|
||||
0x7d, 0x06, 0xed, 0xbb, 0x7a, 0xaf, 0x2f, 0x58, 0x89, 0x18, 0x50, 0xab, 0xbd, 0xca, 0x3d,
|
||||
0x20, 0x39, 0x8c, 0x27, 0x64, 0x56, 0xcb, 0xc4, 0x21, 0x58, 0x40, 0x7d, 0xd0, 0x74, 0xee,
|
||||
];
|
||||
|
||||
#[test]
|
||||
@ -878,8 +917,8 @@ mod tests {
|
||||
&ConnectionId::from(&[][..]),
|
||||
&ConnectionId::from(SERVER_CID),
|
||||
);
|
||||
builder.initial_token(&[]).unwrap();
|
||||
builder.pn(1, 2).unwrap();
|
||||
builder.initial_token(&[]);
|
||||
builder.pn(1, 2);
|
||||
builder.encode(&SAMPLE_INITIAL_PAYLOAD);
|
||||
let packet = builder.build(&mut prot).expect("build");
|
||||
assert_eq!(&packet[..], SAMPLE_INITIAL);
|
||||
@ -930,8 +969,8 @@ mod tests {
|
||||
}
|
||||
|
||||
const SAMPLE_SHORT: &[u8] = &[
|
||||
0x55, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x99, 0x9c, 0xbd, 0x77, 0xf5, 0xd7,
|
||||
0x0a, 0x28, 0xe8, 0xfb, 0xc3, 0xed, 0xf5, 0x71, 0xb1, 0x04, 0x32, 0x2a, 0xae, 0xae,
|
||||
0x40, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0xf4, 0xa8, 0x30, 0x39, 0xc4, 0x7d,
|
||||
0x99, 0xe3, 0x94, 0x1c, 0x9b, 0xb9, 0x7a, 0x30, 0x1d, 0xd5, 0x8f, 0xf3, 0xdd, 0xa9,
|
||||
];
|
||||
const SAMPLE_SHORT_PAYLOAD: &[u8] = &[0; 3];
|
||||
|
||||
@ -940,7 +979,7 @@ mod tests {
|
||||
fixture_init();
|
||||
let mut builder =
|
||||
PacketBuilder::short(Encoder::new(), true, &ConnectionId::from(SERVER_CID));
|
||||
builder.pn(0, 1).unwrap();
|
||||
builder.pn(0, 1);
|
||||
builder.encode(SAMPLE_SHORT_PAYLOAD); // Enough payload for sampling.
|
||||
let packet = builder
|
||||
.build(&mut CryptoDxState::test_default())
|
||||
@ -956,7 +995,7 @@ mod tests {
|
||||
let mut builder =
|
||||
PacketBuilder::short(Encoder::new(), true, &ConnectionId::from(SERVER_CID));
|
||||
builder.scramble(true);
|
||||
builder.pn(0, 1).unwrap();
|
||||
builder.pn(0, 1);
|
||||
firsts.push(builder[0]);
|
||||
}
|
||||
let is_set = |bit| move |v| v & bit == bit;
|
||||
@ -1019,14 +1058,14 @@ mod tests {
|
||||
&ConnectionId::from(SERVER_CID),
|
||||
&ConnectionId::from(CLIENT_CID),
|
||||
);
|
||||
builder.pn(0, 1).unwrap();
|
||||
builder.pn(0, 1);
|
||||
builder.encode(&[0; 3]);
|
||||
let encoder = builder.build(&mut prot).expect("build");
|
||||
assert_eq!(encoder.len(), 45);
|
||||
let first = encoder.clone();
|
||||
|
||||
let mut builder = PacketBuilder::short(encoder, false, &ConnectionId::from(SERVER_CID));
|
||||
builder.pn(1, 3).unwrap();
|
||||
builder.pn(1, 3);
|
||||
builder.encode(&[0]); // Minimal size (packet number is big enough).
|
||||
let encoder = builder.build(&mut prot).expect("build");
|
||||
assert_eq!(
|
||||
@ -1040,9 +1079,9 @@ mod tests {
|
||||
#[test]
|
||||
fn build_long() {
|
||||
const EXPECTED: &[u8] = &[
|
||||
0xe5, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x40, 0x14, 0xa8, 0x9d, 0xbf, 0x74, 0x70,
|
||||
0x32, 0xda, 0xba, 0xfb, 0x87, 0x61, 0xb8, 0x31, 0x90, 0xf3, 0x25, 0x52, 0x0b, 0xbe,
|
||||
0xdb,
|
||||
0xe4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40, 0x14, 0xfb, 0xa9, 0x32, 0x3a, 0xf8,
|
||||
0xbb, 0x18, 0x63, 0xc6, 0xbd, 0x78, 0x0e, 0xba, 0x0c, 0x98, 0x65, 0x58, 0xc9, 0x62,
|
||||
0x31,
|
||||
];
|
||||
|
||||
fixture_init();
|
||||
@ -1053,7 +1092,7 @@ mod tests {
|
||||
&ConnectionId::from(&[][..]),
|
||||
&ConnectionId::from(&[][..]),
|
||||
);
|
||||
builder.pn(0, 1).unwrap();
|
||||
builder.pn(0, 1);
|
||||
builder.encode(&[1, 2, 3]);
|
||||
let packet = builder.build(&mut CryptoDxState::test_default()).unwrap();
|
||||
assert_eq!(&packet[..], EXPECTED);
|
||||
@ -1072,7 +1111,7 @@ mod tests {
|
||||
&ConnectionId::from(&[][..]),
|
||||
&ConnectionId::from(&[][..]),
|
||||
);
|
||||
builder.pn(0, 1).unwrap();
|
||||
builder.pn(0, 1);
|
||||
builder.scramble(true);
|
||||
if (builder[0] & PACKET_BIT_FIXED_QUIC) == 0 {
|
||||
found_unset = true;
|
||||
@ -1093,12 +1132,49 @@ mod tests {
|
||||
&ConnectionId::from(&[][..]),
|
||||
&ConnectionId::from(SERVER_CID),
|
||||
);
|
||||
builder.initial_token(&[]).unwrap();
|
||||
builder.pn(1, 2).unwrap();
|
||||
assert_ne!(builder.remaining(), 0);
|
||||
builder.initial_token(&[]);
|
||||
assert_ne!(builder.remaining(), 0);
|
||||
builder.pn(1, 2);
|
||||
assert_ne!(builder.remaining(), 0);
|
||||
let encoder = builder.abort();
|
||||
assert!(encoder.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_insufficient_space() {
|
||||
fixture_init();
|
||||
|
||||
let mut builder = PacketBuilder::short(
|
||||
Encoder::with_capacity(100),
|
||||
true,
|
||||
&ConnectionId::from(SERVER_CID),
|
||||
);
|
||||
builder.pn(0, 1);
|
||||
// Pad, but not up to the full capacity. Leave enough space for the
|
||||
// AEAD expansion and some extra, but not for an entire long header.
|
||||
builder.set_limit(75);
|
||||
builder.enable_padding(true);
|
||||
assert!(builder.pad());
|
||||
let encoder = builder.build(&mut CryptoDxState::test_default()).unwrap();
|
||||
let encoder_copy = encoder.clone();
|
||||
|
||||
let builder = PacketBuilder::long(
|
||||
encoder,
|
||||
PacketType::Initial,
|
||||
QuicVersion::default(),
|
||||
&ConnectionId::from(SERVER_CID),
|
||||
&ConnectionId::from(SERVER_CID),
|
||||
);
|
||||
assert_eq!(builder.remaining(), 0);
|
||||
assert_eq!(builder.abort(), encoder_copy);
|
||||
}
|
||||
|
||||
const SAMPLE_RETRY_V1: &[u8] = &[
|
||||
0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x04, 0xa2, 0x65, 0xba, 0x2e, 0xff, 0x4d, 0x82, 0x90, 0x58,
|
||||
0xfb, 0x3f, 0x0f, 0x24, 0x96, 0xba,
|
||||
];
|
||||
const SAMPLE_RETRY_27: &[u8] = &[
|
||||
0xff, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xa5, 0x23, 0xcb, 0x5b, 0xa5, 0x24, 0x69, 0x5f, 0x65, 0x69,
|
||||
@ -1158,6 +1234,11 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_retry_v1() {
|
||||
build_retry_single(QuicVersion::Version1, SAMPLE_RETRY_V1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_retry_27() {
|
||||
build_retry_single(QuicVersion::Draft27, SAMPLE_RETRY_27);
|
||||
@ -1194,10 +1275,13 @@ mod tests {
|
||||
// Odds are approximately 1 in 8 that the full comparison doesn't happen
|
||||
// for a given version.
|
||||
for _ in 0..32 {
|
||||
build_retry_v1();
|
||||
build_retry_27();
|
||||
build_retry_28();
|
||||
build_retry_29();
|
||||
build_retry_30();
|
||||
build_retry_31();
|
||||
build_retry_32();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1278,9 +1362,9 @@ mod tests {
|
||||
|
||||
const SAMPLE_VN: &[u8] = &[
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x08,
|
||||
0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0xff, 0x00, 0x00, 0x1b, 0xff, 0x00, 0x00,
|
||||
0x1c, 0xff, 0x00, 0x00, 0x1d, 0xff, 0x00, 0x00, 0x1e, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x00,
|
||||
0x00, 0x20, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||
0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00,
|
||||
0x1b, 0xff, 0x00, 0x00, 0x1c, 0xff, 0x00, 0x00, 0x1d, 0xff, 0x00, 0x00, 0x1e, 0xff, 0x00,
|
||||
0x00, 0x1f, 0xff, 0x00, 0x00, 0x20, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||
];
|
||||
|
||||
#[test]
|
||||
|
@ -22,6 +22,10 @@ const RETRY_SECRET_29: &[u8] = &[
|
||||
0x8b, 0x0d, 0x37, 0xeb, 0x85, 0x35, 0x02, 0x2e, 0xbc, 0x8d, 0x76, 0xa2, 0x07, 0xd8, 0x0d, 0xf2,
|
||||
0x26, 0x46, 0xec, 0x06, 0xdc, 0x80, 0x96, 0x42, 0xc3, 0x0a, 0x8b, 0xaa, 0x2b, 0xaa, 0xff, 0x4c,
|
||||
];
|
||||
const RETRY_SECRET_V1: &[u8] = &[
|
||||
0xd9, 0xc9, 0x94, 0x3e, 0x61, 0x01, 0xfd, 0x20, 0x00, 0x21, 0x50, 0x6b, 0xcc, 0x02, 0x81, 0x4c,
|
||||
0x73, 0x03, 0x0f, 0x25, 0xc7, 0x9d, 0x71, 0xce, 0x87, 0x6e, 0xca, 0x87, 0x6e, 0x6f, 0xca, 0x8e,
|
||||
];
|
||||
|
||||
/// The AEAD used for Retry is fixed, so use thread local storage.
|
||||
fn make_aead(secret: &[u8]) -> Aead {
|
||||
@ -33,6 +37,7 @@ fn make_aead(secret: &[u8]) -> Aead {
|
||||
}
|
||||
thread_local!(static RETRY_AEAD_27: RefCell<Aead> = RefCell::new(make_aead(RETRY_SECRET_27)));
|
||||
thread_local!(static RETRY_AEAD_29: RefCell<Aead> = RefCell::new(make_aead(RETRY_SECRET_29)));
|
||||
thread_local!(static RETRY_AEAD_V1: RefCell<Aead> = RefCell::new(make_aead(RETRY_SECRET_V1)));
|
||||
|
||||
/// Run a function with the appropriate Retry AEAD.
|
||||
pub fn use_aead<F, T>(quic_version: QuicVersion, f: F) -> Res<T>
|
||||
@ -40,6 +45,7 @@ where
|
||||
F: FnOnce(&Aead) -> Res<T>,
|
||||
{
|
||||
match quic_version {
|
||||
QuicVersion::Version1 => &RETRY_AEAD_V1,
|
||||
QuicVersion::Draft27 | QuicVersion::Draft28 => &RETRY_AEAD_27,
|
||||
QuicVersion::Draft29
|
||||
| QuicVersion::Draft30
|
||||
|
184
third_party/rust/neqo-transport/src/path.rs
vendored
184
third_party/rust/neqo-transport/src/path.rs
vendored
@ -10,20 +10,25 @@
|
||||
use std::cell::RefCell;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Display};
|
||||
use std::mem;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::rc::Rc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::cc::CongestionControlAlgorithm;
|
||||
use crate::cid::{ConnectionId, ConnectionIdRef, RemoteConnectionIdEntry};
|
||||
use crate::frame::{
|
||||
FRAME_TYPE_PATH_CHALLENGE, FRAME_TYPE_PATH_RESPONSE, FRAME_TYPE_RETIRE_CONNECTION_ID,
|
||||
};
|
||||
use crate::packet::PacketBuilder;
|
||||
use crate::recovery::RecoveryToken;
|
||||
use crate::rtt::RttEstimate;
|
||||
use crate::sender::PacketSender;
|
||||
use crate::stats::FrameStats;
|
||||
use crate::tracking::{PNSpace, SentPacket};
|
||||
use crate::{Error, Res};
|
||||
|
||||
use neqo_common::{hex, qdebug, qinfo, qtrace, Datagram, Encoder};
|
||||
use neqo_common::{hex, qdebug, qinfo, qlog::NeqoQlog, qtrace, Datagram, Encoder};
|
||||
use neqo_crypto::random;
|
||||
|
||||
/// This is the MTU that we assume when using IPv6.
|
||||
@ -61,12 +66,21 @@ pub struct Paths {
|
||||
|
||||
/// Connection IDs that need to be retired.
|
||||
to_retire: Vec<u64>,
|
||||
|
||||
/// QLog handler.
|
||||
qlog: NeqoQlog,
|
||||
}
|
||||
|
||||
impl Paths {
|
||||
/// Find the path for the given addresses.
|
||||
/// This might be a temporary path.
|
||||
pub fn find_path(&self, local: SocketAddr, remote: SocketAddr) -> PathRef {
|
||||
pub fn find_path(
|
||||
&self,
|
||||
local: SocketAddr,
|
||||
remote: SocketAddr,
|
||||
cc: CongestionControlAlgorithm,
|
||||
now: Instant,
|
||||
) -> PathRef {
|
||||
self.paths
|
||||
.iter()
|
||||
.find_map(|p| {
|
||||
@ -76,14 +90,26 @@ impl Paths {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| Rc::new(RefCell::new(Path::temporary(local, remote))))
|
||||
.unwrap_or_else(|| {
|
||||
let mut p = Path::temporary(local, remote, cc, self.qlog.clone(), now);
|
||||
if let Some(primary) = self.primary.as_ref() {
|
||||
p.set_initial_rtt(primary.borrow().rtt().estimate());
|
||||
}
|
||||
Rc::new(RefCell::new(p))
|
||||
})
|
||||
}
|
||||
|
||||
/// Find the path, but allow for rebinding. That matches the pair of addresses
|
||||
/// to paths that match the remote address only based on IP addres, not port.
|
||||
/// We use this when the other side migrates to skip address validation and
|
||||
/// creating a new path.
|
||||
pub fn find_path_with_rebinding(&self, local: SocketAddr, remote: SocketAddr) -> PathRef {
|
||||
pub fn find_path_with_rebinding(
|
||||
&self,
|
||||
local: SocketAddr,
|
||||
remote: SocketAddr,
|
||||
cc: CongestionControlAlgorithm,
|
||||
now: Instant,
|
||||
) -> PathRef {
|
||||
self.paths
|
||||
.iter()
|
||||
.find_map(|p| {
|
||||
@ -102,7 +128,15 @@ impl Paths {
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| Rc::new(RefCell::new(Path::temporary(local, remote))))
|
||||
.unwrap_or_else(|| {
|
||||
Rc::new(RefCell::new(Path::temporary(
|
||||
local,
|
||||
remote,
|
||||
cc,
|
||||
self.qlog.clone(),
|
||||
now,
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a reference to the primary path. This will assert if there is no primary
|
||||
@ -188,15 +222,18 @@ impl Paths {
|
||||
/// is forcibly marked as valid and the path is used immediately.
|
||||
/// Otherwise, migration will occur after probing succeeds.
|
||||
/// The path is always probed and will be abandoned if probing fails.
|
||||
pub fn migrate(&mut self, path: &PathRef, force: bool, now: Instant) {
|
||||
/// Returns `true` if the path was migrated.
|
||||
pub fn migrate(&mut self, path: &PathRef, force: bool, now: Instant) -> bool {
|
||||
debug_assert!(!self.is_temporary(path));
|
||||
if force || path.borrow().is_valid() {
|
||||
path.borrow_mut().set_valid(now);
|
||||
let _ = self.select_primary(path);
|
||||
mem::drop(self.select_primary(path));
|
||||
self.migration_target = None;
|
||||
} else {
|
||||
self.migration_target = Some(Rc::clone(path));
|
||||
}
|
||||
path.borrow_mut().probe();
|
||||
self.migration_target.is_none()
|
||||
}
|
||||
|
||||
/// Process elapsed time for active paths.
|
||||
@ -232,7 +269,7 @@ impl Paths {
|
||||
// Need a clone as `fallback` is borrowed from `self`.
|
||||
let path = Rc::clone(fallback);
|
||||
qinfo!([path.borrow()], "Failing over after primary path failed");
|
||||
let _ = self.select_primary(&path);
|
||||
mem::drop(self.select_primary(&path));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -289,7 +326,11 @@ impl Paths {
|
||||
}
|
||||
|
||||
/// A `PATH_RESPONSE` was received.
|
||||
pub fn path_response(&mut self, response: [u8; 8], now: Instant) {
|
||||
/// Returns `true` if migration occurred.
|
||||
#[must_use]
|
||||
pub fn path_response(&mut self, response: [u8; 8], now: Instant) -> bool {
|
||||
// TODO(mt) consider recording an RTT measurement here as we don't train
|
||||
// RTT for non-primary paths.
|
||||
for p in &self.paths {
|
||||
if p.borrow_mut().path_response(response, now) {
|
||||
// The response was accepted. If this path is one we intend
|
||||
@ -300,11 +341,13 @@ impl Paths {
|
||||
.map_or(false, |target| Rc::ptr_eq(target, p))
|
||||
{
|
||||
let primary = self.migration_target.take();
|
||||
let _ = self.select_primary(&primary.unwrap());
|
||||
mem::drop(self.select_primary(&primary.unwrap()));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Write out any `RETIRE_CONNECTION_ID` frames that are outstanding.
|
||||
@ -337,6 +380,26 @@ impl Paths {
|
||||
pub fn acked_retire_cid(&mut self, acked: u64) {
|
||||
self.to_retire.retain(|&seqno| seqno != acked);
|
||||
}
|
||||
|
||||
/// Get an estimate of the RTT on the primary path.
|
||||
#[cfg(test)]
|
||||
pub fn rtt(&self) -> Duration {
|
||||
// Rather than have this fail when there is no active path,
|
||||
// make a new RTT esimate and interrogate that.
|
||||
// That is more expensive, but it should be rare and breaking encapsulation
|
||||
// is worse, especially as this is only used in tests.
|
||||
self.primary_fallible()
|
||||
.map_or(RttEstimate::default().estimate(), |p| {
|
||||
p.borrow().rtt().estimate()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_qlog(&mut self, qlog: NeqoQlog) {
|
||||
for p in &mut self.paths {
|
||||
p.borrow_mut().set_qlog(qlog.clone());
|
||||
}
|
||||
self.qlog = qlog;
|
||||
}
|
||||
}
|
||||
|
||||
/// The state of a path with respect to address validation.
|
||||
@ -399,6 +462,11 @@ pub struct Path {
|
||||
/// A path challenge was received and PATH_RESPONSE has not been sent.
|
||||
challenge: Option<[u8; 8]>,
|
||||
|
||||
/// The round trip time estimate for this path.
|
||||
rtt: RttEstimate,
|
||||
/// A packet sender for the path, which includes congestion control and a pacer.
|
||||
sender: PacketSender,
|
||||
|
||||
/// The number of bytes received on this path.
|
||||
/// Note that this value might saturate on a long-lived connection,
|
||||
/// but we only use it before the path is validated.
|
||||
@ -410,7 +478,15 @@ pub struct Path {
|
||||
impl Path {
|
||||
/// Create a path from addresses and a remote connection ID.
|
||||
/// This is used for migration and for new datagrams.
|
||||
pub fn temporary(local: SocketAddr, remote: SocketAddr) -> Self {
|
||||
pub fn temporary(
|
||||
local: SocketAddr,
|
||||
remote: SocketAddr,
|
||||
cc: CongestionControlAlgorithm,
|
||||
qlog: NeqoQlog,
|
||||
now: Instant,
|
||||
) -> Self {
|
||||
let mut sender = PacketSender::new(cc, Self::mtu_by_addr(remote.ip()), now);
|
||||
sender.set_qlog(qlog);
|
||||
Self {
|
||||
local,
|
||||
remote,
|
||||
@ -420,6 +496,8 @@ impl Path {
|
||||
state: ProbeState::ProbeNeeded { probe_count: 0 },
|
||||
validated: None,
|
||||
challenge: None,
|
||||
rtt: RttEstimate::default(),
|
||||
sender,
|
||||
received_bytes: 0,
|
||||
sent_bytes: 0,
|
||||
}
|
||||
@ -438,7 +516,7 @@ impl Path {
|
||||
/// By adding a remote connection ID, we make the path permanent
|
||||
/// and one that we will later send packets on.
|
||||
/// If `local_cid` is `None`, the existing value will be kept.
|
||||
fn make_permanent(
|
||||
pub(crate) fn make_permanent(
|
||||
&mut self,
|
||||
local_cid: Option<ConnectionId>,
|
||||
remote_cid: RemoteConnectionIdEntry,
|
||||
@ -465,9 +543,13 @@ impl Path {
|
||||
}
|
||||
|
||||
/// Set whether this path is primary.
|
||||
fn set_primary(&mut self, primary: bool) {
|
||||
pub(crate) fn set_primary(&mut self, primary: bool) {
|
||||
qtrace!([self], "Make primary {}", primary);
|
||||
debug_assert!(self.remote_cid.is_some());
|
||||
self.primary = primary;
|
||||
if !primary {
|
||||
self.sender.discard_in_flight();
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the current path as valid. This updates the time that the path was
|
||||
@ -486,14 +568,18 @@ impl Path {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the path MTU. This is currently a fixed value.
|
||||
pub fn mtu(&self) -> usize {
|
||||
match self.local.ip() {
|
||||
fn mtu_by_addr(addr: IpAddr) -> usize {
|
||||
match addr {
|
||||
IpAddr::V4(_) => PATH_MTU_V4,
|
||||
IpAddr::V6(_) => PATH_MTU_V6,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the path MTU. This is currently fixed based on IP version.
|
||||
pub fn mtu(&self) -> usize {
|
||||
Self::mtu_by_addr(self.remote.ip())
|
||||
}
|
||||
|
||||
/// Get the first local connection ID.
|
||||
/// Only do this for the primary path during the handshake.
|
||||
pub fn local_cid(&self) -> &ConnectionId {
|
||||
@ -695,6 +781,31 @@ impl Path {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the RTT estimator for this path.
|
||||
pub fn rtt(&self) -> &RttEstimate {
|
||||
&self.rtt
|
||||
}
|
||||
|
||||
/// Mutably borrow the RTT estimator for this path.
|
||||
pub fn rtt_mut(&mut self) -> &mut RttEstimate {
|
||||
&mut self.rtt
|
||||
}
|
||||
|
||||
/// Read-only access to the owned sender.
|
||||
pub fn sender(&self) -> &PacketSender {
|
||||
&self.sender
|
||||
}
|
||||
|
||||
/// Pass on RTT configuration: the maximum acknowledgment delay of the peer.
|
||||
pub fn set_max_ack_delay(&mut self, mad: Duration) {
|
||||
self.rtt.set_max_ack_delay(mad);
|
||||
}
|
||||
|
||||
/// Initialize the RTT for the path based on an existing estimate.
|
||||
pub fn set_initial_rtt(&mut self, rtt: Duration) {
|
||||
self.rtt.set_initial(rtt);
|
||||
}
|
||||
|
||||
/// Record received bytes for the path.
|
||||
pub fn add_received(&mut self, count: usize) {
|
||||
self.received_bytes = self.received_bytes.saturating_add(count);
|
||||
@ -705,6 +816,42 @@ impl Path {
|
||||
self.sent_bytes = self.sent_bytes.saturating_add(count);
|
||||
}
|
||||
|
||||
/// Record a packet as having been sent on this path.
|
||||
pub fn packet_sent(&mut self, sent: &mut SentPacket) {
|
||||
if !self.is_primary() {
|
||||
sent.clear_primary_path();
|
||||
}
|
||||
self.sender.on_packet_sent(sent, self.rtt.estimate());
|
||||
}
|
||||
|
||||
/// Discard a packet that previously might have been in-flight.
|
||||
pub fn discard_packet(&mut self, sent: &SentPacket) {
|
||||
self.sender.discard(sent);
|
||||
}
|
||||
|
||||
/// Record packets as acknowledged with the sender.
|
||||
pub fn on_packets_acked(&mut self, acked_pkts: &[SentPacket], now: Instant) {
|
||||
debug_assert!(self.is_primary());
|
||||
self.sender
|
||||
.on_packets_acked(acked_pkts, self.rtt.minimum(), now);
|
||||
}
|
||||
|
||||
/// Record packets as lost with the sender.
|
||||
pub fn on_packets_lost(
|
||||
&mut self,
|
||||
prev_largest_acked_sent: Option<Instant>,
|
||||
space: PNSpace,
|
||||
lost_packets: &[SentPacket],
|
||||
) {
|
||||
debug_assert!(self.is_primary());
|
||||
self.sender.on_packets_lost(
|
||||
self.rtt.first_sample_time(),
|
||||
prev_largest_acked_sent,
|
||||
self.rtt.pto(space), // Important: the base PTO, not adjusted.
|
||||
lost_packets,
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the number of bytes that can be written to this path.
|
||||
pub fn amplification_limit(&self) -> usize {
|
||||
if matches!(self.state, ProbeState::Failed) {
|
||||
@ -726,6 +873,11 @@ impl Path {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the `NeqoQLog` instance.
|
||||
pub fn set_qlog(&mut self, qlog: NeqoQlog) {
|
||||
self.sender.set_qlog(qlog);
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Path {
|
||||
|
667
third_party/rust/neqo-transport/src/recovery.rs
vendored
667
third_party/rust/neqo-transport/src/recovery.rs
vendored
File diff suppressed because it is too large
Load Diff
283
third_party/rust/neqo-transport/src/recv_stream.rs
vendored
283
third_party/rust/neqo-transport/src/recv_stream.rs
vendored
@ -12,23 +12,89 @@ use std::cmp::max;
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::Bound::{Included, Unbounded};
|
||||
use std::rc::Rc;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::events::ConnectionEvents;
|
||||
use crate::fc::ReceiverFlowControl;
|
||||
use crate::flow_mgr::FlowMgr;
|
||||
use crate::frame::{write_varint_frame, FRAME_TYPE_STOP_SENDING};
|
||||
use crate::packet::PacketBuilder;
|
||||
use crate::recovery::RecoveryToken;
|
||||
use crate::send_stream::SendStreams;
|
||||
use crate::stats::FrameStats;
|
||||
use crate::stream_id::StreamId;
|
||||
use crate::{AppError, Error, Res};
|
||||
use neqo_common::qtrace;
|
||||
use neqo_common::{qtrace, Role};
|
||||
|
||||
const RX_STREAM_DATA_WINDOW: u64 = 0x10_0000; // 1MiB
|
||||
|
||||
// Export as usize for consistency with SEND_BUFFER_SIZE
|
||||
pub const RECV_BUFFER_SIZE: usize = RX_STREAM_DATA_WINDOW as usize;
|
||||
|
||||
pub(crate) type RecvStreams = BTreeMap<StreamId, RecvStream>;
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct RecvStreams(BTreeMap<StreamId, RecvStream>);
|
||||
|
||||
impl RecvStreams {
|
||||
pub fn write_frames(
|
||||
&mut self,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
for stream in self.0.values_mut() {
|
||||
stream.write_frame(builder, tokens, stats)?;
|
||||
if builder.remaining() < 2 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, id: StreamId, stream: RecvStream) {
|
||||
self.0.insert(id, stream);
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: StreamId) -> Res<&mut RecvStream> {
|
||||
self.0.get_mut(&id).ok_or(Error::InvalidStreamId)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
}
|
||||
|
||||
pub fn clear_terminal(&mut self, send_streams: &SendStreams, role: Role) -> (u64, u64) {
|
||||
let recv_to_remove = self
|
||||
.0
|
||||
.iter()
|
||||
.filter_map(|(id, stream)| {
|
||||
// Remove all streams for which the receiving is done (or aborted).
|
||||
// But only if they are unidirectional, or we have finished sending.
|
||||
if stream.is_terminal() && (id.is_uni() || !send_streams.exists(*id)) {
|
||||
Some(*id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut removed_bidi = 0;
|
||||
let mut removed_uni = 0;
|
||||
for id in &recv_to_remove {
|
||||
self.0.remove(&id);
|
||||
if id.is_remote_initiated(role) {
|
||||
if id.is_bidi() {
|
||||
removed_bidi += 1;
|
||||
} else {
|
||||
removed_uni += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(removed_bidi, removed_uni)
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds data not yet read by application. Orders and dedupes data ranges
|
||||
/// from incoming STREAM frames.
|
||||
@ -69,10 +135,8 @@ impl RxStreamOrderer {
|
||||
return;
|
||||
}
|
||||
|
||||
let extend = if let Some((&prev_start, prev_vec)) = self
|
||||
.data_ranges
|
||||
.range_mut((Unbounded, Included(new_start)))
|
||||
.next_back()
|
||||
let extend = if let Some((&prev_start, prev_vec)) =
|
||||
self.data_ranges.range_mut(..=new_start).next_back()
|
||||
{
|
||||
let prev_end = prev_start + u64::try_from(prev_vec.len()).unwrap();
|
||||
if new_end > prev_end {
|
||||
@ -150,7 +214,7 @@ impl RxStreamOrderer {
|
||||
if extend {
|
||||
let (_, buf) = self
|
||||
.data_ranges
|
||||
.range_mut((Unbounded, Included(new_start)))
|
||||
.range_mut(..=new_start)
|
||||
.next_back()
|
||||
.unwrap();
|
||||
buf.extend_from_slice(to_add);
|
||||
@ -270,9 +334,8 @@ impl RxStreamOrderer {
|
||||
// Because a dead_code warning is easier than clippy::unused_self, see https://github.com/rust-lang/rust/issues/68408
|
||||
enum RecvStreamState {
|
||||
Recv {
|
||||
fc: ReceiverFlowControl<StreamId>,
|
||||
recv_buf: RxStreamOrderer,
|
||||
max_bytes: u64, // Maximum size of recv_buf
|
||||
max_stream_data: u64,
|
||||
},
|
||||
SizeKnown {
|
||||
recv_buf: RxStreamOrderer,
|
||||
@ -282,16 +345,19 @@ enum RecvStreamState {
|
||||
recv_buf: RxStreamOrderer,
|
||||
},
|
||||
DataRead,
|
||||
AbortReading {
|
||||
frame_needed: bool,
|
||||
err: AppError,
|
||||
},
|
||||
ResetRecvd,
|
||||
// Defined by spec but we don't use it: ResetRead
|
||||
}
|
||||
|
||||
impl RecvStreamState {
|
||||
fn new(max_bytes: u64) -> Self {
|
||||
fn new(max_bytes: u64, stream_id: StreamId) -> Self {
|
||||
Self::Recv {
|
||||
fc: ReceiverFlowControl::new(stream_id, max_bytes),
|
||||
recv_buf: RxStreamOrderer::new(),
|
||||
max_bytes,
|
||||
max_stream_data: max_bytes,
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,6 +367,7 @@ impl RecvStreamState {
|
||||
Self::SizeKnown { .. } => "SizeKnown",
|
||||
Self::DataRecvd { .. } => "DataRecvd",
|
||||
Self::DataRead => "DataRead",
|
||||
Self::AbortReading { .. } => "AbortReading",
|
||||
Self::ResetRecvd => "ResetRecvd",
|
||||
}
|
||||
}
|
||||
@ -310,7 +377,7 @@ impl RecvStreamState {
|
||||
Self::Recv { recv_buf, .. }
|
||||
| Self::SizeKnown { recv_buf, .. }
|
||||
| Self::DataRecvd { recv_buf } => Some(recv_buf),
|
||||
Self::DataRead | Self::ResetRecvd => None,
|
||||
Self::DataRead | Self::AbortReading { .. } | Self::ResetRecvd => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,15 +387,6 @@ impl RecvStreamState {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn max_stream_data(&self) -> Option<u64> {
|
||||
match self {
|
||||
Self::Recv {
|
||||
max_stream_data, ..
|
||||
} => Some(*max_stream_data),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement a QUIC receive stream.
|
||||
@ -349,7 +407,7 @@ impl RecvStream {
|
||||
) -> Self {
|
||||
Self {
|
||||
stream_id,
|
||||
state: RecvStreamState::new(max_stream_data),
|
||||
state: RecvStreamState::new(max_stream_data, stream_id),
|
||||
flow_mgr,
|
||||
conn_events,
|
||||
}
|
||||
@ -367,12 +425,6 @@ impl RecvStream {
|
||||
new_state.name()
|
||||
);
|
||||
|
||||
if let RecvStreamState::Recv { .. } = &self.state {
|
||||
self.flow_mgr
|
||||
.borrow_mut()
|
||||
.clear_max_stream_data(self.stream_id)
|
||||
}
|
||||
|
||||
if let RecvStreamState::DataRead = new_state {
|
||||
self.conn_events.recv_stream_complete(self.stream_id);
|
||||
}
|
||||
@ -394,13 +446,9 @@ impl RecvStream {
|
||||
}
|
||||
|
||||
match &mut self.state {
|
||||
RecvStreamState::Recv {
|
||||
recv_buf,
|
||||
max_stream_data,
|
||||
..
|
||||
} => {
|
||||
if new_end > *max_stream_data {
|
||||
qtrace!("Stream RX window {} exceeded: {}", max_stream_data, new_end);
|
||||
RecvStreamState::Recv { recv_buf, fc, .. } => {
|
||||
if !fc.check_allowed(new_end) {
|
||||
qtrace!("Stream RX window exceeded: {}", new_end);
|
||||
return Err(Error::FlowControlError);
|
||||
}
|
||||
|
||||
@ -436,6 +484,7 @@ impl RecvStream {
|
||||
}
|
||||
RecvStreamState::DataRecvd { .. }
|
||||
| RecvStreamState::DataRead
|
||||
| RecvStreamState::AbortReading { .. }
|
||||
| RecvStreamState::ResetRecvd => {
|
||||
qtrace!("data received when we are in state {}", self.state.name())
|
||||
}
|
||||
@ -450,7 +499,9 @@ impl RecvStream {
|
||||
|
||||
pub fn reset(&mut self, application_error_code: AppError) {
|
||||
match self.state {
|
||||
RecvStreamState::Recv { .. } | RecvStreamState::SizeKnown { .. } => {
|
||||
RecvStreamState::Recv { .. }
|
||||
| RecvStreamState::SizeKnown { .. }
|
||||
| RecvStreamState::AbortReading { .. } => {
|
||||
self.conn_events
|
||||
.recv_stream_reset(self.stream_id, application_error_code);
|
||||
self.set_state(RecvStreamState::ResetRecvd);
|
||||
@ -464,29 +515,18 @@ impl RecvStream {
|
||||
/// If we should tell the sender they have more credit, return an offset
|
||||
pub fn maybe_send_flowc_update(&mut self) {
|
||||
// Only ever needed if actively receiving and not in SizeKnown state
|
||||
if let RecvStreamState::Recv {
|
||||
max_bytes,
|
||||
max_stream_data,
|
||||
recv_buf,
|
||||
} = &mut self.state
|
||||
{
|
||||
// Algo: send an update if app has consumed more than half
|
||||
// the data in the current window
|
||||
// TODO(agrover@mozilla.com): This algo is not great but
|
||||
// should prevent Silly Window Syndrome. Spec refers to using
|
||||
// highest seen offset somehow? RTT maybe?
|
||||
let maybe_new_max = recv_buf.retired() + *max_bytes;
|
||||
if maybe_new_max > (*max_bytes / 2) + *max_stream_data {
|
||||
*max_stream_data = maybe_new_max;
|
||||
self.flow_mgr
|
||||
.borrow_mut()
|
||||
.max_stream_data(self.stream_id, maybe_new_max)
|
||||
}
|
||||
if let RecvStreamState::Recv { fc, recv_buf } = &mut self.state {
|
||||
fc.retired(recv_buf.retired());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_stream_data(&self) -> Option<u64> {
|
||||
self.state.max_stream_data()
|
||||
/// Send a flow control update.
|
||||
/// This is used when a peer declares that they are blocked.
|
||||
/// This sends `MAX_STREAM_DATA` if there is any increase possible.
|
||||
pub fn send_flowc_update(&mut self) {
|
||||
if let RecvStreamState::Recv { fc, .. } = &mut self.state {
|
||||
fc.send_flowc_update();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_terminal(&self) -> bool {
|
||||
@ -521,7 +561,9 @@ impl RecvStream {
|
||||
}
|
||||
Ok((bytes_read, fin_read))
|
||||
}
|
||||
RecvStreamState::DataRead | RecvStreamState::ResetRecvd => Err(Error::NoMoreData),
|
||||
RecvStreamState::DataRead
|
||||
| RecvStreamState::AbortReading { .. }
|
||||
| RecvStreamState::ResetRecvd => Err(Error::NoMoreData),
|
||||
};
|
||||
self.maybe_send_flowc_update();
|
||||
res
|
||||
@ -531,21 +573,82 @@ impl RecvStream {
|
||||
qtrace!("stop_sending called when in state {}", self.state.name());
|
||||
match &self.state {
|
||||
RecvStreamState::Recv { .. } | RecvStreamState::SizeKnown { .. } => {
|
||||
self.set_state(RecvStreamState::ResetRecvd);
|
||||
self.flow_mgr.borrow_mut().stop_sending(self.stream_id, err)
|
||||
self.set_state(RecvStreamState::AbortReading {
|
||||
frame_needed: true,
|
||||
err,
|
||||
})
|
||||
}
|
||||
RecvStreamState::DataRecvd { .. } => self.set_state(RecvStreamState::DataRead),
|
||||
RecvStreamState::DataRead | RecvStreamState::ResetRecvd => {
|
||||
RecvStreamState::DataRead
|
||||
| RecvStreamState::AbortReading { .. }
|
||||
| RecvStreamState::ResetRecvd => {
|
||||
// Already in terminal state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Maybe write a `MAX_STREAM_DATA` frame.
|
||||
pub fn write_frame(
|
||||
&mut self,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<()> {
|
||||
match &mut self.state {
|
||||
// Maybe send MAX_STREAM_DATA
|
||||
RecvStreamState::Recv { fc, .. } => fc.write_frames(builder, tokens, stats)?,
|
||||
// Maybe send STOP_SENDING
|
||||
RecvStreamState::AbortReading { frame_needed, err } => {
|
||||
if *frame_needed
|
||||
&& write_varint_frame(
|
||||
builder,
|
||||
&[FRAME_TYPE_STOP_SENDING, self.stream_id.as_u64(), *err],
|
||||
)?
|
||||
{
|
||||
tokens.push(RecoveryToken::StopSending {
|
||||
stream_id: self.stream_id,
|
||||
});
|
||||
stats.stop_sending += 1;
|
||||
*frame_needed = false;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn max_stream_data_lost(&mut self, maximum_data: u64) {
|
||||
if let RecvStreamState::Recv { fc, .. } = &mut self.state {
|
||||
fc.lost(maximum_data);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop_sending_lost(&mut self) {
|
||||
if let RecvStreamState::AbortReading { frame_needed, .. } = &mut self.state {
|
||||
*frame_needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop_sending_acked(&mut self) {
|
||||
if let RecvStreamState::AbortReading { .. } = &mut self.state {
|
||||
self.set_state(RecvStreamState::ResetRecvd);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn has_frames_to_write(&self) -> bool {
|
||||
if let RecvStreamState::Recv { fc, .. } = &self.state {
|
||||
fc.max_data_needed().is_some()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::frame::Frame;
|
||||
use neqo_common::Encoder;
|
||||
use std::ops::Range;
|
||||
|
||||
fn recv_ranges(ranges: &[Range<u64>], available: usize) {
|
||||
@ -980,23 +1083,26 @@ mod tests {
|
||||
let mut buf = vec![0u8; RECV_BUFFER_SIZE + 100]; // Make it overlarge
|
||||
|
||||
s.maybe_send_flowc_update();
|
||||
assert_eq!(s.flow_mgr.borrow().peek(), None);
|
||||
assert!(!s.has_frames_to_write());
|
||||
s.inbound_stream_frame(false, 0, &frame1).unwrap();
|
||||
s.maybe_send_flowc_update();
|
||||
assert_eq!(s.flow_mgr.borrow().peek(), None);
|
||||
assert!(!s.has_frames_to_write());
|
||||
assert_eq!(s.read(&mut buf).unwrap(), (RECV_BUFFER_SIZE, false));
|
||||
assert_eq!(s.data_ready(), false);
|
||||
s.maybe_send_flowc_update();
|
||||
|
||||
// flow msg generated!
|
||||
assert!(s.flow_mgr.borrow().peek().is_some());
|
||||
assert!(s.has_frames_to_write());
|
||||
|
||||
// consume it
|
||||
s.flow_mgr.borrow_mut().next().unwrap();
|
||||
let mut builder = PacketBuilder::short(Encoder::new(), false, &[]);
|
||||
let mut token = Vec::new();
|
||||
s.write_frame(&mut builder, &mut token, &mut FrameStats::default())
|
||||
.unwrap();
|
||||
|
||||
// it should be gone
|
||||
s.maybe_send_flowc_update();
|
||||
assert_eq!(s.flow_mgr.borrow().peek(), None);
|
||||
assert!(!s.has_frames_to_write());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1013,7 +1119,7 @@ mod tests {
|
||||
);
|
||||
|
||||
s.maybe_send_flowc_update();
|
||||
assert_eq!(s.flow_mgr.borrow().peek(), None);
|
||||
assert!(!s.has_frames_to_write());
|
||||
s.inbound_stream_frame(false, 0, &frame1).unwrap();
|
||||
s.inbound_stream_frame(false, RX_STREAM_DATA_WINDOW, &[1; 1])
|
||||
.unwrap_err();
|
||||
@ -1069,42 +1175,11 @@ mod tests {
|
||||
);
|
||||
|
||||
s.inbound_stream_frame(false, 0, &frame1).unwrap();
|
||||
flow_mgr.borrow_mut().max_stream_data(stream_id, 100);
|
||||
assert!(matches!(s.flow_mgr.borrow().peek().unwrap(), Frame::MaxStreamData{..}));
|
||||
let mut buf = [0; RECV_BUFFER_SIZE];
|
||||
s.read(&mut buf).unwrap();
|
||||
assert!(s.has_frames_to_write());
|
||||
s.inbound_stream_frame(true, RX_STREAM_DATA_WINDOW, &[])
|
||||
.unwrap();
|
||||
assert!(matches!(s.flow_mgr.borrow().peek(), None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resend_flowc_if_lost() {
|
||||
let flow_mgr = Rc::new(RefCell::new(FlowMgr::default()));
|
||||
let conn_events = ConnectionEvents::default();
|
||||
|
||||
let frame1 = &[0; RECV_BUFFER_SIZE];
|
||||
let stream_id = StreamId::from(67);
|
||||
let mut s = RecvStream::new(
|
||||
stream_id,
|
||||
RX_STREAM_DATA_WINDOW,
|
||||
Rc::clone(&flow_mgr),
|
||||
conn_events,
|
||||
);
|
||||
|
||||
// A flow control update is queued
|
||||
s.inbound_stream_frame(false, 0, frame1).unwrap();
|
||||
flow_mgr.borrow_mut().max_stream_data(stream_id, 100);
|
||||
// Generates frame
|
||||
assert!(matches!(
|
||||
s.flow_mgr.borrow_mut().next().unwrap(),
|
||||
Frame::MaxStreamData { .. }
|
||||
));
|
||||
// Nothing else queued
|
||||
assert!(matches!(s.flow_mgr.borrow().peek(), None));
|
||||
// Asking for another one won't get you one
|
||||
s.maybe_send_flowc_update();
|
||||
assert!(matches!(s.flow_mgr.borrow().peek(), None));
|
||||
// But if lost, another frame is generated
|
||||
flow_mgr.borrow_mut().max_stream_data(stream_id, 100);
|
||||
assert!(matches!(s.flow_mgr.borrow_mut().next().unwrap(), Frame::MaxStreamData{..}));
|
||||
assert!(!s.has_frames_to_write());
|
||||
}
|
||||
}
|
||||
|
169
third_party/rust/neqo-transport/src/rtt.rs
vendored
Normal file
169
third_party/rust/neqo-transport/src/rtt.rs
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
// 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.
|
||||
|
||||
// Tracking of sent packets and detecting their loss.
|
||||
|
||||
#![deny(clippy::pedantic)]
|
||||
|
||||
use std::cmp::{max, min};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use neqo_common::{qlog::NeqoQlog, qtrace};
|
||||
|
||||
use crate::qlog::{self, QlogMetric};
|
||||
use crate::tracking::PNSpace;
|
||||
|
||||
/// The smallest time that the system timer (via `sleep()`, `nanosleep()`,
|
||||
/// `select()`, or similar) can reliably deliver; see `neqo_common::hrtime`.
|
||||
const GRANULARITY: Duration = Duration::from_millis(1);
|
||||
/// The default value for the maximum time a peer can delay acknowledgment
|
||||
/// of an ack-eliciting packet.
|
||||
const DEFAULT_MAX_ACK_DELAY: Duration = Duration::from_millis(25);
|
||||
// Defined in -recovery 6.2 as 333ms but using lower value.
|
||||
const INITIAL_RTT: Duration = Duration::from_millis(100);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub struct RttEstimate {
|
||||
first_sample_time: Option<Instant>,
|
||||
latest_rtt: Duration,
|
||||
smoothed_rtt: Duration,
|
||||
rttvar: Duration,
|
||||
min_rtt: Duration,
|
||||
max_ack_delay: Duration,
|
||||
}
|
||||
|
||||
impl RttEstimate {
|
||||
pub fn set_initial(&mut self, rtt: Duration) {
|
||||
qtrace!("initial RTT={:?}", rtt);
|
||||
if rtt >= GRANULARITY {
|
||||
// Ignore if the value is too small.
|
||||
self.init(rtt)
|
||||
}
|
||||
}
|
||||
|
||||
fn init(&mut self, rtt: Duration) {
|
||||
// Only allow this when there are no samples.
|
||||
debug_assert!(self.first_sample_time.is_none());
|
||||
self.latest_rtt = rtt;
|
||||
self.min_rtt = rtt;
|
||||
self.smoothed_rtt = rtt;
|
||||
self.rttvar = rtt / 2;
|
||||
}
|
||||
|
||||
pub fn set_max_ack_delay(&mut self, mad: Duration) {
|
||||
self.max_ack_delay = mad;
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
mut qlog: &mut NeqoQlog,
|
||||
mut rtt_sample: Duration,
|
||||
ack_delay: Duration,
|
||||
confirmed: bool,
|
||||
now: Instant,
|
||||
) {
|
||||
// Limit ack delay by max_ack_delay if confirmed.
|
||||
let ack_delay = if confirmed && ack_delay > self.max_ack_delay {
|
||||
self.max_ack_delay
|
||||
} else {
|
||||
ack_delay
|
||||
};
|
||||
|
||||
// min_rtt ignores ack delay.
|
||||
self.min_rtt = min(self.min_rtt, rtt_sample);
|
||||
// Adjust for ack delay unless it goes below `min_rtt`.
|
||||
if rtt_sample - self.min_rtt >= ack_delay {
|
||||
rtt_sample -= ack_delay;
|
||||
}
|
||||
|
||||
if self.first_sample_time.is_none() {
|
||||
self.init(rtt_sample);
|
||||
self.first_sample_time = Some(now);
|
||||
} else {
|
||||
// Calculate EWMA RTT (based on {{?RFC6298}}).
|
||||
let rttvar_sample = if self.smoothed_rtt > rtt_sample {
|
||||
self.smoothed_rtt - rtt_sample
|
||||
} else {
|
||||
rtt_sample - self.smoothed_rtt
|
||||
};
|
||||
|
||||
self.latest_rtt = rtt_sample;
|
||||
self.rttvar = (self.rttvar * 3 + rttvar_sample) / 4;
|
||||
self.smoothed_rtt = (self.smoothed_rtt * 7 + rtt_sample) / 8;
|
||||
}
|
||||
qtrace!(
|
||||
"RTT latest={:?} -> estimate={:?}~{:?}",
|
||||
self.latest_rtt,
|
||||
self.smoothed_rtt,
|
||||
self.rttvar
|
||||
);
|
||||
qlog::metrics_updated(
|
||||
&mut qlog,
|
||||
&[
|
||||
QlogMetric::LatestRtt(self.latest_rtt),
|
||||
QlogMetric::MinRtt(self.min_rtt),
|
||||
QlogMetric::SmoothedRtt(self.smoothed_rtt),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Get the estimated value.
|
||||
pub fn estimate(&self) -> Duration {
|
||||
self.smoothed_rtt
|
||||
}
|
||||
|
||||
pub fn pto(&self, pn_space: PNSpace) -> Duration {
|
||||
self.estimate()
|
||||
+ max(4 * self.rttvar, GRANULARITY)
|
||||
+ if pn_space == PNSpace::ApplicationData {
|
||||
self.max_ack_delay
|
||||
} else {
|
||||
Duration::from_millis(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the loss delay based on the current estimate and the last
|
||||
/// RTT measurement received.
|
||||
pub fn loss_delay(&self) -> Duration {
|
||||
// kTimeThreshold = 9/8
|
||||
// loss_delay = kTimeThreshold * max(latest_rtt, smoothed_rtt)
|
||||
// loss_delay = max(loss_delay, kGranularity)
|
||||
let rtt = max(self.latest_rtt, self.smoothed_rtt);
|
||||
max(rtt * 9 / 8, GRANULARITY)
|
||||
}
|
||||
|
||||
pub fn first_sample_time(&self) -> Option<Instant> {
|
||||
self.first_sample_time
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn latest(&self) -> Duration {
|
||||
self.latest_rtt
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn rttvar(&self) -> Duration {
|
||||
self.rttvar
|
||||
}
|
||||
|
||||
pub fn minimum(&self) -> Duration {
|
||||
self.min_rtt
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RttEstimate {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
first_sample_time: None,
|
||||
latest_rtt: INITIAL_RTT,
|
||||
smoothed_rtt: INITIAL_RTT,
|
||||
rttvar: INITIAL_RTT / 2,
|
||||
min_rtt: INITIAL_RTT,
|
||||
max_ack_delay: DEFAULT_MAX_ACK_DELAY,
|
||||
}
|
||||
}
|
||||
}
|
988
third_party/rust/neqo-transport/src/send_stream.rs
vendored
988
third_party/rust/neqo-transport/src/send_stream.rs
vendored
File diff suppressed because it is too large
Load Diff
37
third_party/rust/neqo-transport/src/sender.rs
vendored
37
third_party/rust/neqo-transport/src/sender.rs
vendored
@ -10,7 +10,6 @@
|
||||
|
||||
use crate::cc::{
|
||||
ClassicCongestionControl, CongestionControl, CongestionControlAlgorithm, Cubic, NewReno,
|
||||
MAX_DATAGRAM_SIZE,
|
||||
};
|
||||
use crate::pace::Pacer;
|
||||
use crate::tracking::SentPacket;
|
||||
@ -25,22 +24,18 @@ pub const PACING_BURST_SIZE: usize = 2;
|
||||
#[derive(Debug)]
|
||||
pub struct PacketSender {
|
||||
cc: Box<dyn CongestionControl>,
|
||||
pacer: Option<Pacer>,
|
||||
pacer: Pacer,
|
||||
}
|
||||
|
||||
impl Display for PacketSender {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.cc)?;
|
||||
if let Some(p) = &self.pacer {
|
||||
write!(f, " {}", p)?;
|
||||
}
|
||||
Ok(())
|
||||
write!(f, "{} {}", self.cc, self.pacer)
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketSender {
|
||||
#[must_use]
|
||||
pub fn new(alg: CongestionControlAlgorithm) -> Self {
|
||||
pub fn new(alg: CongestionControlAlgorithm, mtu: usize, now: Instant) -> Self {
|
||||
Self {
|
||||
cc: match alg {
|
||||
CongestionControlAlgorithm::NewReno => {
|
||||
@ -50,7 +45,7 @@ impl PacketSender {
|
||||
Box::new(ClassicCongestionControl::new(Cubic::default()))
|
||||
}
|
||||
},
|
||||
pacer: None,
|
||||
pacer: Pacer::new(now, mtu * PACING_BURST_SIZE, mtu),
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +64,6 @@ impl PacketSender {
|
||||
self.cc.cwnd_avail()
|
||||
}
|
||||
|
||||
// Multi-packet version of OnPacketAckedCC
|
||||
pub fn on_packets_acked(&mut self, acked_pkts: &[SentPacket], min_rtt: Duration, now: Instant) {
|
||||
self.cc.on_packets_acked(acked_pkts, min_rtt, now);
|
||||
}
|
||||
@ -93,28 +87,23 @@ impl PacketSender {
|
||||
self.cc.discard(pkt);
|
||||
}
|
||||
|
||||
pub fn on_packet_sent(&mut self, pkt: &SentPacket, rtt: Duration) {
|
||||
self.pacer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.spend(pkt.time_sent, rtt, self.cc.cwnd(), pkt.size);
|
||||
self.cc.on_packet_sent(pkt);
|
||||
/// When we migrate, the congestion controller for the previously active path drops
|
||||
/// all bytes in flight.
|
||||
pub fn discard_in_flight(&mut self) {
|
||||
self.cc.discard_in_flight();
|
||||
}
|
||||
|
||||
pub fn start_pacer(&mut self, now: Instant) {
|
||||
// Start the pacer with a small burst size.
|
||||
self.pacer = Some(Pacer::new(
|
||||
now,
|
||||
MAX_DATAGRAM_SIZE * PACING_BURST_SIZE,
|
||||
MAX_DATAGRAM_SIZE,
|
||||
));
|
||||
pub fn on_packet_sent(&mut self, pkt: &SentPacket, rtt: Duration) {
|
||||
self.pacer
|
||||
.spend(pkt.time_sent, rtt, self.cc.cwnd(), pkt.size);
|
||||
self.cc.on_packet_sent(pkt);
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn next_paced(&self, rtt: Duration) -> Option<Instant> {
|
||||
// Only pace if there are bytes in flight.
|
||||
if self.cc.bytes_in_flight() > 0 {
|
||||
Some(self.pacer.as_ref().unwrap().next(rtt, self.cc.cwnd()))
|
||||
Some(self.pacer.next(rtt, self.cc.cwnd()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
11
third_party/rust/neqo-transport/src/server.rs
vendored
11
third_party/rust/neqo-transport/src/server.rs
vendored
@ -39,7 +39,12 @@ pub enum InitialResult {
|
||||
/// MIN_INITIAL_PACKET_SIZE is the smallest packet that can be used to establish
|
||||
/// a new connection across all QUIC versions this server supports.
|
||||
const MIN_INITIAL_PACKET_SIZE: usize = 1200;
|
||||
const TIMER_GRANULARITY: Duration = Duration::from_millis(10);
|
||||
/// The size of timer buckets. This is higher than the actual timer granularity
|
||||
/// as this depends on there being some distribution of events.
|
||||
const TIMER_GRANULARITY: Duration = Duration::from_millis(4);
|
||||
/// The number of buckets in the timer. As mentioned in the definition of `Timer`,
|
||||
/// the granularity and capacity need to multiply to be larger than the largest
|
||||
/// delay that might be used. That's the idle timeout (currently 30s).
|
||||
const TIMER_CAPACITY: usize = 16384;
|
||||
|
||||
type StateRef = Rc<RefCell<ServerConnectionState>>;
|
||||
@ -610,11 +615,11 @@ pub struct ActiveConnectionRef {
|
||||
}
|
||||
|
||||
impl ActiveConnectionRef {
|
||||
pub fn borrow<'a>(&'a self) -> impl Deref<Target = Connection> + 'a {
|
||||
pub fn borrow(&self) -> impl Deref<Target = Connection> + '_ {
|
||||
std::cell::Ref::map(self.c.borrow(), |c| &c.c)
|
||||
}
|
||||
|
||||
pub fn borrow_mut<'a>(&'a mut self) -> impl DerefMut<Target = Connection> + 'a {
|
||||
pub fn borrow_mut(&mut self) -> impl DerefMut<Target = Connection> + '_ {
|
||||
std::cell::RefMut::map(self.c.borrow_mut(), |c| &mut c.c)
|
||||
}
|
||||
|
||||
|
88
third_party/rust/neqo-transport/src/tracking.rs
vendored
88
third_party/rust/neqo-transport/src/tracking.rs
vendored
@ -137,6 +137,7 @@ pub struct SentPacket {
|
||||
pub pn: PacketNumber,
|
||||
ack_eliciting: bool,
|
||||
pub time_sent: Instant,
|
||||
primary_path: bool,
|
||||
pub tokens: Vec<RecoveryToken>,
|
||||
|
||||
time_declared_lost: Option<Instant>,
|
||||
@ -160,6 +161,7 @@ impl SentPacket {
|
||||
pn,
|
||||
time_sent,
|
||||
ack_eliciting,
|
||||
primary_path: true,
|
||||
tokens,
|
||||
time_declared_lost: None,
|
||||
pto: false,
|
||||
@ -172,6 +174,17 @@ impl SentPacket {
|
||||
self.ack_eliciting
|
||||
}
|
||||
|
||||
/// Returns `true` if the packet was sent on the primary path.
|
||||
pub fn on_primary_path(&self) -> bool {
|
||||
self.primary_path
|
||||
}
|
||||
|
||||
/// Clears the flag that had this packet on the primary path.
|
||||
/// Used when migrating to clear out state.
|
||||
pub fn clear_primary_path(&mut self) {
|
||||
self.primary_path = false;
|
||||
}
|
||||
|
||||
/// Whether the packet has been declared lost.
|
||||
pub fn lost(&self) -> bool {
|
||||
self.time_declared_lost.is_some()
|
||||
@ -184,7 +197,12 @@ impl SentPacket {
|
||||
/// Note that this should count packets that contain only ACK and PADDING,
|
||||
/// but we don't send PADDING, so we don't track that.
|
||||
pub fn cc_outstanding(&self) -> bool {
|
||||
self.ack_eliciting() && !self.lost()
|
||||
self.ack_eliciting() && self.on_primary_path() && !self.lost()
|
||||
}
|
||||
|
||||
/// Whether the packet should be tracked as in-flight.
|
||||
pub fn cc_in_flight(&self) -> bool {
|
||||
self.ack_eliciting() && self.on_primary_path()
|
||||
}
|
||||
|
||||
/// Declare the packet as lost. Returns `true` if this is the first time.
|
||||
@ -502,15 +520,16 @@ impl RecvdPackets {
|
||||
&mut self,
|
||||
now: Instant,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Option<RecoveryToken> {
|
||||
) {
|
||||
// The worst possible ACK frame, assuming only one range.
|
||||
// Note that this assumes one byte for the type and count of extra ranges.
|
||||
const LONGEST_ACK_HEADER: usize = 1 + 8 + 8 + 1 + 8;
|
||||
|
||||
// Check that we aren't delaying ACKs.
|
||||
if !self.ack_now(now) {
|
||||
return None;
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop extra ACK ranges to fit the available space. Do this based on
|
||||
@ -523,7 +542,7 @@ impl RecvdPackets {
|
||||
// Apply a hard maximum to keep plenty of space for other stuff.
|
||||
min(1 + (avail / 16), MAX_ACKS_PER_FRAME)
|
||||
} else {
|
||||
return None;
|
||||
return;
|
||||
};
|
||||
|
||||
let ranges = self
|
||||
@ -538,7 +557,7 @@ impl RecvdPackets {
|
||||
let mut iter = ranges.iter();
|
||||
let first = match iter.next() {
|
||||
Some(v) => v,
|
||||
None => return None, // Nothing to send.
|
||||
None => return, // Nothing to send.
|
||||
};
|
||||
builder.encode_varint(first.largest);
|
||||
stats.largest_acknowledged = first.largest;
|
||||
@ -565,10 +584,10 @@ impl RecvdPackets {
|
||||
self.ack_time = None;
|
||||
self.pkts_since_last_ack = 0;
|
||||
|
||||
Some(RecoveryToken::Ack(AckToken {
|
||||
tokens.push(RecoveryToken::Ack(AckToken {
|
||||
space: self.space,
|
||||
ranges,
|
||||
}))
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,16 +655,16 @@ impl AckTracker {
|
||||
pn_space: PNSpace,
|
||||
now: Instant,
|
||||
builder: &mut PacketBuilder,
|
||||
tokens: &mut Vec<RecoveryToken>,
|
||||
stats: &mut FrameStats,
|
||||
) -> Res<Option<RecoveryToken>> {
|
||||
let res = self
|
||||
.get_mut(pn_space)
|
||||
.and_then(|space| space.write_frame(now, builder, stats));
|
||||
|
||||
if builder.len() > builder.limit() {
|
||||
return Err(Error::InternalError(24));
|
||||
) -> Res<()> {
|
||||
if let Some(space) = self.get_mut(pn_space) {
|
||||
space.write_frame(now, builder, tokens, stats);
|
||||
if builder.len() > builder.limit() {
|
||||
return Err(Error::InternalError(24));
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -855,15 +874,19 @@ mod tests {
|
||||
.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 - Duration::from_millis(1)).is_some());
|
||||
let token = tracker
|
||||
|
||||
let mut tokens = Vec::new();
|
||||
let mut stats = FrameStats::default();
|
||||
tracker
|
||||
.write_frame(
|
||||
PNSpace::Initial,
|
||||
*NOW,
|
||||
&mut builder,
|
||||
&mut FrameStats::default(),
|
||||
&mut tokens,
|
||||
&mut stats,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(token.is_some());
|
||||
assert_eq!(stats.ack, 1);
|
||||
|
||||
// Mark another packet as received so we have cause to send another ACK in that space.
|
||||
tracker
|
||||
@ -877,17 +900,18 @@ mod tests {
|
||||
|
||||
assert!(tracker.get_mut(PNSpace::Initial).is_none());
|
||||
assert!(tracker.ack_time(*NOW - Duration::from_millis(1)).is_none());
|
||||
assert!(tracker
|
||||
tracker
|
||||
.write_frame(
|
||||
PNSpace::Initial,
|
||||
*NOW,
|
||||
&mut builder,
|
||||
&mut FrameStats::default()
|
||||
&mut tokens,
|
||||
&mut stats,
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
if let RecoveryToken::Ack(tok) = token.unwrap() {
|
||||
tracker.acked(&tok); // Should be a noop.
|
||||
.unwrap();
|
||||
assert_eq!(stats.ack, 1);
|
||||
if let RecoveryToken::Ack(tok) = &tokens[0] {
|
||||
tracker.acked(tok); // Should be a noop.
|
||||
} else {
|
||||
panic!("not an ACK token");
|
||||
}
|
||||
@ -905,15 +929,17 @@ mod tests {
|
||||
let mut builder = PacketBuilder::short(Encoder::new(), false, &[]);
|
||||
builder.set_limit(10);
|
||||
|
||||
let token = tracker
|
||||
let mut stats = FrameStats::default();
|
||||
tracker
|
||||
.write_frame(
|
||||
PNSpace::Initial,
|
||||
*NOW,
|
||||
&mut builder,
|
||||
&mut FrameStats::default(),
|
||||
&mut Vec::new(),
|
||||
&mut stats,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(token.is_none());
|
||||
assert_eq!(stats.ack, 0);
|
||||
assert_eq!(builder.len(), 1); // Only the short packet header has been added.
|
||||
}
|
||||
|
||||
@ -933,15 +959,17 @@ mod tests {
|
||||
let mut builder = PacketBuilder::short(Encoder::new(), false, &[]);
|
||||
builder.set_limit(32);
|
||||
|
||||
let token = tracker
|
||||
let mut stats = FrameStats::default();
|
||||
tracker
|
||||
.write_frame(
|
||||
PNSpace::Initial,
|
||||
*NOW,
|
||||
&mut builder,
|
||||
&mut FrameStats::default(),
|
||||
&mut Vec::new(),
|
||||
&mut stats,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(token.is_some());
|
||||
assert_eq!(stats.ack, 1);
|
||||
|
||||
let mut dec = builder.as_decoder();
|
||||
let _ = dec.decode_byte().unwrap(); // Skip the short header.
|
||||
|
@ -7,7 +7,7 @@
|
||||
// Tests with the test vectors from the spec.
|
||||
#![deny(clippy::pedantic)]
|
||||
|
||||
use neqo_common::{Datagram, Encoder};
|
||||
use neqo_common::Datagram;
|
||||
use neqo_transport::{
|
||||
Connection, ConnectionParameters, QuicVersion, RandomConnectionIdGenerator, State,
|
||||
};
|
||||
@ -16,157 +16,239 @@ use test_fixture::{self, addr, now};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
const INITIAL_PACKET_27: &str = "c0ff00001b088394c8f03e5157080000\
|
||||
449e3b343aa8535064a4268a0d9d7b1c\
|
||||
9d250ae355162276e9b1e3011ef6bbc0\
|
||||
ab48ad5bcc2681e953857ca62becd752\
|
||||
4daac473e68d7405fbba4e9ee616c870\
|
||||
38bdbe908c06d9605d9ac49030359eec\
|
||||
b1d05a14e117db8cede2bb09d0dbbfee\
|
||||
271cb374d8f10abec82d0f59a1dee29f\
|
||||
e95638ed8dd41da07487468791b719c5\
|
||||
5c46968eb3b54680037102a28e53dc1d\
|
||||
12903db0af5821794b41c4a93357fa59\
|
||||
ce69cfe7f6bdfa629eef78616447e1d6\
|
||||
11c4baf71bf33febcb03137c2c75d253\
|
||||
17d3e13b684370f668411c0f00304b50\
|
||||
1c8fd422bd9b9ad81d643b20da89ca05\
|
||||
25d24d2b142041cae0af205092e43008\
|
||||
0cd8559ea4c5c6e4fa3f66082b7d303e\
|
||||
52ce0162baa958532b0bbc2bc785681f\
|
||||
cf37485dff6595e01e739c8ac9efba31\
|
||||
b985d5f656cc092432d781db95221724\
|
||||
87641c4d3ab8ece01e39bc85b1543661\
|
||||
4775a98ba8fa12d46f9b35e2a55eb72d\
|
||||
7f85181a366663387ddc20551807e007\
|
||||
673bd7e26bf9b29b5ab10a1ca87cbb7a\
|
||||
d97e99eb66959c2a9bc3cbde4707ff77\
|
||||
20b110fa95354674e395812e47a0ae53\
|
||||
b464dcb2d1f345df360dc227270c7506\
|
||||
76f6724eb479f0d2fbb6124429990457\
|
||||
ac6c9167f40aab739998f38b9eccb24f\
|
||||
d47c8410131bf65a52af841275d5b3d1\
|
||||
880b197df2b5dea3e6de56ebce3ffb6e\
|
||||
9277a82082f8d9677a6767089b671ebd\
|
||||
244c214f0bde95c2beb02cd1172d58bd\
|
||||
f39dce56ff68eb35ab39b49b4eac7c81\
|
||||
5ea60451d6e6ab82119118df02a58684\
|
||||
4a9ffe162ba006d0669ef57668cab38b\
|
||||
62f71a2523a084852cd1d079b3658dc2\
|
||||
f3e87949b550bab3e177cfc49ed190df\
|
||||
f0630e43077c30de8f6ae081537f1e83\
|
||||
da537da980afa668e7b7fb25301cf741\
|
||||
524be3c49884b42821f17552fbd1931a\
|
||||
813017b6b6590a41ea18b6ba49cd48a4\
|
||||
40bd9a3346a7623fb4ba34a3ee571e3c\
|
||||
731f35a7a3cf25b551a680fa68763507\
|
||||
b7fde3aaf023c50b9d22da6876ba337e\
|
||||
b5e9dd9ec3daf970242b6c5aab3aa4b2\
|
||||
96ad8b9f6832f686ef70fa938b31b4e5\
|
||||
ddd7364442d3ea72e73d668fb0937796\
|
||||
f462923a81a47e1cee7426ff6d922126\
|
||||
9b5a62ec03d6ec94d12606cb485560ba\
|
||||
b574816009e96504249385bb61a819be\
|
||||
04f62c2066214d8360a2022beb316240\
|
||||
b6c7d78bbe56c13082e0ca272661210a\
|
||||
bf020bf3b5783f1426436cf9ff418405\
|
||||
93a5d0638d32fc51c5c65ff291a3a7a5\
|
||||
2fd6775e623a4439cc08dd25582febc9\
|
||||
44ef92d8dbd329c91de3e9c9582e41f1\
|
||||
7f3d186f104ad3f90995116c682a2a14\
|
||||
a3b4b1f547c335f0be710fc9fc03e0e5\
|
||||
87b8cda31ce65b969878a4ad4283e6d5\
|
||||
b0373f43da86e9e0ffe1ae0fddd35162\
|
||||
55bd74566f36a38703d5f34249ded1f6\
|
||||
6b3d9b45b9af2ccfefe984e13376b1b2\
|
||||
c6404aa48c8026132343da3f3a33659e\
|
||||
c1b3e95080540b28b7f3fcd35fa5d843\
|
||||
b579a84c089121a60d8c1754915c344e\
|
||||
eaf45a9bf27dc0c1e784161691220913\
|
||||
13eb0e87555abd706626e557fc36a04f\
|
||||
cd191a58829104d6075c5594f627ca50\
|
||||
6bf181daec940f4a4f3af0074eee89da\
|
||||
acde6758312622d4fa675b39f728e062\
|
||||
d2bee680d8f41a597c262648bb18bcfc\
|
||||
13c8b3d97b1a77b2ac3af745d61a34cc\
|
||||
4709865bac824a94bb19058015e4e42d\
|
||||
38d3b779d72edc00c5cd088eff802b05";
|
||||
const INITIAL_PACKET_V1: &[u8] = &[
|
||||
0xc0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00,
|
||||
0x44, 0x9e, 0x7b, 0x9a, 0xec, 0x34, 0xd1, 0xb1, 0xc9, 0x8d, 0xd7, 0x68, 0x9f, 0xb8, 0xec, 0x11,
|
||||
0xd2, 0x42, 0xb1, 0x23, 0xdc, 0x9b, 0xd8, 0xba, 0xb9, 0x36, 0xb4, 0x7d, 0x92, 0xec, 0x35, 0x6c,
|
||||
0x0b, 0xab, 0x7d, 0xf5, 0x97, 0x6d, 0x27, 0xcd, 0x44, 0x9f, 0x63, 0x30, 0x00, 0x99, 0xf3, 0x99,
|
||||
0x1c, 0x26, 0x0e, 0xc4, 0xc6, 0x0d, 0x17, 0xb3, 0x1f, 0x84, 0x29, 0x15, 0x7b, 0xb3, 0x5a, 0x12,
|
||||
0x82, 0xa6, 0x43, 0xa8, 0xd2, 0x26, 0x2c, 0xad, 0x67, 0x50, 0x0c, 0xad, 0xb8, 0xe7, 0x37, 0x8c,
|
||||
0x8e, 0xb7, 0x53, 0x9e, 0xc4, 0xd4, 0x90, 0x5f, 0xed, 0x1b, 0xee, 0x1f, 0xc8, 0xaa, 0xfb, 0xa1,
|
||||
0x7c, 0x75, 0x0e, 0x2c, 0x7a, 0xce, 0x01, 0xe6, 0x00, 0x5f, 0x80, 0xfc, 0xb7, 0xdf, 0x62, 0x12,
|
||||
0x30, 0xc8, 0x37, 0x11, 0xb3, 0x93, 0x43, 0xfa, 0x02, 0x8c, 0xea, 0x7f, 0x7f, 0xb5, 0xff, 0x89,
|
||||
0xea, 0xc2, 0x30, 0x82, 0x49, 0xa0, 0x22, 0x52, 0x15, 0x5e, 0x23, 0x47, 0xb6, 0x3d, 0x58, 0xc5,
|
||||
0x45, 0x7a, 0xfd, 0x84, 0xd0, 0x5d, 0xff, 0xfd, 0xb2, 0x03, 0x92, 0x84, 0x4a, 0xe8, 0x12, 0x15,
|
||||
0x46, 0x82, 0xe9, 0xcf, 0x01, 0x2f, 0x90, 0x21, 0xa6, 0xf0, 0xbe, 0x17, 0xdd, 0xd0, 0xc2, 0x08,
|
||||
0x4d, 0xce, 0x25, 0xff, 0x9b, 0x06, 0xcd, 0xe5, 0x35, 0xd0, 0xf9, 0x20, 0xa2, 0xdb, 0x1b, 0xf3,
|
||||
0x62, 0xc2, 0x3e, 0x59, 0x6d, 0x11, 0xa4, 0xf5, 0xa6, 0xcf, 0x39, 0x48, 0x83, 0x8a, 0x3a, 0xec,
|
||||
0x4e, 0x15, 0xda, 0xf8, 0x50, 0x0a, 0x6e, 0xf6, 0x9e, 0xc4, 0xe3, 0xfe, 0xb6, 0xb1, 0xd9, 0x8e,
|
||||
0x61, 0x0a, 0xc8, 0xb7, 0xec, 0x3f, 0xaf, 0x6a, 0xd7, 0x60, 0xb7, 0xba, 0xd1, 0xdb, 0x4b, 0xa3,
|
||||
0x48, 0x5e, 0x8a, 0x94, 0xdc, 0x25, 0x0a, 0xe3, 0xfd, 0xb4, 0x1e, 0xd1, 0x5f, 0xb6, 0xa8, 0xe5,
|
||||
0xeb, 0xa0, 0xfc, 0x3d, 0xd6, 0x0b, 0xc8, 0xe3, 0x0c, 0x5c, 0x42, 0x87, 0xe5, 0x38, 0x05, 0xdb,
|
||||
0x05, 0x9a, 0xe0, 0x64, 0x8d, 0xb2, 0xf6, 0x42, 0x64, 0xed, 0x5e, 0x39, 0xbe, 0x2e, 0x20, 0xd8,
|
||||
0x2d, 0xf5, 0x66, 0xda, 0x8d, 0xd5, 0x99, 0x8c, 0xca, 0xbd, 0xae, 0x05, 0x30, 0x60, 0xae, 0x6c,
|
||||
0x7b, 0x43, 0x78, 0xe8, 0x46, 0xd2, 0x9f, 0x37, 0xed, 0x7b, 0x4e, 0xa9, 0xec, 0x5d, 0x82, 0xe7,
|
||||
0x96, 0x1b, 0x7f, 0x25, 0xa9, 0x32, 0x38, 0x51, 0xf6, 0x81, 0xd5, 0x82, 0x36, 0x3a, 0xa5, 0xf8,
|
||||
0x99, 0x37, 0xf5, 0xa6, 0x72, 0x58, 0xbf, 0x63, 0xad, 0x6f, 0x1a, 0x0b, 0x1d, 0x96, 0xdb, 0xd4,
|
||||
0xfa, 0xdd, 0xfc, 0xef, 0xc5, 0x26, 0x6b, 0xa6, 0x61, 0x17, 0x22, 0x39, 0x5c, 0x90, 0x65, 0x56,
|
||||
0xbe, 0x52, 0xaf, 0xe3, 0xf5, 0x65, 0x63, 0x6a, 0xd1, 0xb1, 0x7d, 0x50, 0x8b, 0x73, 0xd8, 0x74,
|
||||
0x3e, 0xeb, 0x52, 0x4b, 0xe2, 0x2b, 0x3d, 0xcb, 0xc2, 0xc7, 0x46, 0x8d, 0x54, 0x11, 0x9c, 0x74,
|
||||
0x68, 0x44, 0x9a, 0x13, 0xd8, 0xe3, 0xb9, 0x58, 0x11, 0xa1, 0x98, 0xf3, 0x49, 0x1d, 0xe3, 0xe7,
|
||||
0xfe, 0x94, 0x2b, 0x33, 0x04, 0x07, 0xab, 0xf8, 0x2a, 0x4e, 0xd7, 0xc1, 0xb3, 0x11, 0x66, 0x3a,
|
||||
0xc6, 0x98, 0x90, 0xf4, 0x15, 0x70, 0x15, 0x85, 0x3d, 0x91, 0xe9, 0x23, 0x03, 0x7c, 0x22, 0x7a,
|
||||
0x33, 0xcd, 0xd5, 0xec, 0x28, 0x1c, 0xa3, 0xf7, 0x9c, 0x44, 0x54, 0x6b, 0x9d, 0x90, 0xca, 0x00,
|
||||
0xf0, 0x64, 0xc9, 0x9e, 0x3d, 0xd9, 0x79, 0x11, 0xd3, 0x9f, 0xe9, 0xc5, 0xd0, 0xb2, 0x3a, 0x22,
|
||||
0x9a, 0x23, 0x4c, 0xb3, 0x61, 0x86, 0xc4, 0x81, 0x9e, 0x8b, 0x9c, 0x59, 0x27, 0x72, 0x66, 0x32,
|
||||
0x29, 0x1d, 0x6a, 0x41, 0x82, 0x11, 0xcc, 0x29, 0x62, 0xe2, 0x0f, 0xe4, 0x7f, 0xeb, 0x3e, 0xdf,
|
||||
0x33, 0x0f, 0x2c, 0x60, 0x3a, 0x9d, 0x48, 0xc0, 0xfc, 0xb5, 0x69, 0x9d, 0xbf, 0xe5, 0x89, 0x64,
|
||||
0x25, 0xc5, 0xba, 0xc4, 0xae, 0xe8, 0x2e, 0x57, 0xa8, 0x5a, 0xaf, 0x4e, 0x25, 0x13, 0xe4, 0xf0,
|
||||
0x57, 0x96, 0xb0, 0x7b, 0xa2, 0xee, 0x47, 0xd8, 0x05, 0x06, 0xf8, 0xd2, 0xc2, 0x5e, 0x50, 0xfd,
|
||||
0x14, 0xde, 0x71, 0xe6, 0xc4, 0x18, 0x55, 0x93, 0x02, 0xf9, 0x39, 0xb0, 0xe1, 0xab, 0xd5, 0x76,
|
||||
0xf2, 0x79, 0xc4, 0xb2, 0xe0, 0xfe, 0xb8, 0x5c, 0x1f, 0x28, 0xff, 0x18, 0xf5, 0x88, 0x91, 0xff,
|
||||
0xef, 0x13, 0x2e, 0xef, 0x2f, 0xa0, 0x93, 0x46, 0xae, 0xe3, 0x3c, 0x28, 0xeb, 0x13, 0x0f, 0xf2,
|
||||
0x8f, 0x5b, 0x76, 0x69, 0x53, 0x33, 0x41, 0x13, 0x21, 0x19, 0x96, 0xd2, 0x00, 0x11, 0xa1, 0x98,
|
||||
0xe3, 0xfc, 0x43, 0x3f, 0x9f, 0x25, 0x41, 0x01, 0x0a, 0xe1, 0x7c, 0x1b, 0xf2, 0x02, 0x58, 0x0f,
|
||||
0x60, 0x47, 0x47, 0x2f, 0xb3, 0x68, 0x57, 0xfe, 0x84, 0x3b, 0x19, 0xf5, 0x98, 0x40, 0x09, 0xdd,
|
||||
0xc3, 0x24, 0x04, 0x4e, 0x84, 0x7a, 0x4f, 0x4a, 0x0a, 0xb3, 0x4f, 0x71, 0x95, 0x95, 0xde, 0x37,
|
||||
0x25, 0x2d, 0x62, 0x35, 0x36, 0x5e, 0x9b, 0x84, 0x39, 0x2b, 0x06, 0x10, 0x85, 0x34, 0x9d, 0x73,
|
||||
0x20, 0x3a, 0x4a, 0x13, 0xe9, 0x6f, 0x54, 0x32, 0xec, 0x0f, 0xd4, 0xa1, 0xee, 0x65, 0xac, 0xcd,
|
||||
0xd5, 0xe3, 0x90, 0x4d, 0xf5, 0x4c, 0x1d, 0xa5, 0x10, 0xb0, 0xff, 0x20, 0xdc, 0xc0, 0xc7, 0x7f,
|
||||
0xcb, 0x2c, 0x0e, 0x0e, 0xb6, 0x05, 0xcb, 0x05, 0x04, 0xdb, 0x87, 0x63, 0x2c, 0xf3, 0xd8, 0xb4,
|
||||
0xda, 0xe6, 0xe7, 0x05, 0x76, 0x9d, 0x1d, 0xe3, 0x54, 0x27, 0x01, 0x23, 0xcb, 0x11, 0x45, 0x0e,
|
||||
0xfc, 0x60, 0xac, 0x47, 0x68, 0x3d, 0x7b, 0x8d, 0x0f, 0x81, 0x13, 0x65, 0x56, 0x5f, 0xd9, 0x8c,
|
||||
0x4c, 0x8e, 0xb9, 0x36, 0xbc, 0xab, 0x8d, 0x06, 0x9f, 0xc3, 0x3b, 0xd8, 0x01, 0xb0, 0x3a, 0xde,
|
||||
0xa2, 0xe1, 0xfb, 0xc5, 0xaa, 0x46, 0x3d, 0x08, 0xca, 0x19, 0x89, 0x6d, 0x2b, 0xf5, 0x9a, 0x07,
|
||||
0x1b, 0x85, 0x1e, 0x6c, 0x23, 0x90, 0x52, 0x17, 0x2f, 0x29, 0x6b, 0xfb, 0x5e, 0x72, 0x40, 0x47,
|
||||
0x90, 0xa2, 0x18, 0x10, 0x14, 0xf3, 0xb9, 0x4a, 0x4e, 0x97, 0xd1, 0x17, 0xb4, 0x38, 0x13, 0x03,
|
||||
0x68, 0xcc, 0x39, 0xdb, 0xb2, 0xd1, 0x98, 0x06, 0x5a, 0xe3, 0x98, 0x65, 0x47, 0x92, 0x6c, 0xd2,
|
||||
0x16, 0x2f, 0x40, 0xa2, 0x9f, 0x0c, 0x3c, 0x87, 0x45, 0xc0, 0xf5, 0x0f, 0xba, 0x38, 0x52, 0xe5,
|
||||
0x66, 0xd4, 0x45, 0x75, 0xc2, 0x9d, 0x39, 0xa0, 0x3f, 0x0c, 0xda, 0x72, 0x19, 0x84, 0xb6, 0xf4,
|
||||
0x40, 0x59, 0x1f, 0x35, 0x5e, 0x12, 0xd4, 0x39, 0xff, 0x15, 0x0a, 0xab, 0x76, 0x13, 0x49, 0x9d,
|
||||
0xbd, 0x49, 0xad, 0xab, 0xc8, 0x67, 0x6e, 0xef, 0x02, 0x3b, 0x15, 0xb6, 0x5b, 0xfc, 0x5c, 0xa0,
|
||||
0x69, 0x48, 0x10, 0x9f, 0x23, 0xf3, 0x50, 0xdb, 0x82, 0x12, 0x35, 0x35, 0xeb, 0x8a, 0x74, 0x33,
|
||||
0xbd, 0xab, 0xcb, 0x90, 0x92, 0x71, 0xa6, 0xec, 0xbc, 0xb5, 0x8b, 0x93, 0x6a, 0x88, 0xcd, 0x4e,
|
||||
0x8f, 0x2e, 0x6f, 0xf5, 0x80, 0x01, 0x75, 0xf1, 0x13, 0x25, 0x3d, 0x8f, 0xa9, 0xca, 0x88, 0x85,
|
||||
0xc2, 0xf5, 0x52, 0xe6, 0x57, 0xdc, 0x60, 0x3f, 0x25, 0x2e, 0x1a, 0x8e, 0x30, 0x8f, 0x76, 0xf0,
|
||||
0xbe, 0x79, 0xe2, 0xfb, 0x8f, 0x5d, 0x5f, 0xbb, 0xe2, 0xe3, 0x0e, 0xca, 0xdd, 0x22, 0x07, 0x23,
|
||||
0xc8, 0xc0, 0xae, 0xa8, 0x07, 0x8c, 0xdf, 0xcb, 0x38, 0x68, 0x26, 0x3f, 0xf8, 0xf0, 0x94, 0x00,
|
||||
0x54, 0xda, 0x48, 0x78, 0x18, 0x93, 0xa7, 0xe4, 0x9a, 0xd5, 0xaf, 0xf4, 0xaf, 0x30, 0x0c, 0xd8,
|
||||
0x04, 0xa6, 0xb6, 0x27, 0x9a, 0xb3, 0xff, 0x3a, 0xfb, 0x64, 0x49, 0x1c, 0x85, 0x19, 0x4a, 0xab,
|
||||
0x76, 0x0d, 0x58, 0xa6, 0x06, 0x65, 0x4f, 0x9f, 0x44, 0x00, 0xe8, 0xb3, 0x85, 0x91, 0x35, 0x6f,
|
||||
0xbf, 0x64, 0x25, 0xac, 0xa2, 0x6d, 0xc8, 0x52, 0x44, 0x25, 0x9f, 0xf2, 0xb1, 0x9c, 0x41, 0xb9,
|
||||
0xf9, 0x6f, 0x3c, 0xa9, 0xec, 0x1d, 0xde, 0x43, 0x4d, 0xa7, 0xd2, 0xd3, 0x92, 0xb9, 0x05, 0xdd,
|
||||
0xf3, 0xd1, 0xf9, 0xaf, 0x93, 0xd1, 0xaf, 0x59, 0x50, 0xbd, 0x49, 0x3f, 0x5a, 0xa7, 0x31, 0xb4,
|
||||
0x05, 0x6d, 0xf3, 0x1b, 0xd2, 0x67, 0xb6, 0xb9, 0x0a, 0x07, 0x98, 0x31, 0xaa, 0xf5, 0x79, 0xbe,
|
||||
0x0a, 0x39, 0x01, 0x31, 0x37, 0xaa, 0xc6, 0xd4, 0x04, 0xf5, 0x18, 0xcf, 0xd4, 0x68, 0x40, 0x64,
|
||||
0x7e, 0x78, 0xbf, 0xe7, 0x06, 0xca, 0x4c, 0xf5, 0xe9, 0xc5, 0x45, 0x3e, 0x9f, 0x7c, 0xfd, 0x2b,
|
||||
0x8b, 0x4c, 0x8d, 0x16, 0x9a, 0x44, 0xe5, 0x5c, 0x88, 0xd4, 0xa9, 0xa7, 0xf9, 0x47, 0x42, 0x41,
|
||||
0xe2, 0x21, 0xaf, 0x44, 0x86, 0x00, 0x18, 0xab, 0x08, 0x56, 0x97, 0x2e, 0x19, 0x4c, 0xd9, 0x34,
|
||||
];
|
||||
|
||||
const INITIAL_PACKET_29: &str = "cdff00001d088394c8f03e5157080000\
|
||||
449e9cdb990bfb66bc6a93032b50dd89\
|
||||
73972d149421874d3849e3708d71354e\
|
||||
a33bcdc356f3ea6e2a1a1bd7c3d14003\
|
||||
8d3e784d04c30a2cdb40c32523aba2da\
|
||||
fe1c1bf3d27a6be38fe38ae033fbb071\
|
||||
3c1c73661bb6639795b42b97f77068ea\
|
||||
d51f11fbf9489af2501d09481e6c64d4\
|
||||
b8551cd3cea70d830ce2aeeec789ef55\
|
||||
1a7fbe36b3f7e1549a9f8d8e153b3fac\
|
||||
3fb7b7812c9ed7c20b4be190ebd89956\
|
||||
26e7f0fc887925ec6f0606c5d36aa81b\
|
||||
ebb7aacdc4a31bb5f23d55faef5c5190\
|
||||
5783384f375a43235b5c742c78ab1bae\
|
||||
0a188b75efbde6b3774ed61282f9670a\
|
||||
9dea19e1566103ce675ab4e21081fb58\
|
||||
60340a1e88e4f10e39eae25cd685b109\
|
||||
29636d4f02e7fad2a5a458249f5c0298\
|
||||
a6d53acbe41a7fc83fa7cc01973f7a74\
|
||||
d1237a51974e097636b6203997f921d0\
|
||||
7bc1940a6f2d0de9f5a11432946159ed\
|
||||
6cc21df65c4ddd1115f86427259a196c\
|
||||
7148b25b6478b0dc7766e1c4d1b1f515\
|
||||
9f90eabc61636226244642ee148b464c\
|
||||
9e619ee50a5e3ddc836227cad938987c\
|
||||
4ea3c1fa7c75bbf88d89e9ada642b2b8\
|
||||
8fe8107b7ea375b1b64889a4e9e5c38a\
|
||||
1c896ce275a5658d250e2d76e1ed3a34\
|
||||
ce7e3a3f383d0c996d0bed106c2899ca\
|
||||
6fc263ef0455e74bb6ac1640ea7bfedc\
|
||||
59f03fee0e1725ea150ff4d69a7660c5\
|
||||
542119c71de270ae7c3ecfd1af2c4ce5\
|
||||
51986949cc34a66b3e216bfe18b347e6\
|
||||
c05fd050f85912db303a8f054ec23e38\
|
||||
f44d1c725ab641ae929fecc8e3cefa56\
|
||||
19df4231f5b4c009fa0c0bbc60bc75f7\
|
||||
6d06ef154fc8577077d9d6a1d2bd9bf0\
|
||||
81dc783ece60111bea7da9e5a9748069\
|
||||
d078b2bef48de04cabe3755b197d52b3\
|
||||
2046949ecaa310274b4aac0d008b1948\
|
||||
c1082cdfe2083e386d4fd84c0ed0666d\
|
||||
3ee26c4515c4fee73433ac703b690a9f\
|
||||
7bf278a77486ace44c489a0c7ac8dfe4\
|
||||
d1a58fb3a730b993ff0f0d61b4d89557\
|
||||
831eb4c752ffd39c10f6b9f46d8db278\
|
||||
da624fd800e4af85548a294c1518893a\
|
||||
8778c4f6d6d73c93df200960104e062b\
|
||||
388ea97dcf4016bced7f62b4f062cb6c\
|
||||
04c20693d9a0e3b74ba8fe74cc012378\
|
||||
84f40d765ae56a51688d985cf0ceaef4\
|
||||
3045ed8c3f0c33bced08537f6882613a\
|
||||
cd3b08d665fce9dd8aa73171e2d3771a\
|
||||
61dba2790e491d413d93d987e2745af2\
|
||||
9418e428be34941485c93447520ffe23\
|
||||
1da2304d6a0fd5d07d08372202369661\
|
||||
59bef3cf904d722324dd852513df39ae\
|
||||
030d8173908da6364786d3c1bfcb19ea\
|
||||
77a63b25f1e7fc661def480c5d00d444\
|
||||
56269ebd84efd8e3a8b2c257eec76060\
|
||||
682848cbf5194bc99e49ee75e4d0d254\
|
||||
bad4bfd74970c30e44b65511d4ad0e6e\
|
||||
c7398e08e01307eeeea14e46ccd87cf3\
|
||||
6b285221254d8fc6a6765c524ded0085\
|
||||
dca5bd688ddf722e2c0faf9d0fb2ce7a\
|
||||
0c3f2cee19ca0ffba461ca8dc5d2c817\
|
||||
8b0762cf67135558494d2a96f1a139f0\
|
||||
edb42d2af89a9c9122b07acbc29e5e72\
|
||||
2df8615c343702491098478a389c9872\
|
||||
a10b0c9875125e257c7bfdf27eef4060\
|
||||
bd3d00f4c14fd3e3496c38d3c5d1a566\
|
||||
8c39350effbc2d16ca17be4ce29f02ed\
|
||||
969504dda2a8c6b9ff919e693ee79e09\
|
||||
089316e7d1d89ec099db3b2b268725d8\
|
||||
88536a4b8bf9aee8fb43e82a4d919d48\
|
||||
1802771a449b30f3fa2289852607b660";
|
||||
const INITIAL_PACKET_27: &[u8] = &[
|
||||
0xc0, 0xff, 0x00, 0x00, 0x1b, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00,
|
||||
0x44, 0x9e, 0x3b, 0x34, 0x3a, 0xa8, 0x53, 0x50, 0x64, 0xa4, 0x26, 0x8a, 0x0d, 0x9d, 0x7b, 0x1c,
|
||||
0x9d, 0x25, 0x0a, 0xe3, 0x55, 0x16, 0x22, 0x76, 0xe9, 0xb1, 0xe3, 0x01, 0x1e, 0xf6, 0xbb, 0xc0,
|
||||
0xab, 0x48, 0xad, 0x5b, 0xcc, 0x26, 0x81, 0xe9, 0x53, 0x85, 0x7c, 0xa6, 0x2b, 0xec, 0xd7, 0x52,
|
||||
0x4d, 0xaa, 0xc4, 0x73, 0xe6, 0x8d, 0x74, 0x05, 0xfb, 0xba, 0x4e, 0x9e, 0xe6, 0x16, 0xc8, 0x70,
|
||||
0x38, 0xbd, 0xbe, 0x90, 0x8c, 0x06, 0xd9, 0x60, 0x5d, 0x9a, 0xc4, 0x90, 0x30, 0x35, 0x9e, 0xec,
|
||||
0xb1, 0xd0, 0x5a, 0x14, 0xe1, 0x17, 0xdb, 0x8c, 0xed, 0xe2, 0xbb, 0x09, 0xd0, 0xdb, 0xbf, 0xee,
|
||||
0x27, 0x1c, 0xb3, 0x74, 0xd8, 0xf1, 0x0a, 0xbe, 0xc8, 0x2d, 0x0f, 0x59, 0xa1, 0xde, 0xe2, 0x9f,
|
||||
0xe9, 0x56, 0x38, 0xed, 0x8d, 0xd4, 0x1d, 0xa0, 0x74, 0x87, 0x46, 0x87, 0x91, 0xb7, 0x19, 0xc5,
|
||||
0x5c, 0x46, 0x96, 0x8e, 0xb3, 0xb5, 0x46, 0x80, 0x03, 0x71, 0x02, 0xa2, 0x8e, 0x53, 0xdc, 0x1d,
|
||||
0x12, 0x90, 0x3d, 0xb0, 0xaf, 0x58, 0x21, 0x79, 0x4b, 0x41, 0xc4, 0xa9, 0x33, 0x57, 0xfa, 0x59,
|
||||
0xce, 0x69, 0xcf, 0xe7, 0xf6, 0xbd, 0xfa, 0x62, 0x9e, 0xef, 0x78, 0x61, 0x64, 0x47, 0xe1, 0xd6,
|
||||
0x11, 0xc4, 0xba, 0xf7, 0x1b, 0xf3, 0x3f, 0xeb, 0xcb, 0x03, 0x13, 0x7c, 0x2c, 0x75, 0xd2, 0x53,
|
||||
0x17, 0xd3, 0xe1, 0x3b, 0x68, 0x43, 0x70, 0xf6, 0x68, 0x41, 0x1c, 0x0f, 0x00, 0x30, 0x4b, 0x50,
|
||||
0x1c, 0x8f, 0xd4, 0x22, 0xbd, 0x9b, 0x9a, 0xd8, 0x1d, 0x64, 0x3b, 0x20, 0xda, 0x89, 0xca, 0x05,
|
||||
0x25, 0xd2, 0x4d, 0x2b, 0x14, 0x20, 0x41, 0xca, 0xe0, 0xaf, 0x20, 0x50, 0x92, 0xe4, 0x30, 0x08,
|
||||
0x0c, 0xd8, 0x55, 0x9e, 0xa4, 0xc5, 0xc6, 0xe4, 0xfa, 0x3f, 0x66, 0x08, 0x2b, 0x7d, 0x30, 0x3e,
|
||||
0x52, 0xce, 0x01, 0x62, 0xba, 0xa9, 0x58, 0x53, 0x2b, 0x0b, 0xbc, 0x2b, 0xc7, 0x85, 0x68, 0x1f,
|
||||
0xcf, 0x37, 0x48, 0x5d, 0xff, 0x65, 0x95, 0xe0, 0x1e, 0x73, 0x9c, 0x8a, 0xc9, 0xef, 0xba, 0x31,
|
||||
0xb9, 0x85, 0xd5, 0xf6, 0x56, 0xcc, 0x09, 0x24, 0x32, 0xd7, 0x81, 0xdb, 0x95, 0x22, 0x17, 0x24,
|
||||
0x87, 0x64, 0x1c, 0x4d, 0x3a, 0xb8, 0xec, 0xe0, 0x1e, 0x39, 0xbc, 0x85, 0xb1, 0x54, 0x36, 0x61,
|
||||
0x47, 0x75, 0xa9, 0x8b, 0xa8, 0xfa, 0x12, 0xd4, 0x6f, 0x9b, 0x35, 0xe2, 0xa5, 0x5e, 0xb7, 0x2d,
|
||||
0x7f, 0x85, 0x18, 0x1a, 0x36, 0x66, 0x63, 0x38, 0x7d, 0xdc, 0x20, 0x55, 0x18, 0x07, 0xe0, 0x07,
|
||||
0x67, 0x3b, 0xd7, 0xe2, 0x6b, 0xf9, 0xb2, 0x9b, 0x5a, 0xb1, 0x0a, 0x1c, 0xa8, 0x7c, 0xbb, 0x7a,
|
||||
0xd9, 0x7e, 0x99, 0xeb, 0x66, 0x95, 0x9c, 0x2a, 0x9b, 0xc3, 0xcb, 0xde, 0x47, 0x07, 0xff, 0x77,
|
||||
0x20, 0xb1, 0x10, 0xfa, 0x95, 0x35, 0x46, 0x74, 0xe3, 0x95, 0x81, 0x2e, 0x47, 0xa0, 0xae, 0x53,
|
||||
0xb4, 0x64, 0xdc, 0xb2, 0xd1, 0xf3, 0x45, 0xdf, 0x36, 0x0d, 0xc2, 0x27, 0x27, 0x0c, 0x75, 0x06,
|
||||
0x76, 0xf6, 0x72, 0x4e, 0xb4, 0x79, 0xf0, 0xd2, 0xfb, 0xb6, 0x12, 0x44, 0x29, 0x99, 0x04, 0x57,
|
||||
0xac, 0x6c, 0x91, 0x67, 0xf4, 0x0a, 0xab, 0x73, 0x99, 0x98, 0xf3, 0x8b, 0x9e, 0xcc, 0xb2, 0x4f,
|
||||
0xd4, 0x7c, 0x84, 0x10, 0x13, 0x1b, 0xf6, 0x5a, 0x52, 0xaf, 0x84, 0x12, 0x75, 0xd5, 0xb3, 0xd1,
|
||||
0x88, 0x0b, 0x19, 0x7d, 0xf2, 0xb5, 0xde, 0xa3, 0xe6, 0xde, 0x56, 0xeb, 0xce, 0x3f, 0xfb, 0x6e,
|
||||
0x92, 0x77, 0xa8, 0x20, 0x82, 0xf8, 0xd9, 0x67, 0x7a, 0x67, 0x67, 0x08, 0x9b, 0x67, 0x1e, 0xbd,
|
||||
0x24, 0x4c, 0x21, 0x4f, 0x0b, 0xde, 0x95, 0xc2, 0xbe, 0xb0, 0x2c, 0xd1, 0x17, 0x2d, 0x58, 0xbd,
|
||||
0xf3, 0x9d, 0xce, 0x56, 0xff, 0x68, 0xeb, 0x35, 0xab, 0x39, 0xb4, 0x9b, 0x4e, 0xac, 0x7c, 0x81,
|
||||
0x5e, 0xa6, 0x04, 0x51, 0xd6, 0xe6, 0xab, 0x82, 0x11, 0x91, 0x18, 0xdf, 0x02, 0xa5, 0x86, 0x84,
|
||||
0x4a, 0x9f, 0xfe, 0x16, 0x2b, 0xa0, 0x06, 0xd0, 0x66, 0x9e, 0xf5, 0x76, 0x68, 0xca, 0xb3, 0x8b,
|
||||
0x62, 0xf7, 0x1a, 0x25, 0x23, 0xa0, 0x84, 0x85, 0x2c, 0xd1, 0xd0, 0x79, 0xb3, 0x65, 0x8d, 0xc2,
|
||||
0xf3, 0xe8, 0x79, 0x49, 0xb5, 0x50, 0xba, 0xb3, 0xe1, 0x77, 0xcf, 0xc4, 0x9e, 0xd1, 0x90, 0xdf,
|
||||
0xf0, 0x63, 0x0e, 0x43, 0x07, 0x7c, 0x30, 0xde, 0x8f, 0x6a, 0xe0, 0x81, 0x53, 0x7f, 0x1e, 0x83,
|
||||
0xda, 0x53, 0x7d, 0xa9, 0x80, 0xaf, 0xa6, 0x68, 0xe7, 0xb7, 0xfb, 0x25, 0x30, 0x1c, 0xf7, 0x41,
|
||||
0x52, 0x4b, 0xe3, 0xc4, 0x98, 0x84, 0xb4, 0x28, 0x21, 0xf1, 0x75, 0x52, 0xfb, 0xd1, 0x93, 0x1a,
|
||||
0x81, 0x30, 0x17, 0xb6, 0xb6, 0x59, 0x0a, 0x41, 0xea, 0x18, 0xb6, 0xba, 0x49, 0xcd, 0x48, 0xa4,
|
||||
0x40, 0xbd, 0x9a, 0x33, 0x46, 0xa7, 0x62, 0x3f, 0xb4, 0xba, 0x34, 0xa3, 0xee, 0x57, 0x1e, 0x3c,
|
||||
0x73, 0x1f, 0x35, 0xa7, 0xa3, 0xcf, 0x25, 0xb5, 0x51, 0xa6, 0x80, 0xfa, 0x68, 0x76, 0x35, 0x07,
|
||||
0xb7, 0xfd, 0xe3, 0xaa, 0xf0, 0x23, 0xc5, 0x0b, 0x9d, 0x22, 0xda, 0x68, 0x76, 0xba, 0x33, 0x7e,
|
||||
0xb5, 0xe9, 0xdd, 0x9e, 0xc3, 0xda, 0xf9, 0x70, 0x24, 0x2b, 0x6c, 0x5a, 0xab, 0x3a, 0xa4, 0xb2,
|
||||
0x96, 0xad, 0x8b, 0x9f, 0x68, 0x32, 0xf6, 0x86, 0xef, 0x70, 0xfa, 0x93, 0x8b, 0x31, 0xb4, 0xe5,
|
||||
0xdd, 0xd7, 0x36, 0x44, 0x42, 0xd3, 0xea, 0x72, 0xe7, 0x3d, 0x66, 0x8f, 0xb0, 0x93, 0x77, 0x96,
|
||||
0xf4, 0x62, 0x92, 0x3a, 0x81, 0xa4, 0x7e, 0x1c, 0xee, 0x74, 0x26, 0xff, 0x6d, 0x92, 0x21, 0x26,
|
||||
0x9b, 0x5a, 0x62, 0xec, 0x03, 0xd6, 0xec, 0x94, 0xd1, 0x26, 0x06, 0xcb, 0x48, 0x55, 0x60, 0xba,
|
||||
0xb5, 0x74, 0x81, 0x60, 0x09, 0xe9, 0x65, 0x04, 0x24, 0x93, 0x85, 0xbb, 0x61, 0xa8, 0x19, 0xbe,
|
||||
0x04, 0xf6, 0x2c, 0x20, 0x66, 0x21, 0x4d, 0x83, 0x60, 0xa2, 0x02, 0x2b, 0xeb, 0x31, 0x62, 0x40,
|
||||
0xb6, 0xc7, 0xd7, 0x8b, 0xbe, 0x56, 0xc1, 0x30, 0x82, 0xe0, 0xca, 0x27, 0x26, 0x61, 0x21, 0x0a,
|
||||
0xbf, 0x02, 0x0b, 0xf3, 0xb5, 0x78, 0x3f, 0x14, 0x26, 0x43, 0x6c, 0xf9, 0xff, 0x41, 0x84, 0x05,
|
||||
0x93, 0xa5, 0xd0, 0x63, 0x8d, 0x32, 0xfc, 0x51, 0xc5, 0xc6, 0x5f, 0xf2, 0x91, 0xa3, 0xa7, 0xa5,
|
||||
0x2f, 0xd6, 0x77, 0x5e, 0x62, 0x3a, 0x44, 0x39, 0xcc, 0x08, 0xdd, 0x25, 0x58, 0x2f, 0xeb, 0xc9,
|
||||
0x44, 0xef, 0x92, 0xd8, 0xdb, 0xd3, 0x29, 0xc9, 0x1d, 0xe3, 0xe9, 0xc9, 0x58, 0x2e, 0x41, 0xf1,
|
||||
0x7f, 0x3d, 0x18, 0x6f, 0x10, 0x4a, 0xd3, 0xf9, 0x09, 0x95, 0x11, 0x6c, 0x68, 0x2a, 0x2a, 0x14,
|
||||
0xa3, 0xb4, 0xb1, 0xf5, 0x47, 0xc3, 0x35, 0xf0, 0xbe, 0x71, 0x0f, 0xc9, 0xfc, 0x03, 0xe0, 0xe5,
|
||||
0x87, 0xb8, 0xcd, 0xa3, 0x1c, 0xe6, 0x5b, 0x96, 0x98, 0x78, 0xa4, 0xad, 0x42, 0x83, 0xe6, 0xd5,
|
||||
0xb0, 0x37, 0x3f, 0x43, 0xda, 0x86, 0xe9, 0xe0, 0xff, 0xe1, 0xae, 0x0f, 0xdd, 0xd3, 0x51, 0x62,
|
||||
0x55, 0xbd, 0x74, 0x56, 0x6f, 0x36, 0xa3, 0x87, 0x03, 0xd5, 0xf3, 0x42, 0x49, 0xde, 0xd1, 0xf6,
|
||||
0x6b, 0x3d, 0x9b, 0x45, 0xb9, 0xaf, 0x2c, 0xcf, 0xef, 0xe9, 0x84, 0xe1, 0x33, 0x76, 0xb1, 0xb2,
|
||||
0xc6, 0x40, 0x4a, 0xa4, 0x8c, 0x80, 0x26, 0x13, 0x23, 0x43, 0xda, 0x3f, 0x3a, 0x33, 0x65, 0x9e,
|
||||
0xc1, 0xb3, 0xe9, 0x50, 0x80, 0x54, 0x0b, 0x28, 0xb7, 0xf3, 0xfc, 0xd3, 0x5f, 0xa5, 0xd8, 0x43,
|
||||
0xb5, 0x79, 0xa8, 0x4c, 0x08, 0x91, 0x21, 0xa6, 0x0d, 0x8c, 0x17, 0x54, 0x91, 0x5c, 0x34, 0x4e,
|
||||
0xea, 0xf4, 0x5a, 0x9b, 0xf2, 0x7d, 0xc0, 0xc1, 0xe7, 0x84, 0x16, 0x16, 0x91, 0x22, 0x09, 0x13,
|
||||
0x13, 0xeb, 0x0e, 0x87, 0x55, 0x5a, 0xbd, 0x70, 0x66, 0x26, 0xe5, 0x57, 0xfc, 0x36, 0xa0, 0x4f,
|
||||
0xcd, 0x19, 0x1a, 0x58, 0x82, 0x91, 0x04, 0xd6, 0x07, 0x5c, 0x55, 0x94, 0xf6, 0x27, 0xca, 0x50,
|
||||
0x6b, 0xf1, 0x81, 0xda, 0xec, 0x94, 0x0f, 0x4a, 0x4f, 0x3a, 0xf0, 0x07, 0x4e, 0xee, 0x89, 0xda,
|
||||
0xac, 0xde, 0x67, 0x58, 0x31, 0x26, 0x22, 0xd4, 0xfa, 0x67, 0x5b, 0x39, 0xf7, 0x28, 0xe0, 0x62,
|
||||
0xd2, 0xbe, 0xe6, 0x80, 0xd8, 0xf4, 0x1a, 0x59, 0x7c, 0x26, 0x26, 0x48, 0xbb, 0x18, 0xbc, 0xfc,
|
||||
0x13, 0xc8, 0xb3, 0xd9, 0x7b, 0x1a, 0x77, 0xb2, 0xac, 0x3a, 0xf7, 0x45, 0xd6, 0x1a, 0x34, 0xcc,
|
||||
0x47, 0x09, 0x86, 0x5b, 0xac, 0x82, 0x4a, 0x94, 0xbb, 0x19, 0x05, 0x80, 0x15, 0xe4, 0xe4, 0x2d,
|
||||
0x38, 0xd3, 0xb7, 0x79, 0xd7, 0x2e, 0xdc, 0x00, 0xc5, 0xcd, 0x08, 0x8e, 0xff, 0x80, 0x2b, 0x05,
|
||||
];
|
||||
|
||||
const INITIAL_PACKET_29: &[u8] = &[
|
||||
0xcd, 0xff, 0x00, 0x00, 0x1d, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00,
|
||||
0x44, 0x9e, 0x9c, 0xdb, 0x99, 0x0b, 0xfb, 0x66, 0xbc, 0x6a, 0x93, 0x03, 0x2b, 0x50, 0xdd, 0x89,
|
||||
0x73, 0x97, 0x2d, 0x14, 0x94, 0x21, 0x87, 0x4d, 0x38, 0x49, 0xe3, 0x70, 0x8d, 0x71, 0x35, 0x4e,
|
||||
0xa3, 0x3b, 0xcd, 0xc3, 0x56, 0xf3, 0xea, 0x6e, 0x2a, 0x1a, 0x1b, 0xd7, 0xc3, 0xd1, 0x40, 0x03,
|
||||
0x8d, 0x3e, 0x78, 0x4d, 0x04, 0xc3, 0x0a, 0x2c, 0xdb, 0x40, 0xc3, 0x25, 0x23, 0xab, 0xa2, 0xda,
|
||||
0xfe, 0x1c, 0x1b, 0xf3, 0xd2, 0x7a, 0x6b, 0xe3, 0x8f, 0xe3, 0x8a, 0xe0, 0x33, 0xfb, 0xb0, 0x71,
|
||||
0x3c, 0x1c, 0x73, 0x66, 0x1b, 0xb6, 0x63, 0x97, 0x95, 0xb4, 0x2b, 0x97, 0xf7, 0x70, 0x68, 0xea,
|
||||
0xd5, 0x1f, 0x11, 0xfb, 0xf9, 0x48, 0x9a, 0xf2, 0x50, 0x1d, 0x09, 0x48, 0x1e, 0x6c, 0x64, 0xd4,
|
||||
0xb8, 0x55, 0x1c, 0xd3, 0xce, 0xa7, 0x0d, 0x83, 0x0c, 0xe2, 0xae, 0xee, 0xc7, 0x89, 0xef, 0x55,
|
||||
0x1a, 0x7f, 0xbe, 0x36, 0xb3, 0xf7, 0xe1, 0x54, 0x9a, 0x9f, 0x8d, 0x8e, 0x15, 0x3b, 0x3f, 0xac,
|
||||
0x3f, 0xb7, 0xb7, 0x81, 0x2c, 0x9e, 0xd7, 0xc2, 0x0b, 0x4b, 0xe1, 0x90, 0xeb, 0xd8, 0x99, 0x56,
|
||||
0x26, 0xe7, 0xf0, 0xfc, 0x88, 0x79, 0x25, 0xec, 0x6f, 0x06, 0x06, 0xc5, 0xd3, 0x6a, 0xa8, 0x1b,
|
||||
0xeb, 0xb7, 0xaa, 0xcd, 0xc4, 0xa3, 0x1b, 0xb5, 0xf2, 0x3d, 0x55, 0xfa, 0xef, 0x5c, 0x51, 0x90,
|
||||
0x57, 0x83, 0x38, 0x4f, 0x37, 0x5a, 0x43, 0x23, 0x5b, 0x5c, 0x74, 0x2c, 0x78, 0xab, 0x1b, 0xae,
|
||||
0x0a, 0x18, 0x8b, 0x75, 0xef, 0xbd, 0xe6, 0xb3, 0x77, 0x4e, 0xd6, 0x12, 0x82, 0xf9, 0x67, 0x0a,
|
||||
0x9d, 0xea, 0x19, 0xe1, 0x56, 0x61, 0x03, 0xce, 0x67, 0x5a, 0xb4, 0xe2, 0x10, 0x81, 0xfb, 0x58,
|
||||
0x60, 0x34, 0x0a, 0x1e, 0x88, 0xe4, 0xf1, 0x0e, 0x39, 0xea, 0xe2, 0x5c, 0xd6, 0x85, 0xb1, 0x09,
|
||||
0x29, 0x63, 0x6d, 0x4f, 0x02, 0xe7, 0xfa, 0xd2, 0xa5, 0xa4, 0x58, 0x24, 0x9f, 0x5c, 0x02, 0x98,
|
||||
0xa6, 0xd5, 0x3a, 0xcb, 0xe4, 0x1a, 0x7f, 0xc8, 0x3f, 0xa7, 0xcc, 0x01, 0x97, 0x3f, 0x7a, 0x74,
|
||||
0xd1, 0x23, 0x7a, 0x51, 0x97, 0x4e, 0x09, 0x76, 0x36, 0xb6, 0x20, 0x39, 0x97, 0xf9, 0x21, 0xd0,
|
||||
0x7b, 0xc1, 0x94, 0x0a, 0x6f, 0x2d, 0x0d, 0xe9, 0xf5, 0xa1, 0x14, 0x32, 0x94, 0x61, 0x59, 0xed,
|
||||
0x6c, 0xc2, 0x1d, 0xf6, 0x5c, 0x4d, 0xdd, 0x11, 0x15, 0xf8, 0x64, 0x27, 0x25, 0x9a, 0x19, 0x6c,
|
||||
0x71, 0x48, 0xb2, 0x5b, 0x64, 0x78, 0xb0, 0xdc, 0x77, 0x66, 0xe1, 0xc4, 0xd1, 0xb1, 0xf5, 0x15,
|
||||
0x9f, 0x90, 0xea, 0xbc, 0x61, 0x63, 0x62, 0x26, 0x24, 0x46, 0x42, 0xee, 0x14, 0x8b, 0x46, 0x4c,
|
||||
0x9e, 0x61, 0x9e, 0xe5, 0x0a, 0x5e, 0x3d, 0xdc, 0x83, 0x62, 0x27, 0xca, 0xd9, 0x38, 0x98, 0x7c,
|
||||
0x4e, 0xa3, 0xc1, 0xfa, 0x7c, 0x75, 0xbb, 0xf8, 0x8d, 0x89, 0xe9, 0xad, 0xa6, 0x42, 0xb2, 0xb8,
|
||||
0x8f, 0xe8, 0x10, 0x7b, 0x7e, 0xa3, 0x75, 0xb1, 0xb6, 0x48, 0x89, 0xa4, 0xe9, 0xe5, 0xc3, 0x8a,
|
||||
0x1c, 0x89, 0x6c, 0xe2, 0x75, 0xa5, 0x65, 0x8d, 0x25, 0x0e, 0x2d, 0x76, 0xe1, 0xed, 0x3a, 0x34,
|
||||
0xce, 0x7e, 0x3a, 0x3f, 0x38, 0x3d, 0x0c, 0x99, 0x6d, 0x0b, 0xed, 0x10, 0x6c, 0x28, 0x99, 0xca,
|
||||
0x6f, 0xc2, 0x63, 0xef, 0x04, 0x55, 0xe7, 0x4b, 0xb6, 0xac, 0x16, 0x40, 0xea, 0x7b, 0xfe, 0xdc,
|
||||
0x59, 0xf0, 0x3f, 0xee, 0x0e, 0x17, 0x25, 0xea, 0x15, 0x0f, 0xf4, 0xd6, 0x9a, 0x76, 0x60, 0xc5,
|
||||
0x54, 0x21, 0x19, 0xc7, 0x1d, 0xe2, 0x70, 0xae, 0x7c, 0x3e, 0xcf, 0xd1, 0xaf, 0x2c, 0x4c, 0xe5,
|
||||
0x51, 0x98, 0x69, 0x49, 0xcc, 0x34, 0xa6, 0x6b, 0x3e, 0x21, 0x6b, 0xfe, 0x18, 0xb3, 0x47, 0xe6,
|
||||
0xc0, 0x5f, 0xd0, 0x50, 0xf8, 0x59, 0x12, 0xdb, 0x30, 0x3a, 0x8f, 0x05, 0x4e, 0xc2, 0x3e, 0x38,
|
||||
0xf4, 0x4d, 0x1c, 0x72, 0x5a, 0xb6, 0x41, 0xae, 0x92, 0x9f, 0xec, 0xc8, 0xe3, 0xce, 0xfa, 0x56,
|
||||
0x19, 0xdf, 0x42, 0x31, 0xf5, 0xb4, 0xc0, 0x09, 0xfa, 0x0c, 0x0b, 0xbc, 0x60, 0xbc, 0x75, 0xf7,
|
||||
0x6d, 0x06, 0xef, 0x15, 0x4f, 0xc8, 0x57, 0x70, 0x77, 0xd9, 0xd6, 0xa1, 0xd2, 0xbd, 0x9b, 0xf0,
|
||||
0x81, 0xdc, 0x78, 0x3e, 0xce, 0x60, 0x11, 0x1b, 0xea, 0x7d, 0xa9, 0xe5, 0xa9, 0x74, 0x80, 0x69,
|
||||
0xd0, 0x78, 0xb2, 0xbe, 0xf4, 0x8d, 0xe0, 0x4c, 0xab, 0xe3, 0x75, 0x5b, 0x19, 0x7d, 0x52, 0xb3,
|
||||
0x20, 0x46, 0x94, 0x9e, 0xca, 0xa3, 0x10, 0x27, 0x4b, 0x4a, 0xac, 0x0d, 0x00, 0x8b, 0x19, 0x48,
|
||||
0xc1, 0x08, 0x2c, 0xdf, 0xe2, 0x08, 0x3e, 0x38, 0x6d, 0x4f, 0xd8, 0x4c, 0x0e, 0xd0, 0x66, 0x6d,
|
||||
0x3e, 0xe2, 0x6c, 0x45, 0x15, 0xc4, 0xfe, 0xe7, 0x34, 0x33, 0xac, 0x70, 0x3b, 0x69, 0x0a, 0x9f,
|
||||
0x7b, 0xf2, 0x78, 0xa7, 0x74, 0x86, 0xac, 0xe4, 0x4c, 0x48, 0x9a, 0x0c, 0x7a, 0xc8, 0xdf, 0xe4,
|
||||
0xd1, 0xa5, 0x8f, 0xb3, 0xa7, 0x30, 0xb9, 0x93, 0xff, 0x0f, 0x0d, 0x61, 0xb4, 0xd8, 0x95, 0x57,
|
||||
0x83, 0x1e, 0xb4, 0xc7, 0x52, 0xff, 0xd3, 0x9c, 0x10, 0xf6, 0xb9, 0xf4, 0x6d, 0x8d, 0xb2, 0x78,
|
||||
0xda, 0x62, 0x4f, 0xd8, 0x00, 0xe4, 0xaf, 0x85, 0x54, 0x8a, 0x29, 0x4c, 0x15, 0x18, 0x89, 0x3a,
|
||||
0x87, 0x78, 0xc4, 0xf6, 0xd6, 0xd7, 0x3c, 0x93, 0xdf, 0x20, 0x09, 0x60, 0x10, 0x4e, 0x06, 0x2b,
|
||||
0x38, 0x8e, 0xa9, 0x7d, 0xcf, 0x40, 0x16, 0xbc, 0xed, 0x7f, 0x62, 0xb4, 0xf0, 0x62, 0xcb, 0x6c,
|
||||
0x04, 0xc2, 0x06, 0x93, 0xd9, 0xa0, 0xe3, 0xb7, 0x4b, 0xa8, 0xfe, 0x74, 0xcc, 0x01, 0x23, 0x78,
|
||||
0x84, 0xf4, 0x0d, 0x76, 0x5a, 0xe5, 0x6a, 0x51, 0x68, 0x8d, 0x98, 0x5c, 0xf0, 0xce, 0xae, 0xf4,
|
||||
0x30, 0x45, 0xed, 0x8c, 0x3f, 0x0c, 0x33, 0xbc, 0xed, 0x08, 0x53, 0x7f, 0x68, 0x82, 0x61, 0x3a,
|
||||
0xcd, 0x3b, 0x08, 0xd6, 0x65, 0xfc, 0xe9, 0xdd, 0x8a, 0xa7, 0x31, 0x71, 0xe2, 0xd3, 0x77, 0x1a,
|
||||
0x61, 0xdb, 0xa2, 0x79, 0x0e, 0x49, 0x1d, 0x41, 0x3d, 0x93, 0xd9, 0x87, 0xe2, 0x74, 0x5a, 0xf2,
|
||||
0x94, 0x18, 0xe4, 0x28, 0xbe, 0x34, 0x94, 0x14, 0x85, 0xc9, 0x34, 0x47, 0x52, 0x0f, 0xfe, 0x23,
|
||||
0x1d, 0xa2, 0x30, 0x4d, 0x6a, 0x0f, 0xd5, 0xd0, 0x7d, 0x08, 0x37, 0x22, 0x02, 0x36, 0x96, 0x61,
|
||||
0x59, 0xbe, 0xf3, 0xcf, 0x90, 0x4d, 0x72, 0x23, 0x24, 0xdd, 0x85, 0x25, 0x13, 0xdf, 0x39, 0xae,
|
||||
0x03, 0x0d, 0x81, 0x73, 0x90, 0x8d, 0xa6, 0x36, 0x47, 0x86, 0xd3, 0xc1, 0xbf, 0xcb, 0x19, 0xea,
|
||||
0x77, 0xa6, 0x3b, 0x25, 0xf1, 0xe7, 0xfc, 0x66, 0x1d, 0xef, 0x48, 0x0c, 0x5d, 0x00, 0xd4, 0x44,
|
||||
0x56, 0x26, 0x9e, 0xbd, 0x84, 0xef, 0xd8, 0xe3, 0xa8, 0xb2, 0xc2, 0x57, 0xee, 0xc7, 0x60, 0x60,
|
||||
0x68, 0x28, 0x48, 0xcb, 0xf5, 0x19, 0x4b, 0xc9, 0x9e, 0x49, 0xee, 0x75, 0xe4, 0xd0, 0xd2, 0x54,
|
||||
0xba, 0xd4, 0xbf, 0xd7, 0x49, 0x70, 0xc3, 0x0e, 0x44, 0xb6, 0x55, 0x11, 0xd4, 0xad, 0x0e, 0x6e,
|
||||
0xc7, 0x39, 0x8e, 0x08, 0xe0, 0x13, 0x07, 0xee, 0xee, 0xa1, 0x4e, 0x46, 0xcc, 0xd8, 0x7c, 0xf3,
|
||||
0x6b, 0x28, 0x52, 0x21, 0x25, 0x4d, 0x8f, 0xc6, 0xa6, 0x76, 0x5c, 0x52, 0x4d, 0xed, 0x00, 0x85,
|
||||
0xdc, 0xa5, 0xbd, 0x68, 0x8d, 0xdf, 0x72, 0x2e, 0x2c, 0x0f, 0xaf, 0x9d, 0x0f, 0xb2, 0xce, 0x7a,
|
||||
0x0c, 0x3f, 0x2c, 0xee, 0x19, 0xca, 0x0f, 0xfb, 0xa4, 0x61, 0xca, 0x8d, 0xc5, 0xd2, 0xc8, 0x17,
|
||||
0x8b, 0x07, 0x62, 0xcf, 0x67, 0x13, 0x55, 0x58, 0x49, 0x4d, 0x2a, 0x96, 0xf1, 0xa1, 0x39, 0xf0,
|
||||
0xed, 0xb4, 0x2d, 0x2a, 0xf8, 0x9a, 0x9c, 0x91, 0x22, 0xb0, 0x7a, 0xcb, 0xc2, 0x9e, 0x5e, 0x72,
|
||||
0x2d, 0xf8, 0x61, 0x5c, 0x34, 0x37, 0x02, 0x49, 0x10, 0x98, 0x47, 0x8a, 0x38, 0x9c, 0x98, 0x72,
|
||||
0xa1, 0x0b, 0x0c, 0x98, 0x75, 0x12, 0x5e, 0x25, 0x7c, 0x7b, 0xfd, 0xf2, 0x7e, 0xef, 0x40, 0x60,
|
||||
0xbd, 0x3d, 0x00, 0xf4, 0xc1, 0x4f, 0xd3, 0xe3, 0x49, 0x6c, 0x38, 0xd3, 0xc5, 0xd1, 0xa5, 0x66,
|
||||
0x8c, 0x39, 0x35, 0x0e, 0xff, 0xbc, 0x2d, 0x16, 0xca, 0x17, 0xbe, 0x4c, 0xe2, 0x9f, 0x02, 0xed,
|
||||
0x96, 0x95, 0x04, 0xdd, 0xa2, 0xa8, 0xc6, 0xb9, 0xff, 0x91, 0x9e, 0x69, 0x3e, 0xe7, 0x9e, 0x09,
|
||||
0x08, 0x93, 0x16, 0xe7, 0xd1, 0xd8, 0x9e, 0xc0, 0x99, 0xdb, 0x3b, 0x2b, 0x26, 0x87, 0x25, 0xd8,
|
||||
0x88, 0x53, 0x6a, 0x4b, 0x8b, 0xf9, 0xae, 0xe8, 0xfb, 0x43, 0xe8, 0x2a, 0x4d, 0x91, 0x9d, 0x48,
|
||||
0x18, 0x02, 0x77, 0x1a, 0x44, 0x9b, 0x30, 0xf3, 0xfa, 0x22, 0x89, 0x85, 0x26, 0x07, 0xb6, 0x60,
|
||||
];
|
||||
|
||||
fn make_server(quic_version: QuicVersion) -> Connection {
|
||||
test_fixture::fixture_init();
|
||||
@ -179,23 +261,27 @@ fn make_server(quic_version: QuicVersion) -> Connection {
|
||||
.expect("create a default server")
|
||||
}
|
||||
|
||||
fn process_client_initial(quic_version: QuicVersion, packet: &str) {
|
||||
fn process_client_initial(quic_version: QuicVersion, packet: &[u8]) {
|
||||
let mut server = make_server(quic_version);
|
||||
|
||||
let pkt: Vec<u8> = Encoder::from_hex(packet).into();
|
||||
let dgram = Datagram::new(addr(), addr(), pkt);
|
||||
let dgram = Datagram::new(addr(), addr(), packet);
|
||||
assert_eq!(*server.state(), State::Init);
|
||||
let out = server.process(Some(dgram), now());
|
||||
assert_eq!(*server.state(), State::Handshaking);
|
||||
assert!(out.dgram().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_client_initial_v1() {
|
||||
process_client_initial(QuicVersion::Version1, INITIAL_PACKET_V1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_client_initial_27() {
|
||||
process_client_initial(QuicVersion::Draft27, &INITIAL_PACKET_27);
|
||||
process_client_initial(QuicVersion::Draft27, INITIAL_PACKET_27);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_client_initial_29() {
|
||||
process_client_initial(QuicVersion::Draft29, &INITIAL_PACKET_29);
|
||||
process_client_initial(QuicVersion::Draft29, INITIAL_PACKET_29);
|
||||
}
|
||||
|
13
third_party/rust/neqo-transport/tests/server.rs
vendored
13
third_party/rust/neqo-transport/tests/server.rs
vendored
@ -98,7 +98,12 @@ fn complete_connection(
|
||||
server: &mut Server,
|
||||
mut datagram: Option<Datagram>,
|
||||
) -> ActiveConnectionRef {
|
||||
let is_done = |c: &Connection| matches!(c.state(), State::Confirmed | State::Closing { .. } | State::Closed(..));
|
||||
let is_done = |c: &Connection| {
|
||||
matches!(
|
||||
c.state(),
|
||||
State::Confirmed | State::Closing { .. } | State::Closed(..)
|
||||
)
|
||||
};
|
||||
while !is_done(client) {
|
||||
let _ = test_fixture::maybe_authenticate(client);
|
||||
let out = client.process(datagram, now());
|
||||
@ -695,8 +700,8 @@ fn vn_after_retry() {
|
||||
// Generate an AEAD and header protection object for a client Initial.
|
||||
fn client_initial_aead_and_hp(dcid: &[u8]) -> (Aead, HpKey) {
|
||||
const INITIAL_SALT: &[u8] = &[
|
||||
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11,
|
||||
0xe0, 0x43, 0x90, 0xa8, 0x99,
|
||||
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c,
|
||||
0xad, 0xcc, 0xbb, 0x7f, 0x0a,
|
||||
];
|
||||
let initial_secret = hkdf::extract(
|
||||
TLS_VERSION_1_3,
|
||||
@ -881,7 +886,7 @@ fn mitm_retry() {
|
||||
assert!(dgram.is_some()); // Client sending CLOSE_CONNECTIONs
|
||||
assert!(matches!(
|
||||
*client.state(),
|
||||
State::Closing{
|
||||
State::Closing {
|
||||
error: ConnectionError::Transport(Error::ProtocolViolation),
|
||||
..
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user