зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1926928 - update to neqo v0.10.0 r=necko-reviewers,sunil,valentin
Differential Revision: https://phabricator.services.mozilla.com/D226823
This commit is contained in:
Родитель
06d2615a13
Коммит
72924760ab
|
@ -90,9 +90,9 @@ git = "https://github.com/mozilla/mp4parse-rust"
|
||||||
rev = "a138e40ec1c603615873e524b5b22e11c0ec4820"
|
rev = "a138e40ec1c603615873e524b5b22e11c0ec4820"
|
||||||
replace-with = "vendored-sources"
|
replace-with = "vendored-sources"
|
||||||
|
|
||||||
[source."git+https://github.com/mozilla/neqo?tag=v0.9.2"]
|
[source."git+https://github.com/mozilla/neqo?tag=v0.10.0"]
|
||||||
git = "https://github.com/mozilla/neqo"
|
git = "https://github.com/mozilla/neqo"
|
||||||
tag = "v0.9.2"
|
tag = "v0.10.0"
|
||||||
replace-with = "vendored-sources"
|
replace-with = "vendored-sources"
|
||||||
|
|
||||||
[source."git+https://github.com/servo/unicode-bidi?rev=ca612daf1c08c53abe07327cb3e6ef6e0a760f0c"]
|
[source."git+https://github.com/servo/unicode-bidi?rev=ca612daf1c08c53abe07327cb3e6ef6e0a760f0c"]
|
||||||
|
|
|
@ -4281,8 +4281,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neqo-bin"
|
name = "neqo-bin"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
|
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"clap-verbosity-flag",
|
"clap-verbosity-flag",
|
||||||
|
@ -4303,8 +4303,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neqo-common"
|
name = "neqo-common"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
|
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enum-map",
|
"enum-map",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
@ -4315,8 +4315,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neqo-crypto"
|
name = "neqo-crypto"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
|
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen 0.69.4",
|
"bindgen 0.69.4",
|
||||||
"log",
|
"log",
|
||||||
|
@ -4330,8 +4330,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neqo-http3"
|
name = "neqo-http3"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
|
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enumset",
|
"enumset",
|
||||||
"log",
|
"log",
|
||||||
|
@ -4346,8 +4346,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neqo-qpack"
|
name = "neqo-qpack"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
|
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"neqo-common",
|
"neqo-common",
|
||||||
|
@ -4358,8 +4358,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neqo-transport"
|
name = "neqo-transport"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
|
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enum-map",
|
"enum-map",
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
|
@ -4373,8 +4373,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neqo-udp"
|
name = "neqo-udp"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
|
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"neqo-common",
|
"neqo-common",
|
||||||
|
|
|
@ -1166,7 +1166,6 @@ networking:
|
||||||
- DecodingFrame
|
- DecodingFrame
|
||||||
- DecryptError
|
- DecryptError
|
||||||
- DisabledVersion
|
- DisabledVersion
|
||||||
- HandshakeFailed
|
|
||||||
- IdleTimeout
|
- IdleTimeout
|
||||||
- IntegerOverflow
|
- IntegerOverflow
|
||||||
- InvalidInput
|
- InvalidInput
|
||||||
|
|
|
@ -10,11 +10,11 @@ name = "neqo_glue"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
firefox-on-glean = { path = "../../../toolkit/components/glean/api" }
|
firefox-on-glean = { path = "../../../toolkit/components/glean/api" }
|
||||||
neqo-udp = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-udp = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-http3 = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-http3 = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-transport = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-transport = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-common = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-common = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-qpack = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-qpack = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
nserror = { path = "../../../xpcom/rust/nserror" }
|
nserror = { path = "../../../xpcom/rust/nserror" }
|
||||||
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
nsstring = { path = "../../../xpcom/rust/nsstring" }
|
||||||
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
xpcom = { path = "../../../xpcom/rust/xpcom" }
|
||||||
|
@ -29,7 +29,7 @@ uuid = { version = "1.0", features = ["v4"] }
|
||||||
winapi = {version = "0.3", features = ["ws2def"] }
|
winapi = {version = "0.3", features = ["ws2def"] }
|
||||||
|
|
||||||
[dependencies.neqo-crypto]
|
[dependencies.neqo-crypto]
|
||||||
tag = "v0.9.2"
|
tag = "v0.10.0"
|
||||||
git = "https://github.com/mozilla/neqo"
|
git = "https://github.com/mozilla/neqo"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["gecko"]
|
features = ["gecko"]
|
||||||
|
|
|
@ -41,6 +41,10 @@ use uuid::Uuid;
|
||||||
use winapi::shared::ws2def::{AF_INET, AF_INET6};
|
use winapi::shared::ws2def::{AF_INET, AF_INET6};
|
||||||
use xpcom::{interfaces::nsISocketProvider, AtomicRefcnt, RefCounted, RefPtr};
|
use xpcom::{interfaces::nsISocketProvider, AtomicRefcnt, RefCounted, RefPtr};
|
||||||
|
|
||||||
|
std::thread_local! {
|
||||||
|
static RECV_BUF: RefCell<Vec<u8>> = RefCell::new(vec![0; neqo_udp::RECV_BUF_SIZE]);
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct NeqoHttp3Conn {
|
pub struct NeqoHttp3Conn {
|
||||||
conn: Http3Client,
|
conn: Http3Client,
|
||||||
|
@ -517,10 +521,10 @@ pub unsafe extern "C" fn neqo_http3conn_process_input_use_nspr_for_io(
|
||||||
remote,
|
remote,
|
||||||
conn.local_addr,
|
conn.local_addr,
|
||||||
IpTos::default(),
|
IpTos::default(),
|
||||||
(*packet).to_vec(),
|
(*packet).as_slice(),
|
||||||
);
|
);
|
||||||
conn.conn
|
conn.conn
|
||||||
.process_input(&d, get_current_or_last_output_time(&conn.last_output_time));
|
.process_input(d, get_current_or_last_output_time(&conn.last_output_time));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,52 +542,61 @@ pub unsafe extern "C" fn neqo_http3conn_process_input(
|
||||||
) -> ProcessInputResult {
|
) -> ProcessInputResult {
|
||||||
let mut bytes_read = 0;
|
let mut bytes_read = 0;
|
||||||
|
|
||||||
loop {
|
RECV_BUF.with_borrow_mut(|recv_buf| {
|
||||||
let mut dgrams = match conn
|
loop {
|
||||||
.socket
|
let dgrams = match conn
|
||||||
.as_mut()
|
.socket
|
||||||
.expect("non NSPR IO")
|
.as_mut()
|
||||||
.recv(&conn.local_addr)
|
.expect("non NSPR IO")
|
||||||
{
|
.recv(conn.local_addr, recv_buf)
|
||||||
Ok(dgrams) => dgrams,
|
{
|
||||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
Ok(dgrams) => dgrams,
|
||||||
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
qwarn!("failed to receive datagrams: {}", e);
|
||||||
|
return ProcessInputResult {
|
||||||
|
result: NS_ERROR_FAILURE,
|
||||||
|
bytes_read: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if dgrams.len() == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
qwarn!("failed to receive datagrams: {}", e);
|
// Attach metric instrumentation to `dgrams` iterator.
|
||||||
return ProcessInputResult {
|
let mut sum = 0;
|
||||||
result: NS_ERROR_FAILURE,
|
conn.datagram_segments_received
|
||||||
bytes_read: 0,
|
.accumulate(dgrams.len() as u64);
|
||||||
};
|
let datagram_segment_size_received = &mut conn.datagram_segment_size_received;
|
||||||
}
|
let dgrams = dgrams.map(|d| {
|
||||||
|
datagram_segment_size_received.accumulate(d.len() as u64);
|
||||||
|
sum += d.len();
|
||||||
|
d
|
||||||
|
});
|
||||||
|
|
||||||
|
// Override `dgrams` ECN marks according to prefs.
|
||||||
|
let ecn_enabled = static_prefs::pref!("network.http.http3.ecn");
|
||||||
|
let dgrams = dgrams.map(|mut d| {
|
||||||
|
if !ecn_enabled {
|
||||||
|
d.set_tos(Default::default());
|
||||||
|
}
|
||||||
|
d
|
||||||
|
});
|
||||||
|
|
||||||
|
conn.conn.process_multiple_input(dgrams, Instant::now());
|
||||||
|
|
||||||
|
conn.datagram_size_received.accumulate(sum as u64);
|
||||||
|
bytes_read += sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProcessInputResult {
|
||||||
|
result: NS_OK,
|
||||||
|
bytes_read: bytes_read.try_into().unwrap_or(u32::MAX),
|
||||||
};
|
};
|
||||||
if dgrams.is_empty() {
|
})
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sum = 0;
|
|
||||||
let ecn_enabled = static_prefs::pref!("network.http.http3.ecn");
|
|
||||||
for dgram in &mut dgrams {
|
|
||||||
if !ecn_enabled {
|
|
||||||
dgram.set_tos(Default::default());
|
|
||||||
}
|
|
||||||
conn.datagram_segment_size_received
|
|
||||||
.accumulate(dgram.len() as u64);
|
|
||||||
sum += dgram.len();
|
|
||||||
}
|
|
||||||
conn.datagram_size_received.accumulate(sum as u64);
|
|
||||||
conn.datagram_segments_received
|
|
||||||
.accumulate(dgrams.len() as u64);
|
|
||||||
bytes_read += sum;
|
|
||||||
|
|
||||||
conn.conn
|
|
||||||
.process_multiple_input(dgrams.iter(), Instant::now());
|
|
||||||
}
|
|
||||||
|
|
||||||
return ProcessInputResult {
|
|
||||||
result: NS_OK,
|
|
||||||
bytes_read: bytes_read.try_into().unwrap_or(u32::MAX),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -1001,7 +1014,6 @@ impl From<TransportError> for CloseError {
|
||||||
TransportError::ConnectionState => CloseError::TransportInternalErrorOther(3),
|
TransportError::ConnectionState => CloseError::TransportInternalErrorOther(3),
|
||||||
TransportError::DecodingFrame => CloseError::TransportInternalErrorOther(4),
|
TransportError::DecodingFrame => CloseError::TransportInternalErrorOther(4),
|
||||||
TransportError::DecryptError => CloseError::TransportInternalErrorOther(5),
|
TransportError::DecryptError => CloseError::TransportInternalErrorOther(5),
|
||||||
TransportError::HandshakeFailed => CloseError::TransportInternalErrorOther(6),
|
|
||||||
TransportError::IntegerOverflow => CloseError::TransportInternalErrorOther(7),
|
TransportError::IntegerOverflow => CloseError::TransportInternalErrorOther(7),
|
||||||
TransportError::InvalidInput => CloseError::TransportInternalErrorOther(8),
|
TransportError::InvalidInput => CloseError::TransportInternalErrorOther(8),
|
||||||
TransportError::InvalidMigration => CloseError::TransportInternalErrorOther(9),
|
TransportError::InvalidMigration => CloseError::TransportInternalErrorOther(9),
|
||||||
|
@ -1057,7 +1069,6 @@ fn transport_error_to_glean_label(error: &TransportError) -> &'static str {
|
||||||
TransportError::DecodingFrame => "DecodingFrame",
|
TransportError::DecodingFrame => "DecodingFrame",
|
||||||
TransportError::DecryptError => "DecryptError",
|
TransportError::DecryptError => "DecryptError",
|
||||||
TransportError::DisabledVersion => "DisabledVersion",
|
TransportError::DisabledVersion => "DisabledVersion",
|
||||||
TransportError::HandshakeFailed => "HandshakeFailed",
|
|
||||||
TransportError::IdleTimeout => "IdleTimeout",
|
TransportError::IdleTimeout => "IdleTimeout",
|
||||||
TransportError::IntegerOverflow => "IntegerOverflow",
|
TransportError::IntegerOverflow => "IntegerOverflow",
|
||||||
TransportError::InvalidInput => "InvalidInput",
|
TransportError::InvalidInput => "InvalidInput",
|
||||||
|
|
|
@ -6,11 +6,11 @@ edition = "2018"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
neqo-bin = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-bin = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-transport = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-transport = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-common = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-common = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-http3 = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-http3 = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
neqo-qpack = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
|
neqo-qpack = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
|
||||||
log = "0.4.0"
|
log = "0.4.0"
|
||||||
base64 = "0.21"
|
base64 = "0.21"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
|
@ -20,7 +20,7 @@ tokio = { version = "1", features = ["rt-multi-thread"] }
|
||||||
mozilla-central-workspace-hack = { version = "0.1", features = ["http3server"], optional = true }
|
mozilla-central-workspace-hack = { version = "0.1", features = ["http3server"], optional = true }
|
||||||
|
|
||||||
[dependencies.neqo-crypto]
|
[dependencies.neqo-crypto]
|
||||||
tag = "v0.9.2"
|
tag = "v0.10.0"
|
||||||
git = "https://github.com/mozilla/neqo"
|
git = "https://github.com/mozilla/neqo"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["gecko"]
|
features = ["gecko"]
|
||||||
|
|
|
@ -179,7 +179,7 @@ impl Http3TestServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpServer for Http3TestServer {
|
impl HttpServer for Http3TestServer {
|
||||||
fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output {
|
fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
|
||||||
let output = self.server.process(dgram, now);
|
let output = self.server.process(dgram, now);
|
||||||
|
|
||||||
let output = if self.sessions_to_close.is_empty() {
|
let output = if self.sessions_to_close.is_empty() {
|
||||||
|
@ -637,7 +637,7 @@ impl ::std::fmt::Display for Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpServer for Server {
|
impl HttpServer for Server {
|
||||||
fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output {
|
fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
|
||||||
self.0.process(dgram, now)
|
self.0.process(dgram, now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,7 +882,7 @@ impl Http3ProxyServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpServer for Http3ProxyServer {
|
impl HttpServer for Http3ProxyServer {
|
||||||
fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output {
|
fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
|
||||||
let output = self.server.process(dgram, now);
|
let output = self.server.process(dgram, now);
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
|
@ -1015,7 +1015,7 @@ impl ::std::fmt::Display for NonRespondingServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpServer for NonRespondingServer {
|
impl HttpServer for NonRespondingServer {
|
||||||
fn process(&mut self, _dgram: Option<&Datagram>, _now: Instant) -> Output {
|
fn process(&mut self, _dgram: Option<Datagram>, _now: Instant) -> Output {
|
||||||
Output::None
|
Output::None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1227,7 +1227,7 @@ extern "C" fn __tsan_default_suppressions() -> *const std::os::raw::c_char {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Work around until we can use raw-dylibs.
|
// Work around until we can use raw-dylibs.
|
||||||
#[cfg_attr(target_os = "windows", link(name="runtimeobject"))]
|
#[cfg_attr(target_os = "windows", link(name = "runtimeobject"))]
|
||||||
extern "C" {}
|
extern "C" {}
|
||||||
#[cfg_attr(target_os = "windows", link(name="propsys"))]
|
#[cfg_attr(target_os = "windows", link(name = "propsys"))]
|
||||||
extern "C" {}
|
extern "C" {}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"937660e9dcd5400a6b252abc9c7b4c916d475719396d7fd288d260ce39f0e373","benches/main.rs":"aa39bf1f08863e3bace034a991c60a4723f1a7d30b3fc1d1f8c4d7f73bc748c3","src/bin/client.rs":"db77efd75dc0745b6dd983ab8fa3bc8f5f9111967f0d90d23cb19140a940246d","src/bin/server.rs":"2f7ab3c7a98117bd162e6fd07abef1d21791d1bb240db3aae61afa6ff72df83a","src/client/http09.rs":"9d728f068954df99adec622d771e8e734155b3a7aff80d823273a21cab94d6dd","src/client/http3.rs":"77cc2cc6a831a2b3e5719a69798e4f0cafea6f59006caf5990282168c4a30c82","src/client/mod.rs":"931d1b51d71694a56d22af1a6ecb03941ae1283fa04e65a2b83ef08351e71b9d","src/lib.rs":"d2ebba2cb72d1b637baa856c9a5715a31c1f35c3476225ce6ffc9cbe29bc28e9","src/server/http09.rs":"9ffb0f62c6202a2914086b7e1d8ba77e016c1b4f4a9895b268a6312a04ad70e3","src/server/http3.rs":"0bdab101bffda37257360f9a968d32ff8884b40f292878f3dc27b055e0b5864b","src/server/mod.rs":"e1edfc71853f8b5be96287391919dc84d24191e865f7b9b4a38eebfda07ce453","src/udp.rs":"9042b73c20223e1c7b45d862dea9417fc367032db09dd05d48ca06ac33638435"},"package":null}
|
{"files":{"Cargo.toml":"3e509d82762d5e23010e0dc484522c84c08b0c5d596bd0ab7110e2c16ec5afaf","benches/main.rs":"ccfc5f44b2228603ef82a3c22fba57b8beb40a81254bd771b2b26556540d094e","src/bin/client.rs":"db77efd75dc0745b6dd983ab8fa3bc8f5f9111967f0d90d23cb19140a940246d","src/bin/server.rs":"2f7ab3c7a98117bd162e6fd07abef1d21791d1bb240db3aae61afa6ff72df83a","src/client/http09.rs":"c0f30400a4e2822c54051efe6f8a1f096ef21ecfe602737cd71dd5b86b662f4b","src/client/http3.rs":"85a0fc3b1d50f6a108b3d74ee115270b06f2412443134627ade752b9691b5ae5","src/client/mod.rs":"b7f3ca90b886283e999b21288a57db5ed9456062ff12c9bf2570025659c9efdd","src/lib.rs":"d2ebba2cb72d1b637baa856c9a5715a31c1f35c3476225ce6ffc9cbe29bc28e9","src/server/http09.rs":"3d168f28c29cbc7c33aab713afa180dba0f627e55edc60ee7e02ec29e3847e68","src/server/http3.rs":"a15266daec0a3f1ef279f9b1101e49a0537ce0d9f1e34adc2d69fb735634b464","src/server/mod.rs":"d5f7e405edb7cfbe0b898ece754dd62effe71e7db60356411c4ee35e9443beb2","src/udp.rs":"4aadb956e50f961241b2850e6f3bdf715ccbac943e3ab585f4b46e755d03d2de"},"package":null}
|
|
@ -13,7 +13,7 @@
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
name = "neqo-bin"
|
name = "neqo-bin"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
||||||
build = false
|
build = false
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::{path::PathBuf, str::FromStr};
|
use std::{env, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
|
use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
|
||||||
use neqo_bin::{client, server};
|
use neqo_bin::{client, server};
|
||||||
|
@ -20,18 +20,18 @@ fn transfer(c: &mut Criterion) {
|
||||||
neqo_crypto::init_db(PathBuf::from_str("../test-fixture/db").unwrap()).unwrap();
|
neqo_crypto::init_db(PathBuf::from_str("../test-fixture/db").unwrap()).unwrap();
|
||||||
|
|
||||||
let done_sender = spawn_server();
|
let done_sender = spawn_server();
|
||||||
|
let mtu = env::var("MTU").map_or_else(|_| String::new(), |mtu| format!("/mtu-{mtu}"));
|
||||||
for Benchmark { name, requests } in [
|
for Benchmark { name, requests } in [
|
||||||
Benchmark {
|
Benchmark {
|
||||||
name: "1-conn/1-100mb-resp (aka. Download)".to_string(),
|
name: format!("1-conn/1-100mb-resp{mtu} (aka. Download)"),
|
||||||
requests: vec![100 * 1024 * 1024],
|
requests: vec![100 * 1024 * 1024],
|
||||||
},
|
},
|
||||||
Benchmark {
|
Benchmark {
|
||||||
name: "1-conn/10_000-parallel-1b-resp (aka. RPS)".to_string(),
|
name: format!("1-conn/10_000-parallel-1b-resp{mtu} (aka. RPS)"),
|
||||||
requests: vec![1; 10_000],
|
requests: vec![1; 10_000],
|
||||||
},
|
},
|
||||||
Benchmark {
|
Benchmark {
|
||||||
name: "1-conn/1-1b-resp (aka. HPS)".to_string(),
|
name: format!("1-conn/1-1b-resp{mtu} (aka. HPS)"),
|
||||||
requests: vec![1; 1],
|
requests: vec![1; 1],
|
||||||
},
|
},
|
||||||
] {
|
] {
|
||||||
|
|
|
@ -26,7 +26,7 @@ use neqo_transport::{
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use super::{get_output_file, qlog_new, Args, CloseState, Res};
|
use super::{get_output_file, qlog_new, Args, CloseState, Res};
|
||||||
use crate::STREAM_IO_BUFFER_SIZE;
|
use crate::{client::local_addr_for, STREAM_IO_BUFFER_SIZE};
|
||||||
|
|
||||||
pub struct Handler<'a> {
|
pub struct Handler<'a> {
|
||||||
streams: HashMap<StreamId, Option<BufWriter<File>>>,
|
streams: HashMap<StreamId, Option<BufWriter<File>>>,
|
||||||
|
@ -37,6 +37,7 @@ pub struct Handler<'a> {
|
||||||
token: Option<ResumptionToken>,
|
token: Option<ResumptionToken>,
|
||||||
needs_key_update: bool,
|
needs_key_update: bool,
|
||||||
read_buffer: Vec<u8>,
|
read_buffer: Vec<u8>,
|
||||||
|
migration: Option<&'a (u16, SocketAddr)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler<'_> {
|
impl Handler<'_> {
|
||||||
|
@ -85,6 +86,26 @@ impl super::Handler for Handler<'_> {
|
||||||
self.download_urls(client);
|
self.download_urls(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ConnectionEvent::StateChange(State::Confirmed) => {
|
||||||
|
if let Some((local_port, migration_addr)) = self.migration.take() {
|
||||||
|
let local_addr = local_addr_for(migration_addr, *local_port);
|
||||||
|
qdebug!("Migrating path to {:?} -> {:?}", local_addr, migration_addr);
|
||||||
|
client
|
||||||
|
.migrate(
|
||||||
|
Some(local_addr),
|
||||||
|
Some(*migration_addr),
|
||||||
|
false,
|
||||||
|
Instant::now(),
|
||||||
|
)
|
||||||
|
.map(|()| {
|
||||||
|
qinfo!(
|
||||||
|
"Connection migrated to {:?} -> {:?}",
|
||||||
|
local_addr,
|
||||||
|
migration_addr
|
||||||
|
);
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
ConnectionEvent::StateChange(
|
ConnectionEvent::StateChange(
|
||||||
State::WaitInitial | State::Handshaking | State::Connected,
|
State::WaitInitial | State::Handshaking | State::Connected,
|
||||||
) => {
|
) => {
|
||||||
|
@ -181,10 +202,11 @@ impl super::Client for Connection {
|
||||||
self.process_output(now)
|
self.process_output(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
|
fn process_multiple_input<'a>(
|
||||||
where
|
&mut self,
|
||||||
I: IntoIterator<Item = &'a Datagram>,
|
dgrams: impl IntoIterator<Item = Datagram<&'a [u8]>>,
|
||||||
{
|
now: Instant,
|
||||||
|
) {
|
||||||
self.process_multiple_input(dgrams, now);
|
self.process_multiple_input(dgrams, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +233,11 @@ impl super::Client for Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> Handler<'b> {
|
impl<'b> Handler<'b> {
|
||||||
pub fn new(url_queue: VecDeque<Url>, args: &'b Args) -> Self {
|
pub fn new(
|
||||||
|
url_queue: VecDeque<Url>,
|
||||||
|
args: &'b Args,
|
||||||
|
migration: Option<&'b (u16, SocketAddr)>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
streams: HashMap::new(),
|
streams: HashMap::new(),
|
||||||
url_queue,
|
url_queue,
|
||||||
|
@ -221,6 +247,7 @@ impl<'b> Handler<'b> {
|
||||||
token: None,
|
token: None,
|
||||||
needs_key_update: args.key_update,
|
needs_key_update: args.key_update,
|
||||||
read_buffer: vec![0; STREAM_IO_BUFFER_SIZE],
|
read_buffer: vec![0; STREAM_IO_BUFFER_SIZE],
|
||||||
|
migration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,10 +132,11 @@ impl super::Client for Http3Client {
|
||||||
self.process_output(now)
|
self.process_output(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
|
fn process_multiple_input<'a>(
|
||||||
where
|
&mut self,
|
||||||
I: IntoIterator<Item = &'a Datagram>,
|
dgrams: impl IntoIterator<Item = Datagram<&'a [u8]>>,
|
||||||
{
|
now: Instant,
|
||||||
|
) {
|
||||||
self.process_multiple_input(dgrams, now);
|
self.process_multiple_input(dgrams, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ use neqo_crypto::{
|
||||||
use neqo_http3::Output;
|
use neqo_http3::Output;
|
||||||
use neqo_transport::{AppError, CloseReason, ConnectionId, Version};
|
use neqo_transport::{AppError, CloseReason, ConnectionId, Version};
|
||||||
use tokio::time::Sleep;
|
use tokio::time::Sleep;
|
||||||
use url::{Origin, Url};
|
use url::{Host, Origin, Url};
|
||||||
|
|
||||||
use crate::SharedArgs;
|
use crate::SharedArgs;
|
||||||
|
|
||||||
|
@ -231,8 +231,11 @@ impl Args {
|
||||||
|
|
||||||
// Only use v1 for most QNS tests.
|
// Only use v1 for most QNS tests.
|
||||||
self.shared.quic_parameters.quic_version = vec![Version::Version1];
|
self.shared.quic_parameters.quic_version = vec![Version::Version1];
|
||||||
|
// This is the default for all tests except http3.
|
||||||
|
self.shared.use_old_http = true;
|
||||||
match testcase.as_str() {
|
match testcase.as_str() {
|
||||||
"http3" => {
|
"http3" => {
|
||||||
|
self.shared.use_old_http = false;
|
||||||
if let Some(testcase) = &self.test {
|
if let Some(testcase) = &self.test {
|
||||||
if testcase.as_str() != "upload" {
|
if testcase.as_str() != "upload" {
|
||||||
qerror!("Unsupported test case: {testcase}");
|
qerror!("Unsupported test case: {testcase}");
|
||||||
|
@ -242,15 +245,18 @@ impl Args {
|
||||||
self.method = String::from("POST");
|
self.method = String::from("POST");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"handshake" | "transfer" | "retry" | "ecn" => {
|
"handshake"
|
||||||
self.shared.use_old_http = true;
|
| "transfer"
|
||||||
}
|
| "retry"
|
||||||
|
| "ecn"
|
||||||
|
| "rebind-port"
|
||||||
|
| "rebind-addr"
|
||||||
|
| "connectionmigration" => {}
|
||||||
"resumption" => {
|
"resumption" => {
|
||||||
if self.urls.len() < 2 {
|
if self.urls.len() < 2 {
|
||||||
qerror!("Warning: resumption test won't work without >1 URL");
|
qerror!("Warning: resumption test won't work without >1 URL");
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
self.shared.use_old_http = true;
|
|
||||||
self.resume = true;
|
self.resume = true;
|
||||||
}
|
}
|
||||||
"zerortt" => {
|
"zerortt" => {
|
||||||
|
@ -258,7 +264,6 @@ impl Args {
|
||||||
qerror!("Warning: zerortt test won't work without >1 URL");
|
qerror!("Warning: zerortt test won't work without >1 URL");
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
self.shared.use_old_http = true;
|
|
||||||
self.resume = true;
|
self.resume = true;
|
||||||
// PMTUD probes inflate what we sent in 1-RTT, causing QNS to fail the test.
|
// PMTUD probes inflate what we sent in 1-RTT, causing QNS to fail the test.
|
||||||
self.shared.quic_parameters.no_pmtud = true;
|
self.shared.quic_parameters.no_pmtud = true;
|
||||||
|
@ -267,22 +272,18 @@ impl Args {
|
||||||
self.shared.quic_parameters.no_pacing = true;
|
self.shared.quic_parameters.no_pacing = true;
|
||||||
}
|
}
|
||||||
"multiconnect" => {
|
"multiconnect" => {
|
||||||
self.shared.use_old_http = true;
|
|
||||||
self.download_in_series = true;
|
self.download_in_series = true;
|
||||||
}
|
}
|
||||||
"chacha20" => {
|
"chacha20" => {
|
||||||
self.shared.use_old_http = true;
|
|
||||||
self.shared.ciphers.clear();
|
self.shared.ciphers.clear();
|
||||||
self.shared
|
self.shared
|
||||||
.ciphers
|
.ciphers
|
||||||
.extend_from_slice(&[String::from("TLS_CHACHA20_POLY1305_SHA256")]);
|
.extend_from_slice(&[String::from("TLS_CHACHA20_POLY1305_SHA256")]);
|
||||||
}
|
}
|
||||||
"keyupdate" => {
|
"keyupdate" => {
|
||||||
self.shared.use_old_http = true;
|
|
||||||
self.key_update = true;
|
self.key_update = true;
|
||||||
}
|
}
|
||||||
"v2" => {
|
"v2" => {
|
||||||
self.shared.use_old_http = true;
|
|
||||||
// Use default version set for this test (which allows compatible vneg.)
|
// Use default version set for this test (which allows compatible vneg.)
|
||||||
self.shared.quic_parameters.quic_version.clear();
|
self.shared.quic_parameters.quic_version.clear();
|
||||||
}
|
}
|
||||||
|
@ -373,9 +374,11 @@ enum CloseState {
|
||||||
/// Network client, e.g. [`neqo_transport::Connection`] or [`neqo_http3::Http3Client`].
|
/// Network client, e.g. [`neqo_transport::Connection`] or [`neqo_http3::Http3Client`].
|
||||||
trait Client {
|
trait Client {
|
||||||
fn process_output(&mut self, now: Instant) -> Output;
|
fn process_output(&mut self, now: Instant) -> Output;
|
||||||
fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
|
fn process_multiple_input<'a>(
|
||||||
where
|
&mut self,
|
||||||
I: IntoIterator<Item = &'a Datagram>;
|
dgrams: impl IntoIterator<Item = Datagram<&'a [u8]>>,
|
||||||
|
now: Instant,
|
||||||
|
);
|
||||||
fn has_events(&self) -> bool;
|
fn has_events(&self) -> bool;
|
||||||
fn close<S>(&mut self, now: Instant, app_error: AppError, msg: S)
|
fn close<S>(&mut self, now: Instant, app_error: AppError, msg: S)
|
||||||
where
|
where
|
||||||
|
@ -391,9 +394,28 @@ struct Runner<'a, H: Handler> {
|
||||||
handler: H,
|
handler: H,
|
||||||
timeout: Option<Pin<Box<Sleep>>>,
|
timeout: Option<Pin<Box<Sleep>>>,
|
||||||
args: &'a Args,
|
args: &'a Args,
|
||||||
|
recv_buf: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H: Handler> Runner<'a, H> {
|
impl<'a, H: Handler> Runner<'a, H> {
|
||||||
|
fn new(
|
||||||
|
local_addr: SocketAddr,
|
||||||
|
socket: &'a mut crate::udp::Socket,
|
||||||
|
client: H::Client,
|
||||||
|
handler: H,
|
||||||
|
args: &'a Args,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
local_addr,
|
||||||
|
socket,
|
||||||
|
client,
|
||||||
|
handler,
|
||||||
|
args,
|
||||||
|
timeout: None,
|
||||||
|
recv_buf: vec![0; neqo_udp::RECV_BUF_SIZE],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn run(mut self) -> Res<Option<ResumptionToken>> {
|
async fn run(mut self) -> Res<Option<ResumptionToken>> {
|
||||||
loop {
|
loop {
|
||||||
let handler_done = self.handler.handle(&mut self.client)?;
|
let handler_done = self.handler.handle(&mut self.client)?;
|
||||||
|
@ -456,12 +478,13 @@ impl<'a, H: Handler> Runner<'a, H> {
|
||||||
|
|
||||||
async fn process_multiple_input(&mut self) -> Res<()> {
|
async fn process_multiple_input(&mut self) -> Res<()> {
|
||||||
loop {
|
loop {
|
||||||
let dgrams = self.socket.recv(&self.local_addr)?;
|
let Some(dgrams) = self.socket.recv(self.local_addr, &mut self.recv_buf)? else {
|
||||||
if dgrams.is_empty() {
|
break;
|
||||||
|
};
|
||||||
|
if dgrams.len() == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self.client
|
self.client.process_multiple_input(dgrams, Instant::now());
|
||||||
.process_multiple_input(dgrams.iter(), Instant::now());
|
|
||||||
self.process_output().await?;
|
self.process_output().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +515,29 @@ fn qlog_new(args: &Args, hostname: &str, cid: &ConnectionId) -> Res<NeqoQlog> {
|
||||||
.map_err(Error::QlogError)
|
.map_err(Error::QlogError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn local_addr_for(remote_addr: &SocketAddr, local_port: u16) -> SocketAddr {
|
||||||
|
match remote_addr {
|
||||||
|
SocketAddr::V4(..) => SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), local_port),
|
||||||
|
SocketAddr::V6(..) => SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), local_port),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn urls_by_origin(urls: &[Url]) -> impl Iterator<Item = ((Host, u16), VecDeque<Url>)> {
|
||||||
|
urls.iter()
|
||||||
|
.fold(HashMap::<Origin, VecDeque<Url>>::new(), |mut urls, url| {
|
||||||
|
urls.entry(url.origin()).or_default().push_back(url.clone());
|
||||||
|
urls
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(origin, urls)| match origin {
|
||||||
|
Origin::Tuple(_scheme, h, p) => Some(((h, p), urls)),
|
||||||
|
Origin::Opaque(x) => {
|
||||||
|
qwarn!("Opaque origin {x:?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn client(mut args: Args) -> Res<()> {
|
pub async fn client(mut args: Args) -> Res<()> {
|
||||||
neqo_common::log::init(
|
neqo_common::log::init(
|
||||||
args.shared
|
args.shared
|
||||||
|
@ -505,46 +551,24 @@ pub async fn client(mut args: Args) -> Res<()> {
|
||||||
|
|
||||||
init()?;
|
init()?;
|
||||||
|
|
||||||
let urls_by_origin = args
|
for ((host, port), mut urls) in urls_by_origin(&args.urls) {
|
||||||
.urls
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.fold(HashMap::<Origin, VecDeque<Url>>::new(), |mut urls, url| {
|
|
||||||
urls.entry(url.origin()).or_default().push_back(url);
|
|
||||||
urls
|
|
||||||
})
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(origin, urls)| match origin {
|
|
||||||
Origin::Tuple(_scheme, h, p) => Some(((h, p), urls)),
|
|
||||||
Origin::Opaque(x) => {
|
|
||||||
qwarn!("Opaque origin {x:?}");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for ((host, port), mut urls) in urls_by_origin {
|
|
||||||
if args.resume && urls.len() < 2 {
|
if args.resume && urls.len() < 2 {
|
||||||
qerror!("Resumption to {host} cannot work without at least 2 URLs.");
|
qerror!("Resumption to {host} cannot work without at least 2 URLs.");
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
let remote_addr = format!("{host}:{port}").to_socket_addrs()?.find(|addr| {
|
let mut remote_addrs = format!("{host}:{port}").to_socket_addrs()?.filter(|addr| {
|
||||||
!matches!(
|
!matches!(
|
||||||
(addr, args.ipv4_only, args.ipv6_only),
|
(addr, args.ipv4_only, args.ipv6_only),
|
||||||
(SocketAddr::V4(..), false, true) | (SocketAddr::V6(..), true, false)
|
(SocketAddr::V4(..), false, true) | (SocketAddr::V6(..), true, false)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
let remote_addr = remote_addrs.next();
|
||||||
let Some(remote_addr) = remote_addr else {
|
let Some(remote_addr) = remote_addr else {
|
||||||
qerror!("No compatible address found for: {host}");
|
qerror!("No compatible address found for: {host}");
|
||||||
exit(1);
|
exit(1);
|
||||||
};
|
};
|
||||||
|
let mut socket = crate::udp::Socket::bind(local_addr_for(&remote_addr, 0))?;
|
||||||
let local_addr = match remote_addr {
|
|
||||||
SocketAddr::V4(..) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from([0; 4])), 0),
|
|
||||||
SocketAddr::V6(..) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from([0; 16])), 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut socket = crate::udp::Socket::bind(local_addr)?;
|
|
||||||
let real_local = socket.local_addr().unwrap();
|
let real_local = socket.local_addr().unwrap();
|
||||||
qinfo!(
|
qinfo!(
|
||||||
"{} Client connecting: {:?} -> {:?}",
|
"{} Client connecting: {:?} -> {:?}",
|
||||||
|
@ -553,6 +577,18 @@ pub async fn client(mut args: Args) -> Res<()> {
|
||||||
remote_addr,
|
remote_addr,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let migration = if args.shared.qns_test.as_deref() == Some("connectionmigration") {
|
||||||
|
#[allow(clippy::option_if_let_else)]
|
||||||
|
if let Some(addr) = remote_addrs.next() {
|
||||||
|
Some((real_local.port(), addr))
|
||||||
|
} else {
|
||||||
|
qerror!("Cannot migrate from {host} when there is no address that follows");
|
||||||
|
exit(127);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let hostname = format!("{host}");
|
let hostname = format!("{host}");
|
||||||
let mut token: Option<ResumptionToken> = None;
|
let mut token: Option<ResumptionToken> = None;
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
|
@ -570,34 +606,20 @@ pub async fn client(mut args: Args) -> Res<()> {
|
||||||
http09::create_client(&args, real_local, remote_addr, &hostname, token)
|
http09::create_client(&args, real_local, remote_addr, &hostname, token)
|
||||||
.expect("failed to create client");
|
.expect("failed to create client");
|
||||||
|
|
||||||
let handler = http09::Handler::new(to_request, &args);
|
let handler = http09::Handler::new(to_request, &args, migration.as_ref());
|
||||||
|
|
||||||
Runner {
|
Runner::new(real_local, &mut socket, client, handler, &args)
|
||||||
args: &args,
|
.run()
|
||||||
client,
|
.await?
|
||||||
handler,
|
|
||||||
local_addr: real_local,
|
|
||||||
socket: &mut socket,
|
|
||||||
timeout: None,
|
|
||||||
}
|
|
||||||
.run()
|
|
||||||
.await?
|
|
||||||
} else {
|
} else {
|
||||||
let client = http3::create_client(&args, real_local, remote_addr, &hostname, token)
|
let client = http3::create_client(&args, real_local, remote_addr, &hostname, token)
|
||||||
.expect("failed to create client");
|
.expect("failed to create client");
|
||||||
|
|
||||||
let handler = http3::Handler::new(to_request, &args);
|
let handler = http3::Handler::new(to_request, &args);
|
||||||
|
|
||||||
Runner {
|
Runner::new(real_local, &mut socket, client, handler, &args)
|
||||||
args: &args,
|
.run()
|
||||||
client,
|
.await?
|
||||||
handler,
|
|
||||||
local_addr: real_local,
|
|
||||||
socket: &mut socket,
|
|
||||||
timeout: None,
|
|
||||||
}
|
|
||||||
.run()
|
|
||||||
.await?
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,7 @@ impl HttpServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::HttpServer for HttpServer {
|
impl super::HttpServer for HttpServer {
|
||||||
fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output {
|
fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output {
|
||||||
self.server.process(dgram, now)
|
self.server.process(dgram, now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl Display for HttpServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::HttpServer for HttpServer {
|
impl super::HttpServer for HttpServer {
|
||||||
fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> neqo_http3::Output {
|
fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> neqo_http3::Output {
|
||||||
self.server.process(dgram, now)
|
self.server.process(dgram, now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ fn qns_read_response(filename: &str) -> Result<Vec<u8>, io::Error> {
|
||||||
|
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
pub trait HttpServer: Display {
|
pub trait HttpServer: Display {
|
||||||
fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output;
|
fn process(&mut self, dgram: Option<Datagram>, now: Instant) -> Output;
|
||||||
fn process_events(&mut self, now: Instant);
|
fn process_events(&mut self, now: Instant);
|
||||||
fn has_events(&self) -> bool;
|
fn has_events(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
@ -205,6 +205,7 @@ pub struct ServerRunner {
|
||||||
server: Box<dyn HttpServer>,
|
server: Box<dyn HttpServer>,
|
||||||
timeout: Option<Pin<Box<Sleep>>>,
|
timeout: Option<Pin<Box<Sleep>>>,
|
||||||
sockets: Vec<(SocketAddr, crate::udp::Socket)>,
|
sockets: Vec<(SocketAddr, crate::udp::Socket)>,
|
||||||
|
recv_buf: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerRunner {
|
impl ServerRunner {
|
||||||
|
@ -219,6 +220,7 @@ impl ServerRunner {
|
||||||
server,
|
server,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
sockets,
|
sockets,
|
||||||
|
recv_buf: vec![0; neqo_udp::RECV_BUF_SIZE],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +238,7 @@ impl ServerRunner {
|
||||||
.unwrap_or(first_socket)
|
.unwrap_or(first_socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process(&mut self, mut dgram: Option<&Datagram>) -> Result<(), io::Error> {
|
async fn process(&mut self, mut dgram: Option<Datagram>) -> Result<(), io::Error> {
|
||||||
loop {
|
loop {
|
||||||
match self.server.process(dgram.take(), (self.now)()) {
|
match self.server.process(dgram.take(), (self.now)()) {
|
||||||
Output::Datagram(dgram) => {
|
Output::Datagram(dgram) => {
|
||||||
|
@ -289,12 +291,15 @@ impl ServerRunner {
|
||||||
match self.ready().await? {
|
match self.ready().await? {
|
||||||
Ready::Socket(inx) => loop {
|
Ready::Socket(inx) => loop {
|
||||||
let (host, socket) = self.sockets.get_mut(inx).unwrap();
|
let (host, socket) = self.sockets.get_mut(inx).unwrap();
|
||||||
let dgrams = socket.recv(host)?;
|
let Some(dgrams) = socket.recv(*host, &mut self.recv_buf)? else {
|
||||||
if dgrams.is_empty() {
|
break;
|
||||||
|
};
|
||||||
|
if dgrams.len() == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
let dgrams: Vec<Datagram> = dgrams.map(|d| d.to_owned()).collect();
|
||||||
for dgram in dgrams {
|
for dgram in dgrams {
|
||||||
self.process(Some(&dgram)).await?;
|
self.process(Some(dgram)).await?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Ready::Timeout => {
|
Ready::Timeout => {
|
||||||
|
@ -336,20 +341,27 @@ pub async fn server(mut args: Args) -> Res<()> {
|
||||||
qwarn!("Both -V and --qns-test were set. Ignoring testcase specific versions.");
|
qwarn!("Both -V and --qns-test were set. Ignoring testcase specific versions.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the default for all tests except http3.
|
||||||
|
args.shared.use_old_http = true;
|
||||||
// TODO: More options to deduplicate with client?
|
// TODO: More options to deduplicate with client?
|
||||||
match testcase.as_str() {
|
match testcase.as_str() {
|
||||||
"http3" => (),
|
"http3" => args.shared.use_old_http = false,
|
||||||
"zerortt" => {
|
"zerortt" => {
|
||||||
args.shared.use_old_http = true;
|
|
||||||
args.shared.alpn = String::from(HQ_INTEROP);
|
args.shared.alpn = String::from(HQ_INTEROP);
|
||||||
args.shared.quic_parameters.max_streams_bidi = 100;
|
args.shared.quic_parameters.max_streams_bidi = 100;
|
||||||
}
|
}
|
||||||
"handshake" | "transfer" | "resumption" | "multiconnect" | "v2" | "ecn" => {
|
"handshake"
|
||||||
args.shared.use_old_http = true;
|
| "transfer"
|
||||||
|
| "resumption"
|
||||||
|
| "multiconnect"
|
||||||
|
| "v2"
|
||||||
|
| "ecn"
|
||||||
|
| "rebind-port"
|
||||||
|
| "rebind-addr"
|
||||||
|
| "connectionmigration" => {
|
||||||
args.shared.alpn = String::from(HQ_INTEROP);
|
args.shared.alpn = String::from(HQ_INTEROP);
|
||||||
}
|
}
|
||||||
"chacha20" => {
|
"chacha20" => {
|
||||||
args.shared.use_old_http = true;
|
|
||||||
args.shared.alpn = String::from(HQ_INTEROP);
|
args.shared.alpn = String::from(HQ_INTEROP);
|
||||||
args.shared.ciphers.clear();
|
args.shared.ciphers.clear();
|
||||||
args.shared
|
args.shared
|
||||||
|
@ -357,7 +369,6 @@ pub async fn server(mut args: Args) -> Res<()> {
|
||||||
.extend_from_slice(&[String::from("TLS_CHACHA20_POLY1305_SHA256")]);
|
.extend_from_slice(&[String::from("TLS_CHACHA20_POLY1305_SHA256")]);
|
||||||
}
|
}
|
||||||
"retry" => {
|
"retry" => {
|
||||||
args.shared.use_old_http = true;
|
|
||||||
args.shared.alpn = String::from(HQ_INTEROP);
|
args.shared.alpn = String::from(HQ_INTEROP);
|
||||||
args.retry = true;
|
args.retry = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use std::{io, net::SocketAddr};
|
use std::{io, net::SocketAddr};
|
||||||
|
|
||||||
use neqo_common::Datagram;
|
use neqo_common::Datagram;
|
||||||
|
use neqo_udp::DatagramIter;
|
||||||
|
|
||||||
/// Ideally this would live in [`neqo-udp`]. [`neqo-udp`] is used in Firefox.
|
/// Ideally this would live in [`neqo-udp`]. [`neqo-udp`] is used in Firefox.
|
||||||
///
|
///
|
||||||
|
@ -55,14 +56,19 @@ impl Socket {
|
||||||
|
|
||||||
/// Receive a batch of [`Datagram`]s on the given [`Socket`], each set with
|
/// Receive a batch of [`Datagram`]s on the given [`Socket`], each set with
|
||||||
/// the provided local address.
|
/// the provided local address.
|
||||||
pub fn recv(&self, local_address: &SocketAddr) -> Result<Vec<Datagram>, io::Error> {
|
pub fn recv<'a>(
|
||||||
|
&self,
|
||||||
|
local_address: SocketAddr,
|
||||||
|
recv_buf: &'a mut [u8],
|
||||||
|
) -> Result<Option<DatagramIter<'a>>, io::Error> {
|
||||||
self.inner
|
self.inner
|
||||||
.try_io(tokio::io::Interest::READABLE, || {
|
.try_io(tokio::io::Interest::READABLE, || {
|
||||||
neqo_udp::recv_inner(local_address, &self.state, &self.inner)
|
neqo_udp::recv_inner(local_address, &self.state, &self.inner, recv_buf)
|
||||||
})
|
})
|
||||||
|
.map(Some)
|
||||||
.or_else(|e| {
|
.or_else(|e| {
|
||||||
if e.kind() == io::ErrorKind::WouldBlock {
|
if e.kind() == io::ErrorKind::WouldBlock {
|
||||||
Ok(vec![])
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"eabe319e62a4a42e32f4ec35b2ef74eb513f173d11ba9105efb8e33c5e9e7e28","build.rs":"ee5dc521f3d8e18c2b617192d6b6e678f7f2f9886fdd34c0c1c5ef841419b248","src/codec.rs":"6c12d9db7066497f2566e83efc825ae984d04a6b5176010c93d394904103aeed","src/datagram.rs":"2acecfcbecfbb767ea920e3b22388e67b31fcda776cae5b2d7ecbc67dd9febf7","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"1ca74a34bdc97fedecf8a63c4a13cc487d1b2212398fb76f67792c822002138d","src/header.rs":"480a7848466249a78acddbf0bc0b4a096189abc14a89ad1a0943be571add2c2b","src/hrtime.rs":"37447c51c7fd84baad31bc420bf9170c1f4e71356bb6d102bd5651ddf69a2f89","src/incrdecoder.rs":"5c45034e61e75c76d2bca8b075c3e7a3cdd8af8c82b67c76283a2b08ab11846b","src/lib.rs":"2381fc00127a7eaf2265c3a13dc1e1d5843e048f3a8a1c97f1e6621c038de380","src/log.rs":"6ed99e15707c4256ae793011ed2f4b33aa81fed70205aaf5f8d3cd11ad451cf0","src/qlog.rs":"f53cb2a52dd7725c577d4e42065fb1c498ccc33dff0449b6889d9fbc1fdb96e2","src/tos.rs":"28fd9acfce06f68ac6691efd2609618850182f77ef3717ce2db07bfac19a9396","tests/log.rs":"a11e21fb570258ca93bb40e3923817d381e1e605accbc3aed1df5a0a9918b41d"},"package":null}
|
{"files":{"Cargo.toml":"445c47ac5b982936243339e809670d8aa88e7a059a7adc3b49c32e019653507a","build.rs":"ee5dc521f3d8e18c2b617192d6b6e678f7f2f9886fdd34c0c1c5ef841419b248","src/codec.rs":"6c12d9db7066497f2566e83efc825ae984d04a6b5176010c93d394904103aeed","src/datagram.rs":"e8bf176d3b120028731388c17344d03b8195e5fd70f4d03e37144ac5ae5951f5","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"1ca74a34bdc97fedecf8a63c4a13cc487d1b2212398fb76f67792c822002138d","src/header.rs":"480a7848466249a78acddbf0bc0b4a096189abc14a89ad1a0943be571add2c2b","src/hrtime.rs":"37447c51c7fd84baad31bc420bf9170c1f4e71356bb6d102bd5651ddf69a2f89","src/incrdecoder.rs":"5c45034e61e75c76d2bca8b075c3e7a3cdd8af8c82b67c76283a2b08ab11846b","src/lib.rs":"2381fc00127a7eaf2265c3a13dc1e1d5843e048f3a8a1c97f1e6621c038de380","src/log.rs":"6ed99e15707c4256ae793011ed2f4b33aa81fed70205aaf5f8d3cd11ad451cf0","src/qlog.rs":"f53cb2a52dd7725c577d4e42065fb1c498ccc33dff0449b6889d9fbc1fdb96e2","src/tos.rs":"28fd9acfce06f68ac6691efd2609618850182f77ef3717ce2db07bfac19a9396","tests/log.rs":"a11e21fb570258ca93bb40e3923817d381e1e605accbc3aed1df5a0a9918b41d"},"package":null}
|
|
@ -13,7 +13,7 @@
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
name = "neqo-common"
|
name = "neqo-common"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
|
@ -9,23 +9,14 @@ use std::{net::SocketAddr, ops::Deref};
|
||||||
use crate::{hex_with_len, IpTos};
|
use crate::{hex_with_len, IpTos};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Datagram {
|
pub struct Datagram<D = Vec<u8>> {
|
||||||
src: SocketAddr,
|
src: SocketAddr,
|
||||||
dst: SocketAddr,
|
dst: SocketAddr,
|
||||||
tos: IpTos,
|
tos: IpTos,
|
||||||
d: Vec<u8>,
|
d: D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Datagram {
|
impl<D> Datagram<D> {
|
||||||
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, tos: IpTos, d: V) -> Self {
|
|
||||||
Self {
|
|
||||||
src,
|
|
||||||
dst,
|
|
||||||
tos,
|
|
||||||
d: d.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn source(&self) -> SocketAddr {
|
pub const fn source(&self) -> SocketAddr {
|
||||||
self.src
|
self.src
|
||||||
|
@ -46,15 +37,43 @@ impl Datagram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Datagram {
|
impl<D: AsRef<[u8]>> Datagram<D> {
|
||||||
type Target = Vec<u8>;
|
pub fn len(&self) -> usize {
|
||||||
#[must_use]
|
self.d.as_ref().len()
|
||||||
fn deref(&self) -> &Self::Target {
|
}
|
||||||
&self.d
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Datagram {
|
#[cfg(test)]
|
||||||
|
impl<D: AsMut<[u8]> + AsRef<[u8]>> AsMut<[u8]> for Datagram<D> {
|
||||||
|
fn as_mut(&mut self) -> &mut [u8] {
|
||||||
|
self.d.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Datagram<Vec<u8>> {
|
||||||
|
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, tos: IpTos, d: V) -> Self {
|
||||||
|
Self {
|
||||||
|
src,
|
||||||
|
dst,
|
||||||
|
tos,
|
||||||
|
d: d.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: AsRef<[u8]>> Deref for Datagram<D> {
|
||||||
|
type Target = [u8];
|
||||||
|
#[must_use]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
AsRef::<[u8]>::as_ref(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: AsRef<[u8]>> std::fmt::Debug for Datagram<D> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
@ -67,14 +86,46 @@ impl std::fmt::Debug for Datagram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
impl<'a> Datagram<&'a [u8]> {
|
||||||
use test_fixture::datagram;
|
#[must_use]
|
||||||
|
pub const fn from_slice(src: SocketAddr, dst: SocketAddr, tos: IpTos, d: &'a [u8]) -> Self {
|
||||||
|
Self { src, dst, tos, d }
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[must_use]
|
||||||
fn fmt_datagram() {
|
pub fn to_owned(&self) -> Datagram {
|
||||||
let d = datagram([0; 1].to_vec());
|
Datagram {
|
||||||
assert_eq!(
|
src: self.src,
|
||||||
&format!("{d:?}"),
|
dst: self.dst,
|
||||||
"Datagram IpTos(Cs0, Ect0) [fe80::1]:443->[fe80::1]:443: [1]: 00"
|
tos: self.tos,
|
||||||
);
|
d: self.d.to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: AsRef<[u8]>> AsRef<[u8]> for Datagram<D> {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
self.d.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use test_fixture::datagram;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmt_datagram() {
|
||||||
|
let d = datagram([0; 1].to_vec());
|
||||||
|
assert_eq!(
|
||||||
|
&format!("{d:?}"),
|
||||||
|
"Datagram IpTos(Cs0, Ect0) [fe80::1]:443->[fe80::1]:443: [1]: 00"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_empty() {
|
||||||
|
let d = datagram(vec![]);
|
||||||
|
assert_eq!(d.len(), 0);
|
||||||
|
assert!(d.is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"a19a3c6ebbc3eca25aa2b467a1298285cf165df98fbb10c1447b8a5850799cc8","bindings/bindings.toml":"0e06a03035a90ec5f823b30c8b78ec010a332ae0e5ed0c953da2e4c406451793","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"dfc3b2c8038c4b1c69d7a10bd06c4226e36935e7597225aba26039f700cc8f4f","min_version.txt":"04b271df436ebebd03df52ef009d6814f6a64e55203988790a6fcee7b2dc27af","src/aead.rs":"6410bcbe717a6b9ea6f11209b0888033358113ebc05b8a95cec1980d1360be4d","src/aead_null.rs":"81163fafef59bd2800bd0a078d53d0f05ee114f0e22165717823a5ff1cb908af","src/agent.rs":"d24f1a3df8300b93a1b606b2089bd758c9aa41c3a9e333089e6165b3449df94f","src/agentio.rs":"6d86ff8d6319bf6c3dd7124b8d60271e3e1accd07a7b43ba54e81be51c8d2a98","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"8e75e69ec3544474b21f8915a7559463889c2f608b201dee274a8d701880950e","src/constants.rs":"58e296e314825753b2ab1d6effe9a1386421dc568f6ebfa8e95a95acb87205da","src/ech.rs":"75dd192423e8996d9061da5e9c20d30bff5153b9344132eda4fe321c4c141870","src/err.rs":"2366501e0b48933a6a2e1c5b934aa55108c093729c84878b45e1e012e4e45d51","src/exp.rs":"d953873e87430b1c84d4a83c8eb3815041f5585b210bbaf59ae2c4d0057f5edd","src/ext.rs":"cbf7d9f5ecabf4b8c9efd6c334637ab1596ec5266d38ab8d2d6ceae305283deb","src/hkdf.rs":"8745ba761be821c1819cedf6dfd91f8b3148c6718053a4a74f33eb50c7d0cc40","src/hp.rs":"510a4a7f278203aa306ead05608f99397edc3806dc22b0af9e28c665b43ae56c","src/lib.rs":"30632dacb1b6ed9321e42ca1aaa2b71db8d4878eeb27c608e4eabdc0b76bcdba","src/min_version.rs":"c6e1f98b9f56db0622ac38c1be131c55acf4a0f09ed0d6283f4d6308e2d1301a","src/p11.rs":"375397b18fcdf36dcdd22c164c8572dd83caf01b8d0065be3029444b197e1464","src/prio.rs":"5cf0105e78b1db43c65283208174abc3714a41dbb4d5cd80ac547a5a5a7c627c","src/replay.rs":"5cda39bc8fa8a07c493b761b8dfb5cbc9f669f97a2df7832a028ab366b3426be","src/result.rs":"0587cbb6aace71a7f9765ef7c01dcd9f73a49dcc6331e1d8fe4de2aef6ca65b6","src/secrets.rs":"2c47935c5b8c42363897881eaa0c171e84cf031e57a6e1387b99327080e8dd60","src/selfencrypt.rs":"018c2dacabd3e463fdadd5707715b23c26c261c4c7d86e66c62f0acec986cad9","src/ssl.rs":"59bafcaed7caa66fe448339a1f75ce807ef92fc28247709df4f8058499b0787e","src/time.rs":"ade63a72ae90796d7fcccadbb15efc4594fcdb68913a914a657d4556fde88f62","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"cbd0011f1d33281883a45d433228221062424c94e86decade5697731c08a1c52","tests/ext.rs":"57af4e2df211fa8afdb73125d4344ef5c70c1ea4579107c3e6f5746308ee3e7b","tests/handshake.rs":"aa904736d36cc5d5cc0c4f6053b529987f33f944a73411bf08e01d30c4867186","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"ccda23018dac70b3ff3742afcb0fbae0735be9aeb36644a4ae2b1d7c9126801c","tests/init.rs":"3e15150c4b324c06ca5e8935618e4008da53dc0ef4b69325d150831e87dc0b63","tests/selfencrypt.rs":"8d10840b41629bf449a6b3a551377315e8a05ca26c6b041548748196652c5909"},"package":null}
|
{"files":{"Cargo.toml":"3452a05725c5e72f51dc242fad2523fede8e752bf93f05a5b3b1808b0616cff7","bindings/bindings.toml":"0e06a03035a90ec5f823b30c8b78ec010a332ae0e5ed0c953da2e4c406451793","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"dfc3b2c8038c4b1c69d7a10bd06c4226e36935e7597225aba26039f700cc8f4f","min_version.txt":"04b271df436ebebd03df52ef009d6814f6a64e55203988790a6fcee7b2dc27af","src/aead.rs":"6410bcbe717a6b9ea6f11209b0888033358113ebc05b8a95cec1980d1360be4d","src/aead_null.rs":"81163fafef59bd2800bd0a078d53d0f05ee114f0e22165717823a5ff1cb908af","src/agent.rs":"d24f1a3df8300b93a1b606b2089bd758c9aa41c3a9e333089e6165b3449df94f","src/agentio.rs":"6d86ff8d6319bf6c3dd7124b8d60271e3e1accd07a7b43ba54e81be51c8d2a98","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"8e75e69ec3544474b21f8915a7559463889c2f608b201dee274a8d701880950e","src/constants.rs":"58e296e314825753b2ab1d6effe9a1386421dc568f6ebfa8e95a95acb87205da","src/ech.rs":"75dd192423e8996d9061da5e9c20d30bff5153b9344132eda4fe321c4c141870","src/err.rs":"2366501e0b48933a6a2e1c5b934aa55108c093729c84878b45e1e012e4e45d51","src/exp.rs":"d953873e87430b1c84d4a83c8eb3815041f5585b210bbaf59ae2c4d0057f5edd","src/ext.rs":"cbf7d9f5ecabf4b8c9efd6c334637ab1596ec5266d38ab8d2d6ceae305283deb","src/hkdf.rs":"8745ba761be821c1819cedf6dfd91f8b3148c6718053a4a74f33eb50c7d0cc40","src/hp.rs":"510a4a7f278203aa306ead05608f99397edc3806dc22b0af9e28c665b43ae56c","src/lib.rs":"30632dacb1b6ed9321e42ca1aaa2b71db8d4878eeb27c608e4eabdc0b76bcdba","src/min_version.rs":"c6e1f98b9f56db0622ac38c1be131c55acf4a0f09ed0d6283f4d6308e2d1301a","src/p11.rs":"375397b18fcdf36dcdd22c164c8572dd83caf01b8d0065be3029444b197e1464","src/prio.rs":"5cf0105e78b1db43c65283208174abc3714a41dbb4d5cd80ac547a5a5a7c627c","src/replay.rs":"5cda39bc8fa8a07c493b761b8dfb5cbc9f669f97a2df7832a028ab366b3426be","src/result.rs":"0587cbb6aace71a7f9765ef7c01dcd9f73a49dcc6331e1d8fe4de2aef6ca65b6","src/secrets.rs":"2c47935c5b8c42363897881eaa0c171e84cf031e57a6e1387b99327080e8dd60","src/selfencrypt.rs":"018c2dacabd3e463fdadd5707715b23c26c261c4c7d86e66c62f0acec986cad9","src/ssl.rs":"59bafcaed7caa66fe448339a1f75ce807ef92fc28247709df4f8058499b0787e","src/time.rs":"ade63a72ae90796d7fcccadbb15efc4594fcdb68913a914a657d4556fde88f62","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"cbd0011f1d33281883a45d433228221062424c94e86decade5697731c08a1c52","tests/ext.rs":"57af4e2df211fa8afdb73125d4344ef5c70c1ea4579107c3e6f5746308ee3e7b","tests/handshake.rs":"aa904736d36cc5d5cc0c4f6053b529987f33f944a73411bf08e01d30c4867186","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"ccda23018dac70b3ff3742afcb0fbae0735be9aeb36644a4ae2b1d7c9126801c","tests/init.rs":"3e15150c4b324c06ca5e8935618e4008da53dc0ef4b69325d150831e87dc0b63","tests/selfencrypt.rs":"8d10840b41629bf449a6b3a551377315e8a05ca26c6b041548748196652c5909"},"package":null}
|
|
@ -13,7 +13,7 @@
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
name = "neqo-crypto"
|
name = "neqo-crypto"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"371b4660d42aaef9557a5ce91ad7eac0b78d02d13bd9d3f5dad327a6382e6c8b","src/buffered_send_stream.rs":"dfb248c66ea65418b0c7798c2ecaa3ed70ef1af818ef58d53ef742b3445077b7","src/client_events.rs":"77fedca72ce54956eaba3fb7103085d196a631b764662584ea2629224c5c234e","src/conn_params.rs":"7f0df52bceda1923aef2b7c5c64a532f49ea083ea45e3dcd5bd4b03031b89643","src/connection.rs":"1bf52ac3f3714f5bb2b1237fdb7b026ee4a2183f8f173120661f46213f8c5daa","src/connection_client.rs":"e1ad0e79033735373b5c90971f5ef6269c937f9677ab9ec3a271d6a1b5128370","src/connection_server.rs":"cf4da2cdd823e31d2352e45de84d366c45bd3d8adf38c9151a84d808bda80209","src/control_stream_local.rs":"20917762c7e7c1112c56abf1cbaf0ad7f0eab97d8db9a3b10ff524315a235670","src/control_stream_remote.rs":"3729f67aa0681b1dbd4147063890f8440f27d82454776500ae964a17cda4d6b5","src/features/extended_connect/mod.rs":"cbeb2294eaf34f08a2c0d0fe4d3473aea9c65df6faaec9dc3ed29dcb577b1c3f","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"51d6f3828c44b438eb1776e8dcce531af520f28bc0d715807d3f53a0eaa071d1","src/features/extended_connect/tests/webtransport/mod.rs":"3359db4affc034e92b4887a2f564261ce1b3c7f2f7e5ca06d5df7625dbe698ed","src/features/extended_connect/tests/webtransport/negotiation.rs":"a22094dbaf0754d39ac8ac08fce1ae34ace108220b696c7d618567df56cddeec","src/features/extended_connect/tests/webtransport/sessions.rs":"53198069200292a15788eb9de304f670f0044c81df756ce8226d49ea394bc4ec","src/features/extended_connect/tests/webtransport/streams.rs":"eab84efc920b766ea105a47d34bec565f79f64f6c6be1b7f4945d78bddb462fd","src/features/extended_connect/webtransport_session.rs":"debe63b81c8c3c49da9f2b9abb92ea05fb95745a8ee725a956dfeffa53dc9574","src/features/extended_connect/webtransport_streams.rs":"9855d77705acb7d21566333c4b297816e363be2ade14b8685fd1df4a4861cf74","src/features/mod.rs":"89056df3a868cb0037963c942fc27093cc16d84538ffca2d4759f9a6a6c74c7f","src/frames/hframe.rs":"de2c3d1a9205b0459fe676d7d5e1c0e463d3c1dd9e5f518a07b2e4ebbe66e3ec","src/frames/mod.rs":"0e6d49888d723b2c2c73df11020ceb88d9f062e9d4dc436eb38173e0b772d905","src/frames/reader.rs":"01acff3c6bb9d2a0c2ff68b054276fab8d61a47679bec9084d75c4f680a959b3","src/frames/tests/hframe.rs":"53941fd7656f5e424d499278e6d9ba93ce716f219e86fe6fa08c058ea92f8d7b","src/frames/tests/mod.rs":"c6bbf85fbc6cb9adf6115d315f0564317eefd83ff3177c93050844ad77f6e694","src/frames/tests/reader.rs":"9ee0d9cdd87b98da2b94e577bbcc2bfde6d72be5177bf02364188935f79cb36a","src/frames/tests/wtframe.rs":"c6598d24f5e12972f02de6e1394362671633982db637a07e1c0bb9b56d93ea2a","src/frames/wtframe.rs":"0f0366e590f7409580459e8a8b86fc48308ca7585837dddd7c319581a9a5a972","src/headers_checks.rs":"69964deb121721be01df7174c177543c161389295ce1450d348369279e312ba4","src/lib.rs":"3fb980eee46bee8dcb97ad9d55014555d8994a7a2d040ca223f2d28fe7d923ef","src/priority.rs":"946307329f31819d969093406ae5448f7923343ccc112221ea6eedf86cf447dc","src/push_controller.rs":"53f72e8043505f85cba0f9c16b4a5ce14d6668b030d773067bc88b2a10bdd25b","src/qlog.rs":"db5f2dd6566d44b4f0541f75266b417b558c09e62141f056885cb8c66478a932","src/qpack_decoder_receiver.rs":"eb06c4be59da567fef70c20daa2c0f165c768131165479a210e69659f168b88f","src/qpack_encoder_receiver.rs":"831f3da9ec17966286786ba3f2c723395a132e65d6a33b4ec341fe7640c1a53d","src/recv_message.rs":"8b2fb49850560b32dcdd7a90933361ef7d61bc42daad3f2952462913d49e8787","src/request_target.rs":"9720b9f87d66a7c2301bba7de5a5a9300f547613a63153a4d35c7a7506a59b31","src/send_message.rs":"be4e9f64db2c25eb7176b84695e608e768115d62e615d389a33d26f7cd5b0c6c","src/server.rs":"8d48376abf36d036f51a84cddcc3d5acd56786b181fba0e24449e1417b030d63","src/server_connection_events.rs":"1396baab265a814045ccfe63d637a4fdc32a667b5eb2925fa4951f5c3078fb20","src/server_events.rs":"02fc8c0711efd758fb1ddee27d257c12ed35e2a989e7bf3de44bd662dc8234e3","src/settings.rs":"d0f8c546e70161422a029a40564b9e9b953fe671c60835196b16f3364779eaf9","src/stream_type_reader.rs":"4e79202e7f1415165fe4eb88b9af67cbb8f85a13d68a577249c397fd5a78dbfb","tests/httpconn.rs":"87c32197258711d916cace23ed850c5bf0198f5e32756c68a32d91206b6e6db8","tests/priority.rs":"364754507873298612ad12e8d1d106d26d993712142d0be4cbf056da5338854c","tests/send_message.rs":"cdf7028eb64f8f3778c3bbb2a10e9482c4e995e9e1813143ccd83ec96b2d4b6a","tests/webtransport.rs":"02b81be0a20252a8bb0796b5287e426c1af5ddaf5a47d68aa9165393cba83c45"},"package":null}
|
{"files":{"Cargo.toml":"8598be82b6e7ce910c20bf0fc518ca50d4cd5698b4f5408f1b33de6dd4169009","src/buffered_send_stream.rs":"dfb248c66ea65418b0c7798c2ecaa3ed70ef1af818ef58d53ef742b3445077b7","src/client_events.rs":"77fedca72ce54956eaba3fb7103085d196a631b764662584ea2629224c5c234e","src/conn_params.rs":"7f0df52bceda1923aef2b7c5c64a532f49ea083ea45e3dcd5bd4b03031b89643","src/connection.rs":"1bf52ac3f3714f5bb2b1237fdb7b026ee4a2183f8f173120661f46213f8c5daa","src/connection_client.rs":"a27423973be27501bb8e8ae169938fa215322fa78f7f5b95cb418adc6fa8b7a1","src/connection_server.rs":"cf4da2cdd823e31d2352e45de84d366c45bd3d8adf38c9151a84d808bda80209","src/control_stream_local.rs":"20917762c7e7c1112c56abf1cbaf0ad7f0eab97d8db9a3b10ff524315a235670","src/control_stream_remote.rs":"3729f67aa0681b1dbd4147063890f8440f27d82454776500ae964a17cda4d6b5","src/features/extended_connect/mod.rs":"f9a08a6ec1dde79133c18c21b85f6b9a01468d98bace838f559340383cc603e7","src/features/extended_connect/tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","src/features/extended_connect/tests/webtransport/datagrams.rs":"51d6f3828c44b438eb1776e8dcce531af520f28bc0d715807d3f53a0eaa071d1","src/features/extended_connect/tests/webtransport/mod.rs":"7828af3887acc5b141ec1af459069eeb4f2d95e7c9e5639047006c179ce6a355","src/features/extended_connect/tests/webtransport/negotiation.rs":"6ddb604a0aa521335ab84ff07718e485f926a27da730d5697c33d6df62af39d6","src/features/extended_connect/tests/webtransport/sessions.rs":"6ed8c6247a84916cf6bb6dc4eeded20f1d80c6d2ea8f256975786c5f3ab2efcb","src/features/extended_connect/tests/webtransport/streams.rs":"eab84efc920b766ea105a47d34bec565f79f64f6c6be1b7f4945d78bddb462fd","src/features/extended_connect/webtransport_session.rs":"debe63b81c8c3c49da9f2b9abb92ea05fb95745a8ee725a956dfeffa53dc9574","src/features/extended_connect/webtransport_streams.rs":"9855d77705acb7d21566333c4b297816e363be2ade14b8685fd1df4a4861cf74","src/features/mod.rs":"89056df3a868cb0037963c942fc27093cc16d84538ffca2d4759f9a6a6c74c7f","src/frames/hframe.rs":"de2c3d1a9205b0459fe676d7d5e1c0e463d3c1dd9e5f518a07b2e4ebbe66e3ec","src/frames/mod.rs":"0e6d49888d723b2c2c73df11020ceb88d9f062e9d4dc436eb38173e0b772d905","src/frames/reader.rs":"01acff3c6bb9d2a0c2ff68b054276fab8d61a47679bec9084d75c4f680a959b3","src/frames/tests/hframe.rs":"53941fd7656f5e424d499278e6d9ba93ce716f219e86fe6fa08c058ea92f8d7b","src/frames/tests/mod.rs":"6cb78d24bbab27f877d0526deb3e9a26694a23a9ce8ebe664947a852a3d92747","src/frames/tests/reader.rs":"6fb66c7a03acfc2e231e7bb3d020c902b59366a7523e488d118b24440ac68501","src/frames/tests/wtframe.rs":"c6598d24f5e12972f02de6e1394362671633982db637a07e1c0bb9b56d93ea2a","src/frames/wtframe.rs":"0f0366e590f7409580459e8a8b86fc48308ca7585837dddd7c319581a9a5a972","src/headers_checks.rs":"69964deb121721be01df7174c177543c161389295ce1450d348369279e312ba4","src/lib.rs":"3fb980eee46bee8dcb97ad9d55014555d8994a7a2d040ca223f2d28fe7d923ef","src/priority.rs":"946307329f31819d969093406ae5448f7923343ccc112221ea6eedf86cf447dc","src/push_controller.rs":"7f8b668d7ff16372693830ac4d3e6834e77465762a0a8d77ab7f9e883c2fb919","src/qlog.rs":"db5f2dd6566d44b4f0541f75266b417b558c09e62141f056885cb8c66478a932","src/qpack_decoder_receiver.rs":"eb06c4be59da567fef70c20daa2c0f165c768131165479a210e69659f168b88f","src/qpack_encoder_receiver.rs":"831f3da9ec17966286786ba3f2c723395a132e65d6a33b4ec341fe7640c1a53d","src/recv_message.rs":"8b2fb49850560b32dcdd7a90933361ef7d61bc42daad3f2952462913d49e8787","src/request_target.rs":"9720b9f87d66a7c2301bba7de5a5a9300f547613a63153a4d35c7a7506a59b31","src/send_message.rs":"be4e9f64db2c25eb7176b84695e608e768115d62e615d389a33d26f7cd5b0c6c","src/server.rs":"c6a231fea182acd4f7e064578a1ad85a5fa0f618f3e0842d499f84f841bbf9da","src/server_connection_events.rs":"1396baab265a814045ccfe63d637a4fdc32a667b5eb2925fa4951f5c3078fb20","src/server_events.rs":"02fc8c0711efd758fb1ddee27d257c12ed35e2a989e7bf3de44bd662dc8234e3","src/settings.rs":"d0f8c546e70161422a029a40564b9e9b953fe671c60835196b16f3364779eaf9","src/stream_type_reader.rs":"115d50bbaa304a74d601614b755bcb626572ab89d5db7bfae9fff8ad64270722","tests/httpconn.rs":"72b4f66fc9b9efeb070907da35f1db2d320d232ef74380fd36ad7c2ddd213076","tests/priority.rs":"3b0e03d6a8fbde52c695130bb3e40d3b70cb74ee826af28db577060911bcbc03","tests/send_message.rs":"9540259485e8b7df1d07ff8abdc8cb86d5f32d736aea3bce28e8b0ecc00a9f5b","tests/webtransport.rs":"3bfcfddd57a8fe262c597b756982d671065a593d99d09d42b04f954a27a2a5fa"},"package":null}
|
|
@ -13,7 +13,7 @@
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
name = "neqo-http3"
|
name = "neqo-http3"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
||||||
build = false
|
build = false
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -68,7 +68,7 @@ pub(crate) enum ExtendedConnectType {
|
||||||
impl ExtendedConnectType {
|
impl ExtendedConnectType {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::unused_self)] // This will change when we have more features using ExtendedConnectType.
|
#[allow(clippy::unused_self)] // This will change when we have more features using ExtendedConnectType.
|
||||||
pub const fn string(&self) -> &str {
|
pub const fn string(self) -> &'static str {
|
||||||
"webtransport"
|
"webtransport"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,8 @@ pub fn default_http3_server(server_params: Http3Parameters) -> Http3Server {
|
||||||
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
let mut out = None;
|
let mut out = None;
|
||||||
loop {
|
loop {
|
||||||
out = client.process(out.as_ref(), now()).dgram();
|
out = client.process(out, now()).dgram();
|
||||||
out = server.process(out.as_ref(), now()).dgram();
|
out = server.process(out, now()).dgram();
|
||||||
if out.is_none() {
|
if out.is_none() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -74,31 +74,31 @@ fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
// Perform only Quic transport handshake.
|
// Perform only Quic transport handshake.
|
||||||
fn connect_with(client: &mut Http3Client, server: &mut Http3Server) {
|
fn connect_with(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
assert_eq!(client.state(), Http3State::Initializing);
|
assert_eq!(client.state(), Http3State::Initializing);
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert_eq!(client.state(), Http3State::Initializing);
|
assert_eq!(client.state(), Http3State::Initializing);
|
||||||
|
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
||||||
assert!(client.events().any(authentication_needed));
|
assert!(client.events().any(authentication_needed));
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
|
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
|
let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
|
||||||
assert!(client.events().any(connected));
|
assert!(client.events().any(connected));
|
||||||
|
|
||||||
assert_eq!(client.state(), Http3State::Connected);
|
assert_eq!(client.state(), Http3State::Connected);
|
||||||
|
|
||||||
// Exchange H3 setttings
|
// Exchange H3 setttings
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
std::mem::drop(client.process(out.as_dgram_ref(), now()));
|
std::mem::drop(client.process(out.dgram(), now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect(
|
fn connect(
|
||||||
|
@ -200,10 +200,10 @@ impl WtTest {
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
loop {
|
loop {
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
out = self.client.process(out.as_ref(), now).dgram();
|
out = self.client.process(out, now).dgram();
|
||||||
let client_none = out.is_none();
|
let client_none = out.is_none();
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
out = self.server.process(out.as_ref(), now).dgram();
|
out = self.server.process(out, now).dgram();
|
||||||
if client_none && out.is_none() {
|
if client_none && out.is_none() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,9 +86,9 @@ fn zero_rtt(
|
||||||
assert_eq!(client.webtransport_enabled(), client_org && server_org);
|
assert_eq!(client.webtransport_enabled(), client_org && server_org);
|
||||||
|
|
||||||
// exchange token
|
// exchange token
|
||||||
let out = server.process(None, now());
|
let out = server.process_output(now());
|
||||||
// We do not have a token so we need to wait for a resumption token timer to trigger.
|
// We do not have a token so we need to wait for a resumption token timer to trigger.
|
||||||
std::mem::drop(client.process(out.as_dgram_ref(), now() + Duration::from_millis(250)));
|
std::mem::drop(client.process(out.dgram(), now() + Duration::from_millis(250)));
|
||||||
assert_eq!(client.state(), Http3State::Connected);
|
assert_eq!(client.state(), Http3State::Connected);
|
||||||
let token = client
|
let token = client
|
||||||
.events()
|
.events()
|
||||||
|
@ -233,8 +233,8 @@ fn zero_rtt_wt_settings() {
|
||||||
fn exchange_packets2(client: &mut Http3Client, server: &mut Connection) {
|
fn exchange_packets2(client: &mut Http3Client, server: &mut Connection) {
|
||||||
let mut out = None;
|
let mut out = None;
|
||||||
loop {
|
loop {
|
||||||
out = client.process(out.as_ref(), now()).dgram();
|
out = client.process(out, now()).dgram();
|
||||||
out = server.process(out.as_ref(), now()).dgram();
|
out = server.process(out, now()).dgram();
|
||||||
if out.is_none() {
|
if out.is_none() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,18 +425,18 @@ fn wt_close_session_cannot_be_sent_at_once() {
|
||||||
Err(Error::InvalidStreamId)
|
Err(Error::InvalidStreamId)
|
||||||
);
|
);
|
||||||
|
|
||||||
let out = wt.server.process(None, now());
|
let out = wt.server.process_output(now());
|
||||||
let out = wt.client.process(out.as_dgram_ref(), now());
|
let out = wt.client.process(out.dgram(), now());
|
||||||
|
|
||||||
// Client has not received the full CloseSession frame and it can create more streams.
|
// Client has not received the full CloseSession frame and it can create more streams.
|
||||||
let unidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
|
let unidi_client = wt.create_wt_stream_client(wt_session.stream_id(), StreamType::UniDi);
|
||||||
|
|
||||||
let out = wt.server.process(out.as_dgram_ref(), now());
|
let out = wt.server.process(out.dgram(), now());
|
||||||
let out = wt.client.process(out.as_dgram_ref(), now());
|
let out = wt.client.process(out.dgram(), now());
|
||||||
let out = wt.server.process(out.as_dgram_ref(), now());
|
let out = wt.server.process(out.dgram(), now());
|
||||||
let out = wt.client.process(out.as_dgram_ref(), now());
|
let out = wt.client.process(out.dgram(), now());
|
||||||
let out = wt.server.process(out.as_dgram_ref(), now());
|
let out = wt.server.process(out.dgram(), now());
|
||||||
let _out = wt.client.process(out.as_dgram_ref(), now());
|
let _out = wt.client.process(out.dgram(), now());
|
||||||
|
|
||||||
wt.check_events_after_closing_session_client(
|
wt.check_events_after_closing_session_client(
|
||||||
&[],
|
&[],
|
||||||
|
|
|
@ -22,13 +22,13 @@ pub fn enc_dec<T: FrameDecoder<T>>(d: &Encoder, st: &str, remaining: usize) -> T
|
||||||
|
|
||||||
let mut conn_c = default_client();
|
let mut conn_c = default_client();
|
||||||
let mut conn_s = default_server();
|
let mut conn_s = default_server();
|
||||||
let out = conn_c.process(None, now());
|
let out = conn_c.process_output(now());
|
||||||
let out = conn_s.process(out.as_dgram_ref(), now());
|
let out = conn_s.process(out.dgram(), now());
|
||||||
let out = conn_c.process(out.as_dgram_ref(), now());
|
let out = conn_c.process(out.dgram(), now());
|
||||||
mem::drop(conn_s.process(out.as_dgram_ref(), now()));
|
mem::drop(conn_s.process(out.dgram(), now()));
|
||||||
conn_c.authenticated(AuthenticationStatus::Ok, now());
|
conn_c.authenticated(AuthenticationStatus::Ok, now());
|
||||||
let out = conn_c.process(None, now());
|
let out = conn_c.process_output(now());
|
||||||
mem::drop(conn_s.process(out.as_dgram_ref(), now()));
|
mem::drop(conn_s.process(out.dgram(), now()));
|
||||||
|
|
||||||
// create a stream
|
// create a stream
|
||||||
let stream_id = conn_s.stream_create(StreamType::BiDi).unwrap();
|
let stream_id = conn_s.stream_create(StreamType::BiDi).unwrap();
|
||||||
|
@ -38,8 +38,8 @@ pub fn enc_dec<T: FrameDecoder<T>>(d: &Encoder, st: &str, remaining: usize) -> T
|
||||||
// conver string into u8 vector
|
// conver string into u8 vector
|
||||||
let buf = Encoder::from_hex(st);
|
let buf = Encoder::from_hex(st);
|
||||||
conn_s.stream_send(stream_id, buf.as_ref()).unwrap();
|
conn_s.stream_send(stream_id, buf.as_ref()).unwrap();
|
||||||
let out = conn_s.process(None, now());
|
let out = conn_s.process_output(now());
|
||||||
mem::drop(conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(conn_c.process(out.dgram(), now()));
|
||||||
|
|
||||||
let (frame, fin) = fr
|
let (frame, fin) = fr
|
||||||
.receive::<T>(&mut StreamReaderConnectionWrapper::new(
|
.receive::<T>(&mut StreamReaderConnectionWrapper::new(
|
||||||
|
|
|
@ -39,8 +39,8 @@ impl FrameReaderTest {
|
||||||
|
|
||||||
fn process<T: FrameDecoder<T>>(&mut self, v: &[u8]) -> Option<T> {
|
fn process<T: FrameDecoder<T>>(&mut self, v: &[u8]) -> Option<T> {
|
||||||
self.conn_s.stream_send(self.stream_id, v).unwrap();
|
self.conn_s.stream_send(self.stream_id, v).unwrap();
|
||||||
let out = self.conn_s.process(None, now());
|
let out = self.conn_s.process_output(now());
|
||||||
mem::drop(self.conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(self.conn_c.process(out.dgram(), now()));
|
||||||
let (frame, fin) = self
|
let (frame, fin) = self
|
||||||
.fr
|
.fr
|
||||||
.receive::<T>(&mut StreamReaderConnectionWrapper::new(
|
.receive::<T>(&mut StreamReaderConnectionWrapper::new(
|
||||||
|
@ -230,13 +230,13 @@ fn test_reading_frame<T: FrameDecoder<T> + PartialEq + Debug>(
|
||||||
fr.conn_s.stream_close_send(fr.stream_id).unwrap();
|
fr.conn_s.stream_close_send(fr.stream_id).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let out = fr.conn_s.process(None, now());
|
let out = fr.conn_s.process_output(now());
|
||||||
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(fr.conn_c.process(out.dgram(), now()));
|
||||||
|
|
||||||
if matches!(test_to_send, FrameReadingTestSend::DataThenFin) {
|
if matches!(test_to_send, FrameReadingTestSend::DataThenFin) {
|
||||||
fr.conn_s.stream_close_send(fr.stream_id).unwrap();
|
fr.conn_s.stream_close_send(fr.stream_id).unwrap();
|
||||||
let out = fr.conn_s.process(None, now());
|
let out = fr.conn_s.process_output(now());
|
||||||
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(fr.conn_c.process(out.dgram(), now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let rv = fr.fr.receive::<T>(&mut StreamReaderConnectionWrapper::new(
|
let rv = fr.fr.receive::<T>(&mut StreamReaderConnectionWrapper::new(
|
||||||
|
@ -478,12 +478,12 @@ fn frame_reading_when_stream_is_closed_before_sending_data() {
|
||||||
let mut fr = FrameReaderTest::new();
|
let mut fr = FrameReaderTest::new();
|
||||||
|
|
||||||
fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap();
|
fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap();
|
||||||
let out = fr.conn_s.process(None, now());
|
let out = fr.conn_s.process_output(now());
|
||||||
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(fr.conn_c.process(out.dgram(), now()));
|
||||||
|
|
||||||
assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id));
|
assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id));
|
||||||
let out = fr.conn_c.process(None, now());
|
let out = fr.conn_c.process_output(now());
|
||||||
mem::drop(fr.conn_s.process(out.as_dgram_ref(), now()));
|
mem::drop(fr.conn_s.process(out.dgram(), now()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((None, true)),
|
Ok((None, true)),
|
||||||
fr.fr
|
fr.fr
|
||||||
|
@ -501,12 +501,12 @@ fn wt_frame_reading_when_stream_is_closed_before_sending_data() {
|
||||||
let mut fr = FrameReaderTest::new();
|
let mut fr = FrameReaderTest::new();
|
||||||
|
|
||||||
fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap();
|
fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap();
|
||||||
let out = fr.conn_s.process(None, now());
|
let out = fr.conn_s.process_output(now());
|
||||||
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(fr.conn_c.process(out.dgram(), now()));
|
||||||
|
|
||||||
assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id));
|
assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id));
|
||||||
let out = fr.conn_c.process(None, now());
|
let out = fr.conn_c.process_output(now());
|
||||||
mem::drop(fr.conn_s.process(out.as_dgram_ref(), now()));
|
mem::drop(fr.conn_s.process(out.dgram(), now()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok((None, true)),
|
Ok((None, true)),
|
||||||
fr.fr
|
fr.fr
|
||||||
|
|
|
@ -364,7 +364,7 @@ impl PushController {
|
||||||
}
|
}
|
||||||
Some(PushState::Active { stream_id, .. }) => {
|
Some(PushState::Active { stream_id, .. }) => {
|
||||||
self.conn_events.remove_events_for_push_id(push_id);
|
self.conn_events.remove_events_for_push_id(push_id);
|
||||||
// Cancel the stream. the transport steam may already be done, so ignore an error.
|
// Cancel the stream. The transport stream may already be done, so ignore an error.
|
||||||
mem::drop(base_handler.stream_stop_sending(
|
mem::drop(base_handler.stream_stop_sending(
|
||||||
conn,
|
conn,
|
||||||
*stream_id,
|
*stream_id,
|
||||||
|
|
|
@ -113,7 +113,12 @@ impl Http3Server {
|
||||||
self.server.ech_config()
|
self.server.ech_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output {
|
/// Short-hand for [`Http3Server::process`] with no input datagram.
|
||||||
|
pub fn process_output(&mut self, now: Instant) -> Output {
|
||||||
|
self.process(None::<Datagram>, now)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(&mut self, dgram: Option<Datagram<impl AsRef<[u8]>>>, now: Instant) -> Output {
|
||||||
qtrace!([self], "Process.");
|
qtrace!([self], "Process.");
|
||||||
let out = self.server.process(dgram, now);
|
let out = self.server.process(dgram, now);
|
||||||
self.process_http3(now);
|
self.process_http3(now);
|
||||||
|
@ -123,7 +128,7 @@ impl Http3Server {
|
||||||
qtrace!([self], "Send packet: {:?}", d);
|
qtrace!([self], "Send packet: {:?}", d);
|
||||||
Output::Datagram(d)
|
Output::Datagram(d)
|
||||||
}
|
}
|
||||||
_ => self.server.process(Option::<&Datagram>::None, now),
|
_ => self.server.process(Option::<Datagram>::None, now),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,29 +401,29 @@ mod tests {
|
||||||
const SERVER_SIDE_DECODER_STREAM_ID: StreamId = StreamId::new(11);
|
const SERVER_SIDE_DECODER_STREAM_ID: StreamId = StreamId::new(11);
|
||||||
|
|
||||||
fn connect_transport(server: &mut Http3Server, client: &mut Connection, resume: bool) {
|
fn connect_transport(server: &mut Http3Server, client: &mut Connection, resume: bool) {
|
||||||
let c1 = client.process(None, now());
|
let c1 = client.process_output(now());
|
||||||
let s1 = server.process(c1.as_dgram_ref(), now());
|
let s1 = server.process(c1.dgram(), now());
|
||||||
let c2 = client.process(s1.as_dgram_ref(), now());
|
let c2 = client.process(s1.dgram(), now());
|
||||||
let needs_auth = client
|
let needs_auth = client
|
||||||
.events()
|
.events()
|
||||||
.any(|e| e == ConnectionEvent::AuthenticationNeeded);
|
.any(|e| e == ConnectionEvent::AuthenticationNeeded);
|
||||||
let c2 = if needs_auth {
|
let c2 = if needs_auth {
|
||||||
assert!(!resume);
|
assert!(!resume);
|
||||||
// c2 should just be an ACK, so absorb that.
|
// c2 should just be an ACK, so absorb that.
|
||||||
let s_ack = server.process(c2.as_dgram_ref(), now());
|
let s_ack = server.process(c2.dgram(), now());
|
||||||
assert!(s_ack.as_dgram_ref().is_none());
|
assert!(s_ack.dgram().is_none());
|
||||||
|
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
client.process(None, now())
|
client.process_output(now())
|
||||||
} else {
|
} else {
|
||||||
assert!(resume);
|
assert!(resume);
|
||||||
c2
|
c2
|
||||||
};
|
};
|
||||||
assert!(client.state().connected());
|
assert!(client.state().connected());
|
||||||
let s2 = server.process(c2.as_dgram_ref(), now());
|
let s2 = server.process(c2.dgram(), now());
|
||||||
assert_connected(server);
|
assert_connected(server);
|
||||||
let c3 = client.process(s2.as_dgram_ref(), now());
|
let c3 = client.process(s2.dgram(), now());
|
||||||
assert!(c3.as_dgram_ref().is_none());
|
assert!(c3.dgram().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a client/server and check setting frame.
|
// Start a client/server and check setting frame.
|
||||||
|
@ -552,9 +557,9 @@ mod tests {
|
||||||
let decoder_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
|
let decoder_stream = neqo_trans_conn.stream_create(StreamType::UniDi).unwrap();
|
||||||
sent = neqo_trans_conn.stream_send(decoder_stream, &[0x3]);
|
sent = neqo_trans_conn.stream_send(decoder_stream, &[0x3]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out1 = neqo_trans_conn.process(None, now());
|
let out1 = neqo_trans_conn.process_output(now());
|
||||||
let out2 = server.process(out1.as_dgram_ref(), now());
|
let out2 = server.process(out1.dgram(), now());
|
||||||
mem::drop(neqo_trans_conn.process(out2.as_dgram_ref(), now()));
|
mem::drop(neqo_trans_conn.process(out2.dgram(), now()));
|
||||||
|
|
||||||
// assert no error occured.
|
// assert no error occured.
|
||||||
assert_not_closed(server);
|
assert_not_closed(server);
|
||||||
|
@ -584,8 +589,8 @@ mod tests {
|
||||||
let (mut hconn, mut peer_conn) = connect();
|
let (mut hconn, mut peer_conn) = connect();
|
||||||
let control = peer_conn.control_stream_id;
|
let control = peer_conn.control_stream_id;
|
||||||
peer_conn.stream_close_send(control).unwrap();
|
peer_conn.stream_close_send(control).unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,8 +604,8 @@ mod tests {
|
||||||
// Send a MAX_PUSH_ID frame instead.
|
// Send a MAX_PUSH_ID frame instead.
|
||||||
let sent = neqo_trans_conn.stream_send(control_stream, &[0x0, 0xd, 0x1, 0xf]);
|
let sent = neqo_trans_conn.stream_send(control_stream, &[0x0, 0xd, 0x1, 0xf]);
|
||||||
assert_eq!(sent, Ok(4));
|
assert_eq!(sent, Ok(4));
|
||||||
let out = neqo_trans_conn.process(None, now());
|
let out = neqo_trans_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpMissingSettings);
|
assert_closed(&hconn, &Error::HttpMissingSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,8 +616,8 @@ mod tests {
|
||||||
let (mut hconn, mut peer_conn) = connect();
|
let (mut hconn, mut peer_conn) = connect();
|
||||||
// send the second SETTINGS frame.
|
// send the second SETTINGS frame.
|
||||||
peer_conn.control_send(&[0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64]);
|
peer_conn.control_send(&[0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64]);
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpFrameUnexpected);
|
assert_closed(&hconn, &Error::HttpFrameUnexpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,8 +631,8 @@ mod tests {
|
||||||
let mut e = Encoder::default();
|
let mut e = Encoder::default();
|
||||||
frame.encode(&mut e);
|
frame.encode(&mut e);
|
||||||
peer_conn.control_send(e.as_ref());
|
peer_conn.control_send(e.as_ref());
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
// check if the given connection got closed on invalid stream ids
|
// check if the given connection got closed on invalid stream ids
|
||||||
if valid {
|
if valid {
|
||||||
assert_not_closed(&hconn);
|
assert_not_closed(&hconn);
|
||||||
|
@ -669,8 +674,8 @@ mod tests {
|
||||||
// receive a frame that is not allowed on the control stream.
|
// receive a frame that is not allowed on the control stream.
|
||||||
peer_conn.control_send(v);
|
peer_conn.control_send(v);
|
||||||
|
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpFrameUnexpected);
|
assert_closed(&hconn, &Error::HttpFrameUnexpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,11 +708,11 @@ mod tests {
|
||||||
_ = peer_conn
|
_ = peer_conn
|
||||||
.stream_send(new_stream_id, &[0x41, 0x19, 0x4, 0x4, 0x6, 0x0, 0x8, 0x0])
|
.stream_send(new_stream_id, &[0x41, 0x19, 0x4, 0x4, 0x6, 0x0, 0x8, 0x0])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
let out = hconn.process(out.as_dgram_ref(), now());
|
let out = hconn.process(out.dgram(), now());
|
||||||
mem::drop(peer_conn.process(out.as_dgram_ref(), now()));
|
mem::drop(peer_conn.process(out.dgram(), now()));
|
||||||
let out = hconn.process(None, now());
|
let out = hconn.process_output(now());
|
||||||
mem::drop(peer_conn.process(out.as_dgram_ref(), now()));
|
mem::drop(peer_conn.process(out.dgram(), now()));
|
||||||
|
|
||||||
// check for stop-sending with Error::HttpStreamCreation.
|
// check for stop-sending with Error::HttpStreamCreation.
|
||||||
let mut stop_sending_event_found = false;
|
let mut stop_sending_event_found = false;
|
||||||
|
@ -734,9 +739,9 @@ mod tests {
|
||||||
// create a push stream.
|
// create a push stream.
|
||||||
let push_stream_id = peer_conn.stream_create(StreamType::UniDi).unwrap();
|
let push_stream_id = peer_conn.stream_create(StreamType::UniDi).unwrap();
|
||||||
_ = peer_conn.stream_send(push_stream_id, &[0x1]).unwrap();
|
_ = peer_conn.stream_send(push_stream_id, &[0x1]).unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
let out = hconn.process(out.as_dgram_ref(), now());
|
let out = hconn.process(out.dgram(), now());
|
||||||
mem::drop(peer_conn.conn.process(out.as_dgram_ref(), now()));
|
mem::drop(peer_conn.conn.process(out.dgram(), now()));
|
||||||
assert_closed(&hconn, &Error::HttpStreamCreation);
|
assert_closed(&hconn, &Error::HttpStreamCreation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,77 +756,77 @@ mod tests {
|
||||||
// send the stream type
|
// send the stream type
|
||||||
let mut sent = peer_conn.stream_send(control_stream, &[0x0]);
|
let mut sent = peer_conn.stream_send(control_stream, &[0x0]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
// start sending SETTINGS frame
|
// start sending SETTINGS frame
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x4]);
|
sent = peer_conn.stream_send(control_stream, &[0x4]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x4]);
|
sent = peer_conn.stream_send(control_stream, &[0x4]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x6]);
|
sent = peer_conn.stream_send(control_stream, &[0x6]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x0]);
|
sent = peer_conn.stream_send(control_stream, &[0x0]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x8]);
|
sent = peer_conn.stream_send(control_stream, &[0x8]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x0]);
|
sent = peer_conn.stream_send(control_stream, &[0x0]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
assert_not_closed(&hconn);
|
assert_not_closed(&hconn);
|
||||||
|
|
||||||
// Now test PushPromise
|
// Now test PushPromise
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x5]);
|
sent = peer_conn.stream_send(control_stream, &[0x5]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x5]);
|
sent = peer_conn.stream_send(control_stream, &[0x5]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x4]);
|
sent = peer_conn.stream_send(control_stream, &[0x4]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x61]);
|
sent = peer_conn.stream_send(control_stream, &[0x61]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x62]);
|
sent = peer_conn.stream_send(control_stream, &[0x62]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x63]);
|
sent = peer_conn.stream_send(control_stream, &[0x63]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
sent = peer_conn.stream_send(control_stream, &[0x64]);
|
sent = peer_conn.stream_send(control_stream, &[0x64]);
|
||||||
assert_eq!(sent, Ok(1));
|
assert_eq!(sent, Ok(1));
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
// PUSH_PROMISE on a control stream will cause an error
|
// PUSH_PROMISE on a control stream will cause an error
|
||||||
assert_closed(&hconn, &Error::HttpFrameUnexpected);
|
assert_closed(&hconn, &Error::HttpFrameUnexpected);
|
||||||
|
@ -836,8 +841,8 @@ mod tests {
|
||||||
peer_conn.stream_send(stream_id, res).unwrap();
|
peer_conn.stream_send(stream_id, res).unwrap();
|
||||||
peer_conn.stream_close_send(stream_id).unwrap();
|
peer_conn.stream_close_send(stream_id).unwrap();
|
||||||
|
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
assert_closed(&hconn, &Error::HttpFrame);
|
assert_closed(&hconn, &Error::HttpFrame);
|
||||||
}
|
}
|
||||||
|
@ -888,8 +893,8 @@ mod tests {
|
||||||
peer_conn.stream_send(stream_id, REQUEST_WITH_BODY).unwrap();
|
peer_conn.stream_send(stream_id, REQUEST_WITH_BODY).unwrap();
|
||||||
peer_conn.stream_close_send(stream_id).unwrap();
|
peer_conn.stream_close_send(stream_id).unwrap();
|
||||||
|
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
// Check connection event. There should be 1 Header and 2 data events.
|
// Check connection event. There should be 1 Header and 2 data events.
|
||||||
let mut headers_frames = 0;
|
let mut headers_frames = 0;
|
||||||
|
@ -935,8 +940,8 @@ mod tests {
|
||||||
.stream_send(stream_id, &REQUEST_WITH_BODY[..20])
|
.stream_send(stream_id, &REQUEST_WITH_BODY[..20])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
// Check connection event. There should be 1 Header and no data events.
|
// Check connection event. There should be 1 Header and no data events.
|
||||||
let mut headers_frames = 0;
|
let mut headers_frames = 0;
|
||||||
|
@ -972,7 +977,7 @@ mod tests {
|
||||||
| Http3ServerEvent::WebTransport(_) => {}
|
| Http3ServerEvent::WebTransport(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let out = hconn.process(None, now());
|
let out = hconn.process_output(now());
|
||||||
|
|
||||||
// Send data.
|
// Send data.
|
||||||
peer_conn
|
peer_conn
|
||||||
|
@ -980,8 +985,8 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
peer_conn.stream_close_send(stream_id).unwrap();
|
peer_conn.stream_close_send(stream_id).unwrap();
|
||||||
|
|
||||||
let out = peer_conn.process(out.as_dgram_ref(), now());
|
let out = peer_conn.process(out.dgram(), now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
while let Some(event) = hconn.next_event() {
|
while let Some(event) = hconn.next_event() {
|
||||||
match event {
|
match event {
|
||||||
|
@ -1012,8 +1017,8 @@ mod tests {
|
||||||
.stream_send(request_stream_id, &REQUEST_WITH_BODY[..20])
|
.stream_send(request_stream_id, &REQUEST_WITH_BODY[..20])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
// Check connection event. There should be 1 Header and no data events.
|
// Check connection event. There should be 1 Header and no data events.
|
||||||
// The server will reset the stream.
|
// The server will reset the stream.
|
||||||
|
@ -1043,10 +1048,10 @@ mod tests {
|
||||||
| Http3ServerEvent::WebTransport(_) => {}
|
| Http3ServerEvent::WebTransport(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let out = hconn.process(None, now());
|
let out = hconn.process_output(now());
|
||||||
|
|
||||||
let out = peer_conn.process(out.as_dgram_ref(), now());
|
let out = peer_conn.process(out.dgram(), now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
// Check that STOP_SENDING and REET has been received.
|
// Check that STOP_SENDING and REET has been received.
|
||||||
let mut reset = 0;
|
let mut reset = 0;
|
||||||
|
@ -1077,8 +1082,8 @@ mod tests {
|
||||||
peer_conn
|
peer_conn
|
||||||
.stream_reset_send(CLIENT_SIDE_CONTROL_STREAM_ID, Error::HttpNoError.code())
|
.stream_reset_send(CLIENT_SIDE_CONTROL_STREAM_ID, Error::HttpNoError.code())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1090,8 +1095,8 @@ mod tests {
|
||||||
peer_conn
|
peer_conn
|
||||||
.stream_reset_send(CLIENT_SIDE_ENCODER_STREAM_ID, Error::HttpNoError.code())
|
.stream_reset_send(CLIENT_SIDE_ENCODER_STREAM_ID, Error::HttpNoError.code())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1103,8 +1108,8 @@ mod tests {
|
||||||
peer_conn
|
peer_conn
|
||||||
.stream_reset_send(CLIENT_SIDE_DECODER_STREAM_ID, Error::HttpNoError.code())
|
.stream_reset_send(CLIENT_SIDE_DECODER_STREAM_ID, Error::HttpNoError.code())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1117,8 +1122,8 @@ mod tests {
|
||||||
peer_conn
|
peer_conn
|
||||||
.stream_stop_sending(SERVER_SIDE_CONTROL_STREAM_ID, Error::HttpNoError.code())
|
.stream_stop_sending(SERVER_SIDE_CONTROL_STREAM_ID, Error::HttpNoError.code())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,8 +1135,8 @@ mod tests {
|
||||||
peer_conn
|
peer_conn
|
||||||
.stream_stop_sending(SERVER_SIDE_ENCODER_STREAM_ID, Error::HttpNoError.code())
|
.stream_stop_sending(SERVER_SIDE_ENCODER_STREAM_ID, Error::HttpNoError.code())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,8 +1148,8 @@ mod tests {
|
||||||
peer_conn
|
peer_conn
|
||||||
.stream_stop_sending(SERVER_SIDE_DECODER_STREAM_ID, Error::HttpNoError.code())
|
.stream_stop_sending(SERVER_SIDE_DECODER_STREAM_ID, Error::HttpNoError.code())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1251,8 +1256,8 @@ mod tests {
|
||||||
.stream_send(request_stream_id_2, REQUEST_WITH_BODY)
|
.stream_send(request_stream_id_2, REQUEST_WITH_BODY)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let out = peer_conn.process(None, now());
|
let out = peer_conn.process_output(now());
|
||||||
hconn.process(out.as_dgram_ref(), now());
|
hconn.process(out.dgram(), now());
|
||||||
|
|
||||||
let mut requests = HashMap::new();
|
let mut requests = HashMap::new();
|
||||||
while let Some(event) = hconn.next_event() {
|
while let Some(event) = hconn.next_event() {
|
||||||
|
|
|
@ -268,8 +268,8 @@ mod tests {
|
||||||
let (mut conn_c, mut conn_s) = connect();
|
let (mut conn_c, mut conn_s) = connect();
|
||||||
// create a stream
|
// create a stream
|
||||||
let stream_id = conn_s.stream_create(stream_type).unwrap();
|
let stream_id = conn_s.stream_create(stream_type).unwrap();
|
||||||
let out = conn_s.process(None, now());
|
let out = conn_s.process_output(now());
|
||||||
mem::drop(conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(conn_c.process(out.dgram(), now()));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
conn_c,
|
conn_c,
|
||||||
|
@ -291,8 +291,8 @@ mod tests {
|
||||||
self.conn_s
|
self.conn_s
|
||||||
.stream_send(self.stream_id, &enc[i..=i])
|
.stream_send(self.stream_id, &enc[i..=i])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = self.conn_s.process(None, now());
|
let out = self.conn_s.process_output(now());
|
||||||
mem::drop(self.conn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(self.conn_c.process(out.dgram(), now()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
self.decoder.receive(&mut self.conn_c).unwrap(),
|
self.decoder.receive(&mut self.conn_c).unwrap(),
|
||||||
(ReceiveOutput::NoOutput, false)
|
(ReceiveOutput::NoOutput, false)
|
||||||
|
@ -305,8 +305,8 @@ mod tests {
|
||||||
if fin {
|
if fin {
|
||||||
self.conn_s.stream_close_send(self.stream_id).unwrap();
|
self.conn_s.stream_close_send(self.stream_id).unwrap();
|
||||||
}
|
}
|
||||||
let out = self.conn_s.process(None, now());
|
let out = self.conn_s.process_output(now());
|
||||||
mem::drop(self.conn_c.process(out.dgram().as_ref(), now()));
|
mem::drop(self.conn_c.process(out.dgram(), now()));
|
||||||
assert_eq!(&self.decoder.receive(&mut self.conn_c), outcome);
|
assert_eq!(&self.decoder.receive(&mut self.conn_c), outcome);
|
||||||
assert_eq!(self.decoder.done(), done);
|
assert_eq!(self.decoder.done(), done);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,20 +94,20 @@ fn process_client_events(conn: &mut Http3Client) {
|
||||||
|
|
||||||
fn connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option<Datagram> {
|
fn connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option<Datagram> {
|
||||||
assert_eq!(hconn_c.state(), Http3State::Initializing);
|
assert_eq!(hconn_c.state(), Http3State::Initializing);
|
||||||
let out = hconn_c.process(None, now()); // Initial
|
let out = hconn_c.process_output(now()); // Initial
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now()); // Initial + Handshake
|
let out = hconn_s.process(out.dgram(), now()); // Initial + Handshake
|
||||||
let out = hconn_c.process(out.as_dgram_ref(), now()); // ACK
|
let out = hconn_c.process(out.dgram(), now()); // ACK
|
||||||
mem::drop(hconn_s.process(out.as_dgram_ref(), now())); // consume ACK
|
mem::drop(hconn_s.process(out.dgram(), now())); // consume ACK
|
||||||
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
||||||
assert!(hconn_c.events().any(authentication_needed));
|
assert!(hconn_c.events().any(authentication_needed));
|
||||||
hconn_c.authenticated(AuthenticationStatus::Ok, now());
|
hconn_c.authenticated(AuthenticationStatus::Ok, now());
|
||||||
let out = hconn_c.process(None, now()); // Handshake
|
let out = hconn_c.process_output(now()); // Handshake
|
||||||
assert_eq!(hconn_c.state(), Http3State::Connected);
|
assert_eq!(hconn_c.state(), Http3State::Connected);
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now()); // Handshake
|
let out = hconn_s.process(out.dgram(), now()); // Handshake
|
||||||
let out = hconn_c.process(out.as_dgram_ref(), now());
|
let out = hconn_c.process(out.dgram(), now());
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now());
|
let out = hconn_s.process(out.dgram(), now());
|
||||||
// assert!(hconn_s.settings_received);
|
// assert!(hconn_s.settings_received);
|
||||||
let out = hconn_c.process(out.as_dgram_ref(), now());
|
let out = hconn_c.process(out.dgram(), now());
|
||||||
// assert!(hconn_c.settings_received);
|
// assert!(hconn_c.settings_received);
|
||||||
|
|
||||||
out.dgram()
|
out.dgram()
|
||||||
|
@ -121,28 +121,28 @@ fn connect_peers_with_network_propagation_delay(
|
||||||
let net_delay = Duration::from_millis(net_delay);
|
let net_delay = Duration::from_millis(net_delay);
|
||||||
assert_eq!(hconn_c.state(), Http3State::Initializing);
|
assert_eq!(hconn_c.state(), Http3State::Initializing);
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
let out = hconn_c.process(None, now); // Initial
|
let out = hconn_c.process_output(now); // Initial
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now); // Initial + Handshake
|
let out = hconn_s.process(out.dgram(), now); // Initial + Handshake
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
let out = hconn_c.process(out.as_dgram_ref(), now); // ACK
|
let out = hconn_c.process(out.dgram(), now); // ACK
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now); // consume ACK
|
let out = hconn_s.process(out.dgram(), now); // consume ACK
|
||||||
assert!(out.dgram().is_none());
|
assert!(out.dgram().is_none());
|
||||||
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
||||||
assert!(hconn_c.events().any(authentication_needed));
|
assert!(hconn_c.events().any(authentication_needed));
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
hconn_c.authenticated(AuthenticationStatus::Ok, now);
|
hconn_c.authenticated(AuthenticationStatus::Ok, now);
|
||||||
let out = hconn_c.process(None, now); // Handshake
|
let out = hconn_c.process_output(now); // Handshake
|
||||||
assert_eq!(hconn_c.state(), Http3State::Connected);
|
assert_eq!(hconn_c.state(), Http3State::Connected);
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now); // HANDSHAKE_DONE
|
let out = hconn_s.process(out.dgram(), now); // HANDSHAKE_DONE
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
let out = hconn_c.process(out.as_dgram_ref(), now); // Consume HANDSHAKE_DONE, send control streams.
|
let out = hconn_c.process(out.dgram(), now); // Consume HANDSHAKE_DONE, send control streams.
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now); // consume and send control streams.
|
let out = hconn_s.process(out.dgram(), now); // consume and send control streams.
|
||||||
now += net_delay;
|
now += net_delay;
|
||||||
let out = hconn_c.process(out.as_dgram_ref(), now); // consume control streams.
|
let out = hconn_c.process(out.dgram(), now); // consume control streams.
|
||||||
(out.dgram(), now)
|
(out.dgram(), now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,8 +157,8 @@ fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
|
||||||
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server, out_ex: Option<Datagram>) {
|
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server, out_ex: Option<Datagram>) {
|
||||||
let mut out = out_ex;
|
let mut out = out_ex;
|
||||||
loop {
|
loop {
|
||||||
out = client.process(out.as_ref(), now()).dgram();
|
out = client.process(out, now()).dgram();
|
||||||
out = server.process(out.as_ref(), now()).dgram();
|
out = server.process(out, now()).dgram();
|
||||||
if out.is_none() {
|
if out.is_none() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -186,17 +186,17 @@ fn fetch() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(req, 0);
|
assert_eq!(req, 0);
|
||||||
hconn_c.stream_close_send(req).unwrap();
|
hconn_c.stream_close_send(req).unwrap();
|
||||||
let out = hconn_c.process(dgram.as_ref(), now());
|
let out = hconn_c.process(dgram, now());
|
||||||
qtrace!("-----server");
|
qtrace!("-----server");
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now());
|
let out = hconn_s.process(out.dgram(), now());
|
||||||
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(hconn_c.process(out.dgram(), now()));
|
||||||
process_server_events(&hconn_s);
|
process_server_events(&hconn_s);
|
||||||
let out = hconn_s.process(None, now());
|
let out = hconn_s.process(None::<Datagram>, now());
|
||||||
|
|
||||||
qtrace!("-----client");
|
qtrace!("-----client");
|
||||||
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(hconn_c.process(out.dgram(), now()));
|
||||||
let out = hconn_s.process(None, now());
|
let out = hconn_s.process(None::<Datagram>, now());
|
||||||
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(hconn_c.process(out.dgram(), now()));
|
||||||
process_client_events(&mut hconn_c);
|
process_client_events(&mut hconn_c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,10 +215,10 @@ fn response_103() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(req, 0);
|
assert_eq!(req, 0);
|
||||||
hconn_c.stream_close_send(req).unwrap();
|
hconn_c.stream_close_send(req).unwrap();
|
||||||
let out = hconn_c.process(dgram.as_ref(), now());
|
let out = hconn_c.process(dgram, now());
|
||||||
|
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now());
|
let out = hconn_s.process(out.dgram(), now());
|
||||||
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(hconn_c.process(out.dgram(), now()));
|
||||||
let request = receive_request(&hconn_s).unwrap();
|
let request = receive_request(&hconn_s).unwrap();
|
||||||
let info_headers = [
|
let info_headers = [
|
||||||
Header::new(":status", "103"),
|
Header::new(":status", "103"),
|
||||||
|
@ -226,9 +226,9 @@ fn response_103() {
|
||||||
];
|
];
|
||||||
// Send 103
|
// Send 103
|
||||||
request.send_headers(&info_headers).unwrap();
|
request.send_headers(&info_headers).unwrap();
|
||||||
let out = hconn_s.process(None, now());
|
let out = hconn_s.process(None::<Datagram>, now());
|
||||||
|
|
||||||
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(hconn_c.process(out.dgram(), now()));
|
||||||
|
|
||||||
let info_headers_event = |e| {
|
let info_headers_event = |e| {
|
||||||
matches!(e, Http3ClientEvent::HeaderReady { headers,
|
matches!(e, Http3ClientEvent::HeaderReady { headers,
|
||||||
|
@ -238,8 +238,8 @@ fn response_103() {
|
||||||
assert!(hconn_c.events().any(info_headers_event));
|
assert!(hconn_c.events().any(info_headers_event));
|
||||||
|
|
||||||
set_response(&request);
|
set_response(&request);
|
||||||
let out = hconn_s.process(None, now());
|
let out = hconn_s.process(None::<Datagram>, now());
|
||||||
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
|
mem::drop(hconn_c.process(out.dgram(), now()));
|
||||||
process_client_events(&mut hconn_c);
|
process_client_events(&mut hconn_c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,8 +448,8 @@ fn zerortt() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
hconn_c.stream_close_send(req).unwrap();
|
hconn_c.stream_close_send(req).unwrap();
|
||||||
|
|
||||||
let out = hconn_c.process(dgram.as_ref(), now());
|
let out = hconn_c.process(dgram, now());
|
||||||
let out = hconn_s.process(out.as_dgram_ref(), now());
|
let out = hconn_s.process(out.dgram(), now());
|
||||||
|
|
||||||
let mut request_stream = None;
|
let mut request_stream = None;
|
||||||
let mut zerortt_state_change = false;
|
let mut zerortt_state_change = false;
|
||||||
|
@ -513,7 +513,7 @@ fn fetch_noresponse_will_idletimeout() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(req, 0);
|
assert_eq!(req, 0);
|
||||||
hconn_c.stream_close_send(req).unwrap();
|
hconn_c.stream_close_send(req).unwrap();
|
||||||
let _out = hconn_c.process(dgram.as_ref(), now);
|
let _out = hconn_c.process(dgram, now);
|
||||||
qtrace!("-----server");
|
qtrace!("-----server");
|
||||||
|
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
|
|
|
@ -16,9 +16,9 @@ use test_fixture::*;
|
||||||
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
let mut out = None;
|
let mut out = None;
|
||||||
loop {
|
loop {
|
||||||
out = client.process(out.as_ref(), now()).dgram();
|
out = client.process(out, now()).dgram();
|
||||||
let client_done = out.is_none();
|
let client_done = out.is_none();
|
||||||
out = server.process(out.as_ref(), now()).dgram();
|
out = server.process(out, now()).dgram();
|
||||||
if out.is_none() && client_done {
|
if out.is_none() && client_done {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -28,29 +28,29 @@ fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
// Perform only Quic transport handshake.
|
// Perform only Quic transport handshake.
|
||||||
fn connect_with(client: &mut Http3Client, server: &mut Http3Server) {
|
fn connect_with(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
assert_eq!(client.state(), Http3State::Initializing);
|
assert_eq!(client.state(), Http3State::Initializing);
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert_eq!(client.state(), Http3State::Initializing);
|
assert_eq!(client.state(), Http3State::Initializing);
|
||||||
|
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
||||||
assert!(client.events().any(authentication_needed));
|
assert!(client.events().any(authentication_needed));
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
|
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
|
let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
|
||||||
assert!(client.events().any(connected));
|
assert!(client.events().any(connected));
|
||||||
|
|
||||||
assert_eq!(client.state(), Http3State::Connected);
|
assert_eq!(client.state(), Http3State::Connected);
|
||||||
// Exchange H3 setttings
|
// Exchange H3 setttings
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
_ = server.process(out.as_dgram_ref(), now());
|
_ = server.process(out.dgram(), now());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect() -> (Http3Client, Http3Server) {
|
fn connect() -> (Http3Client, Http3Server) {
|
||||||
|
|
|
@ -29,8 +29,8 @@ fn response_header_103() -> &'static Vec<Header> {
|
||||||
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
let mut out = None;
|
let mut out = None;
|
||||||
loop {
|
loop {
|
||||||
out = client.process(out.as_ref(), now()).dgram();
|
out = client.process(out, now()).dgram();
|
||||||
out = server.process(out.as_ref(), now()).dgram();
|
out = server.process(out, now()).dgram();
|
||||||
if out.is_none() {
|
if out.is_none() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,19 +41,19 @@ fn connect() -> (Http3Client, Http3Server) {
|
||||||
)
|
)
|
||||||
.expect("create a server");
|
.expect("create a server");
|
||||||
assert_eq!(client.state(), Http3State::Initializing);
|
assert_eq!(client.state(), Http3State::Initializing);
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert_eq!(client.state(), Http3State::Initializing);
|
assert_eq!(client.state(), Http3State::Initializing);
|
||||||
|
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
|
||||||
assert!(client.events().any(authentication_needed));
|
assert!(client.events().any(authentication_needed));
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
|
|
||||||
let mut out = client.process(out.as_dgram_ref(), now()).dgram();
|
let mut out = client.process(out.dgram(), now()).dgram();
|
||||||
let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
|
let connected = |e| matches!(e, Http3ClientEvent::StateChange(Http3State::Connected));
|
||||||
assert!(client.events().any(connected));
|
assert!(client.events().any(connected));
|
||||||
|
|
||||||
|
@ -61,9 +61,9 @@ fn connect() -> (Http3Client, Http3Server) {
|
||||||
|
|
||||||
// Exchange H3 setttings
|
// Exchange H3 setttings
|
||||||
loop {
|
loop {
|
||||||
out = server.process(out.as_ref(), now()).dgram();
|
out = server.process(out, now()).dgram();
|
||||||
let dgram_present = out.is_some();
|
let dgram_present = out.is_some();
|
||||||
out = client.process(out.as_ref(), now()).dgram();
|
out = client.process(out, now()).dgram();
|
||||||
if out.is_none() && !dgram_present {
|
if out.is_none() && !dgram_present {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,8 @@ fn connect() -> (Http3Client, Http3Server) {
|
||||||
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
|
||||||
let mut out = None;
|
let mut out = None;
|
||||||
loop {
|
loop {
|
||||||
out = client.process(out.as_ref(), now()).dgram();
|
out = client.process(out, now()).dgram();
|
||||||
out = server.process(out.as_ref(), now()).dgram();
|
out = server.process(out, now()).dgram();
|
||||||
if out.is_none() {
|
if out.is_none() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"6443d8309747dcbcff3f0f8c7f3a5578e6c19fab0128afa6ff6fe9943de4e4d4","src/decoder.rs":"ed2d6fa29e8726429aabb84e65f5d8025b320c0219b442b47c38903728ba3b2d","src/decoder_instructions.rs":"addf304fbd566ca387e5111cbe25784f7f50e0112ce0372b1ad6d18185b45a02","src/encoder.rs":"9a09c2eb6476fb72e3d73937a6e1c98072910fc7f709aca13f41afed38c7dd9f","src/encoder_instructions.rs":"746569e9f90f07af1aa49ed93f48c3fa3c41f13cea5f0ae88485a78a43a59470","src/header_block.rs":"47ad4a03d7a78e6d2269f8e004a884cb1e001c272a206121f479e29b8446f824","src/huffman.rs":"6976f1b4d3e5ef849a6b080cfb2e8804bf01cfe3b9bd9e3994a319d5405cd8f3","src/huffman_decode_helper.rs":"9ce470e318b3664f58aa109bed483ab15bfd9e0b17d261ea2b609668a42a9d80","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"f9bad0fe7643c618d034c4941ebd30ad5f6015b8b87b484b0ea79681d13d8b49","src/prefix.rs":"d9ad12838d61b38dc2300948e3da01fd65371215edde1c370cf54ccd87d64d46","src/qlog.rs":"fbd96ef7d21db2bae19b8e379995544e8cf123e8e5129c1500ace2773acf5649","src/qpack_send_buf.rs":"48f8d0e011e0fb8e4bd0774279d3465e2be01fd9480eaf374ae2adada6be430d","src/reader.rs":"937e9db6ca4dd8d6f599e58bc2123f3b76b269b089b4e98e3922efd80861dd92","src/static_table.rs":"6e5ec26e2b6bd63375d2d77e72748151d430d1629a8e497ec0d0ea21c078524a","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"2d2c9e6070a1e90048a4ad7c8279f9e1ce7615b44d7d8145fb0f140e554f5ca2"},"package":null}
|
{"files":{"Cargo.toml":"b47c04269b6b2d0ee8418f407a16f8097b38694eb57b42f5a7d1eabd549a8cc4","src/decoder.rs":"5c76a8407e02999a805ecaeae0ec2743121abe1e35b75126994d52ff7deb6af7","src/decoder_instructions.rs":"addf304fbd566ca387e5111cbe25784f7f50e0112ce0372b1ad6d18185b45a02","src/encoder.rs":"55729ecca0360faa07a2fa0ab11dd2bc26137548e9a499b14d540bcee22b7378","src/encoder_instructions.rs":"746569e9f90f07af1aa49ed93f48c3fa3c41f13cea5f0ae88485a78a43a59470","src/header_block.rs":"47ad4a03d7a78e6d2269f8e004a884cb1e001c272a206121f479e29b8446f824","src/huffman.rs":"6976f1b4d3e5ef849a6b080cfb2e8804bf01cfe3b9bd9e3994a319d5405cd8f3","src/huffman_decode_helper.rs":"9ce470e318b3664f58aa109bed483ab15bfd9e0b17d261ea2b609668a42a9d80","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"f9bad0fe7643c618d034c4941ebd30ad5f6015b8b87b484b0ea79681d13d8b49","src/prefix.rs":"d9ad12838d61b38dc2300948e3da01fd65371215edde1c370cf54ccd87d64d46","src/qlog.rs":"fbd96ef7d21db2bae19b8e379995544e8cf123e8e5129c1500ace2773acf5649","src/qpack_send_buf.rs":"48f8d0e011e0fb8e4bd0774279d3465e2be01fd9480eaf374ae2adada6be430d","src/reader.rs":"937e9db6ca4dd8d6f599e58bc2123f3b76b269b089b4e98e3922efd80861dd92","src/static_table.rs":"6e5ec26e2b6bd63375d2d77e72748151d430d1629a8e497ec0d0ea21c078524a","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"2d2c9e6070a1e90048a4ad7c8279f9e1ce7615b44d7d8145fb0f140e554f5ca2"},"package":null}
|
|
@ -13,7 +13,7 @@
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
name = "neqo-qpack"
|
name = "neqo-qpack"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
||||||
build = false
|
build = false
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
|
@ -333,8 +333,8 @@ mod tests {
|
||||||
.peer_conn
|
.peer_conn
|
||||||
.stream_send(decoder.recv_stream_id, encoder_instruction)
|
.stream_send(decoder.recv_stream_id, encoder_instruction)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = decoder.peer_conn.process(None, now());
|
let out = decoder.peer_conn.process_output(now());
|
||||||
mem::drop(decoder.conn.process(out.as_dgram_ref(), now()));
|
mem::drop(decoder.conn.process(out.dgram(), now()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
decoder
|
decoder
|
||||||
.decoder
|
.decoder
|
||||||
|
@ -345,8 +345,8 @@ mod tests {
|
||||||
|
|
||||||
fn send_instructions_and_check(decoder: &mut TestDecoder, decoder_instruction: &[u8]) {
|
fn send_instructions_and_check(decoder: &mut TestDecoder, decoder_instruction: &[u8]) {
|
||||||
decoder.decoder.send(&mut decoder.conn).unwrap();
|
decoder.decoder.send(&mut decoder.conn).unwrap();
|
||||||
let out = decoder.conn.process(None, now());
|
let out = decoder.conn.process_output(now());
|
||||||
mem::drop(decoder.peer_conn.process(out.as_dgram_ref(), now()));
|
mem::drop(decoder.peer_conn.process(out.dgram(), now()));
|
||||||
let mut buf = [0_u8; 100];
|
let mut buf = [0_u8; 100];
|
||||||
let (amount, fin) = decoder
|
let (amount, fin) = decoder
|
||||||
.peer_conn
|
.peer_conn
|
||||||
|
|
|
@ -572,9 +572,9 @@ mod tests {
|
||||||
|
|
||||||
pub fn send_instructions(&mut self, encoder_instruction: &[u8]) {
|
pub fn send_instructions(&mut self, encoder_instruction: &[u8]) {
|
||||||
self.encoder.send_encoder_updates(&mut self.conn).unwrap();
|
self.encoder.send_encoder_updates(&mut self.conn).unwrap();
|
||||||
let out = self.conn.process(None, now());
|
let out = self.conn.process_output(now());
|
||||||
let out2 = self.peer_conn.process(out.as_dgram_ref(), now());
|
let out2 = self.peer_conn.process(out.dgram(), now());
|
||||||
mem::drop(self.conn.process(out2.as_dgram_ref(), now()));
|
mem::drop(self.conn.process(out2.dgram(), now()));
|
||||||
let mut buf = [0_u8; 100];
|
let mut buf = [0_u8; 100];
|
||||||
let (amount, fin) = self
|
let (amount, fin) = self
|
||||||
.peer_conn
|
.peer_conn
|
||||||
|
@ -635,8 +635,8 @@ mod tests {
|
||||||
.peer_conn
|
.peer_conn
|
||||||
.stream_send(encoder.recv_stream_id, decoder_instruction)
|
.stream_send(encoder.recv_stream_id, decoder_instruction)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = encoder.peer_conn.process(None, now());
|
let out = encoder.peer_conn.process_output(now());
|
||||||
mem::drop(encoder.conn.process(out.as_dgram_ref(), now()));
|
mem::drop(encoder.conn.process(out.dgram(), now()));
|
||||||
assert!(encoder
|
assert!(encoder
|
||||||
.encoder
|
.encoder
|
||||||
.read_instructions(&mut encoder.conn, encoder.recv_stream_id)
|
.read_instructions(&mut encoder.conn, encoder.recv_stream_id)
|
||||||
|
@ -1563,8 +1563,8 @@ mod tests {
|
||||||
encoder.send_instructions(ONE_INSTRUCTION_1);
|
encoder.send_instructions(ONE_INSTRUCTION_1);
|
||||||
|
|
||||||
// exchange a flow control update.
|
// exchange a flow control update.
|
||||||
let out = encoder.peer_conn.process(None, now());
|
let out = encoder.peer_conn.process_output(now());
|
||||||
mem::drop(encoder.conn.process(out.as_dgram_ref(), now()));
|
mem::drop(encoder.conn.process(out.dgram(), now()));
|
||||||
|
|
||||||
// Try writing a new header block. Now, headers will be added to the dynamic table again,
|
// Try writing a new header block. Now, headers will be added to the dynamic table again,
|
||||||
// because instructions can be sent.
|
// because instructions can be sent.
|
||||||
|
@ -1610,8 +1610,8 @@ mod tests {
|
||||||
.encoder
|
.encoder
|
||||||
.send_encoder_updates(&mut encoder.conn)
|
.send_encoder_updates(&mut encoder.conn)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = encoder.conn.process(None, now());
|
let out = encoder.conn.process_output(now());
|
||||||
mem::drop(encoder.peer_conn.process(out.as_dgram_ref(), now()));
|
mem::drop(encoder.peer_conn.process(out.dgram(), now()));
|
||||||
// receive an insert count increment.
|
// receive an insert count increment.
|
||||||
recv_instruction(&mut encoder, &[0x01]);
|
recv_instruction(&mut encoder, &[0x01]);
|
||||||
|
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -13,7 +13,7 @@
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
name = "neqo-transport"
|
name = "neqo-transport"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
|
@ -13,7 +13,7 @@ use test_fixture::{
|
||||||
sim::{
|
sim::{
|
||||||
connection::{ConnectionNode, ReachState, ReceiveData, SendData},
|
connection::{ConnectionNode, ReachState, ReceiveData, SendData},
|
||||||
network::{Delay, TailDrop},
|
network::{Delay, TailDrop},
|
||||||
Simulator,
|
ReadySimulator, Simulator,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ const ZERO: Duration = Duration::from_millis(0);
|
||||||
const JITTER: Duration = Duration::from_millis(10);
|
const JITTER: Duration = Duration::from_millis(10);
|
||||||
const TRANSFER_AMOUNT: usize = 1 << 22; // 4Mbyte
|
const TRANSFER_AMOUNT: usize = 1 << 22; // 4Mbyte
|
||||||
|
|
||||||
fn benchmark_transfer(c: &mut Criterion, label: &str, seed: &Option<impl AsRef<str>>) {
|
#[allow(clippy::needless_pass_by_value)] // Passing String where &str would do is fine here.
|
||||||
|
fn benchmark_transfer(c: &mut Criterion, label: &str, seed: Option<impl AsRef<str>>) {
|
||||||
for pacing in [false, true] {
|
for pacing in [false, true] {
|
||||||
let mut group = c.benchmark_group(format!("transfer/pacing-{pacing}"));
|
let mut group = c.benchmark_group(format!("transfer/pacing-{pacing}"));
|
||||||
// Don't let criterion calculate throughput, as that's based on wall-clock time, not
|
// Don't let criterion calculate throughput, as that's based on wall-clock time, not
|
||||||
|
@ -52,9 +53,7 @@ fn benchmark_transfer(c: &mut Criterion, label: &str, seed: &Option<impl AsRef<s
|
||||||
}
|
}
|
||||||
sim.setup()
|
sim.setup()
|
||||||
},
|
},
|
||||||
|sim| {
|
ReadySimulator::run,
|
||||||
sim.run();
|
|
||||||
},
|
|
||||||
SmallInput,
|
SmallInput,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -63,14 +62,14 @@ fn benchmark_transfer(c: &mut Criterion, label: &str, seed: &Option<impl AsRef<s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn benchmark_transfer_variable(c: &mut Criterion) {
|
fn benchmark_transfer_variable(c: &mut Criterion) {
|
||||||
benchmark_transfer(c, "varying-seeds", &std::env::var("SIMULATION_SEED").ok());
|
benchmark_transfer(c, "varying-seeds", std::env::var("SIMULATION_SEED").ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn benchmark_transfer_fixed(c: &mut Criterion) {
|
fn benchmark_transfer_fixed(c: &mut Criterion) {
|
||||||
benchmark_transfer(
|
benchmark_transfer(
|
||||||
c,
|
c,
|
||||||
"same-seed",
|
"same-seed",
|
||||||
&Some("62df6933ba1f543cece01db8f27fb2025529b27f93df39e19f006e1db3b8c843"),
|
Some("62df6933ba1f543cece01db8f27fb2025529b27f93df39e19f006e1db3b8c843"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1022,15 +1022,16 @@ impl Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process new input datagrams on the connection.
|
/// Process new input datagrams on the connection.
|
||||||
pub fn process_input(&mut self, d: &Datagram, now: Instant) {
|
pub fn process_input(&mut self, d: Datagram<impl AsRef<[u8]>>, now: Instant) {
|
||||||
self.process_multiple_input(iter::once(d), now);
|
self.process_multiple_input(iter::once(d), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process new input datagrams on the connection.
|
/// Process new input datagrams on the connection.
|
||||||
pub fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
|
pub fn process_multiple_input(
|
||||||
where
|
&mut self,
|
||||||
I: IntoIterator<Item = &'a Datagram>,
|
dgrams: impl IntoIterator<Item = Datagram<impl AsRef<[u8]>>>,
|
||||||
{
|
now: Instant,
|
||||||
|
) {
|
||||||
let mut dgrams = dgrams.into_iter().peekable();
|
let mut dgrams = dgrams.into_iter().peekable();
|
||||||
if dgrams.peek().is_none() {
|
if dgrams.peek().is_none() {
|
||||||
return;
|
return;
|
||||||
|
@ -1161,7 +1162,7 @@ impl Connection {
|
||||||
|
|
||||||
/// Process input and generate output.
|
/// Process input and generate output.
|
||||||
#[must_use = "Output of the process function must be handled"]
|
#[must_use = "Output of the process function must be handled"]
|
||||||
pub fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output {
|
pub fn process(&mut self, dgram: Option<Datagram<impl AsRef<[u8]>>>, now: Instant) -> Output {
|
||||||
if let Some(d) = dgram {
|
if let Some(d) = dgram {
|
||||||
self.input(d, now, now);
|
self.input(d, now, now);
|
||||||
self.process_saved(now);
|
self.process_saved(now);
|
||||||
|
@ -1241,20 +1242,20 @@ impl Connection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_stateless_reset(&self, path: &PathRef, d: &Datagram) -> bool {
|
fn is_stateless_reset(&self, path: &PathRef, d: &Datagram<impl AsRef<[u8]>>) -> bool {
|
||||||
// If the datagram is too small, don't try.
|
// If the datagram is too small, don't try.
|
||||||
// If the connection is connected, then the reset token will be invalid.
|
// If the connection is connected, then the reset token will be invalid.
|
||||||
if d.len() < 16 || !self.state.connected() {
|
if d.len() < 16 || !self.state.connected() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
<&[u8; 16]>::try_from(&d[d.len() - 16..])
|
<&[u8; 16]>::try_from(&d.as_ref()[d.len() - 16..])
|
||||||
.map_or(false, |token| path.borrow().is_stateless_reset(token))
|
.map_or(false, |token| path.borrow().is_stateless_reset(token))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_stateless_reset(
|
fn check_stateless_reset(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &PathRef,
|
path: &PathRef,
|
||||||
d: &Datagram,
|
d: &Datagram<impl AsRef<[u8]>>,
|
||||||
first: bool,
|
first: bool,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
) -> Res<()> {
|
) -> Res<()> {
|
||||||
|
@ -1280,24 +1281,27 @@ impl Connection {
|
||||||
debug_assert!(self.crypto.states.rx_hp(self.version, cspace).is_some());
|
debug_assert!(self.crypto.states.rx_hp(self.version, cspace).is_some());
|
||||||
for saved in self.saved_datagrams.take_saved() {
|
for saved in self.saved_datagrams.take_saved() {
|
||||||
qtrace!([self], "input saved @{:?}: {:?}", saved.t, saved.d);
|
qtrace!([self], "input saved @{:?}: {:?}", saved.t, saved.d);
|
||||||
self.input(&saved.d, saved.t, now);
|
self.input(saved.d, saved.t, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In case a datagram arrives that we can only partially process, save any
|
/// In case a datagram arrives that we can only partially process, save any
|
||||||
/// part that we don't have keys for.
|
/// part that we don't have keys for.
|
||||||
fn save_datagram(&mut self, cspace: CryptoSpace, d: &Datagram, remaining: usize, now: Instant) {
|
#[allow(clippy::needless_pass_by_value)] // To consume an owned datagram below.
|
||||||
let d = if remaining < d.len() {
|
fn save_datagram(
|
||||||
Datagram::new(
|
&mut self,
|
||||||
d.source(),
|
cspace: CryptoSpace,
|
||||||
d.destination(),
|
d: Datagram<impl AsRef<[u8]>>,
|
||||||
d.tos(),
|
remaining: usize,
|
||||||
&d[d.len() - remaining..],
|
now: Instant,
|
||||||
)
|
) {
|
||||||
} else {
|
let d = Datagram::new(
|
||||||
d.clone()
|
d.source(),
|
||||||
};
|
d.destination(),
|
||||||
|
d.tos(),
|
||||||
|
d[d.len() - remaining..].to_vec(),
|
||||||
|
);
|
||||||
self.saved_datagrams.save(cspace, d, now);
|
self.saved_datagrams.save(cspace, d, now);
|
||||||
self.stats.borrow_mut().saved_datagrams += 1;
|
self.stats.borrow_mut().saved_datagrams += 1;
|
||||||
}
|
}
|
||||||
|
@ -1498,7 +1502,7 @@ impl Connection {
|
||||||
fn postprocess_packet(
|
fn postprocess_packet(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &PathRef,
|
path: &PathRef,
|
||||||
d: &Datagram,
|
d: &Datagram<impl AsRef<[u8]>>,
|
||||||
packet: &PublicPacket,
|
packet: &PublicPacket,
|
||||||
migrate: bool,
|
migrate: bool,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
|
@ -1530,7 +1534,7 @@ impl Connection {
|
||||||
|
|
||||||
/// Take a datagram as input. This reports an error if the packet was bad.
|
/// Take a datagram as input. This reports an error if the packet was bad.
|
||||||
/// This takes two times: when the datagram was received, and the current time.
|
/// This takes two times: when the datagram was received, and the current time.
|
||||||
fn input(&mut self, d: &Datagram, received: Instant, now: Instant) {
|
fn input(&mut self, d: Datagram<impl AsRef<[u8]>>, received: Instant, now: Instant) {
|
||||||
// First determine the path.
|
// First determine the path.
|
||||||
let path = self.paths.find_path_with_rebinding(
|
let path = self.paths.find_path_with_rebinding(
|
||||||
d.destination(),
|
d.destination(),
|
||||||
|
@ -1544,11 +1548,16 @@ impl Connection {
|
||||||
self.capture_error(Some(path), now, 0, res).ok();
|
self.capture_error(Some(path), now, 0, res).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_path(&mut self, path: &PathRef, d: &Datagram, now: Instant) -> Res<()> {
|
fn input_path(
|
||||||
let mut slc = &d[..];
|
&mut self,
|
||||||
|
path: &PathRef,
|
||||||
|
d: Datagram<impl AsRef<[u8]>>,
|
||||||
|
now: Instant,
|
||||||
|
) -> Res<()> {
|
||||||
|
let mut slc = d.as_ref();
|
||||||
let mut dcid = None;
|
let mut dcid = None;
|
||||||
|
|
||||||
qtrace!([self], "{} input {}", path.borrow(), hex(&**d));
|
qtrace!([self], "{} input {}", path.borrow(), hex(&d));
|
||||||
let pto = path.borrow().rtt().pto(self.confirmed());
|
let pto = path.borrow().rtt().pto(self.confirmed());
|
||||||
|
|
||||||
// Handle each packet in the datagram.
|
// Handle each packet in the datagram.
|
||||||
|
@ -1606,7 +1615,7 @@ impl Connection {
|
||||||
} else {
|
} else {
|
||||||
match self.process_packet(path, &payload, now) {
|
match self.process_packet(path, &payload, now) {
|
||||||
Ok(migrate) => {
|
Ok(migrate) => {
|
||||||
self.postprocess_packet(path, d, &packet, migrate, now);
|
self.postprocess_packet(path, &d, &packet, migrate, now);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.ensure_error_path(path, &packet, now);
|
self.ensure_error_path(path, &packet, now);
|
||||||
|
@ -1648,7 +1657,7 @@ impl Connection {
|
||||||
// Decryption failure, or not having keys is not fatal.
|
// Decryption failure, or not having keys is not fatal.
|
||||||
// If the state isn't available, or we can't decrypt the packet, drop
|
// If the state isn't available, or we can't decrypt the packet, drop
|
||||||
// the rest of the datagram on the floor, but don't generate an error.
|
// the rest of the datagram on the floor, but don't generate an error.
|
||||||
self.check_stateless_reset(path, d, dcid.is_none(), now)?;
|
self.check_stateless_reset(path, &d, dcid.is_none(), now)?;
|
||||||
self.stats.borrow_mut().pkt_dropped("Decryption failure");
|
self.stats.borrow_mut().pkt_dropped("Decryption failure");
|
||||||
qlog::packet_dropped(&self.qlog, &packet);
|
qlog::packet_dropped(&self.qlog, &packet);
|
||||||
}
|
}
|
||||||
|
@ -1656,7 +1665,7 @@ impl Connection {
|
||||||
slc = remainder;
|
slc = remainder;
|
||||||
dcid = Some(ConnectionId::from(packet.dcid()));
|
dcid = Some(ConnectionId::from(packet.dcid()));
|
||||||
}
|
}
|
||||||
self.check_stateless_reset(path, d, dcid.is_none(), now)?;
|
self.check_stateless_reset(path, &d, dcid.is_none(), now)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1958,7 +1967,13 @@ impl Connection {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_migration(&mut self, path: &PathRef, d: &Datagram, migrate: bool, now: Instant) {
|
fn handle_migration(
|
||||||
|
&mut self,
|
||||||
|
path: &PathRef,
|
||||||
|
d: &Datagram<impl AsRef<[u8]>>,
|
||||||
|
migrate: bool,
|
||||||
|
now: Instant,
|
||||||
|
) {
|
||||||
if !migrate {
|
if !migrate {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use super::{
|
||||||
ack_bytes, connect_rtt_idle, default_client, default_server, fill_cwnd, increase_cwnd,
|
ack_bytes, connect_rtt_idle, default_client, default_server, fill_cwnd, increase_cwnd,
|
||||||
induce_persistent_congestion, new_client, new_server, send_something, DEFAULT_RTT,
|
induce_persistent_congestion, new_client, new_server, send_something, DEFAULT_RTT,
|
||||||
};
|
};
|
||||||
use crate::stream_id::StreamType;
|
use crate::{connection::tests::assert_path_challenge_min_len, stream_id::StreamType};
|
||||||
|
|
||||||
/// With the default RTT here (100ms) and default ratio (4), endpoints won't send
|
/// With the default RTT here (100ms) and default ratio (4), endpoints won't send
|
||||||
/// `ACK_FREQUENCY` as the ACK delay isn't different enough from the default.
|
/// `ACK_FREQUENCY` as the ACK delay isn't different enough from the default.
|
||||||
|
@ -72,7 +72,7 @@ fn ack_rate_exit_slow_start() {
|
||||||
// and to send ACK_FREQUENCY.
|
// and to send ACK_FREQUENCY.
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
assert_eq!(client.stats().frame_tx.ack_frequency, 0);
|
assert_eq!(client.stats().frame_tx.ack_frequency, 0);
|
||||||
let af = client.process(Some(&ack), now).dgram();
|
let af = client.process(Some(ack), now).dgram();
|
||||||
assert!(af.is_some());
|
assert!(af.is_some());
|
||||||
assert_eq!(client.stats().frame_tx.ack_frequency, 1);
|
assert_eq!(client.stats().frame_tx.ack_frequency, 1);
|
||||||
}
|
}
|
||||||
|
@ -121,11 +121,11 @@ fn ack_rate_client_one_rtt() {
|
||||||
// The first packet will elicit an immediate ACK however, so do this twice.
|
// The first packet will elicit an immediate ACK however, so do this twice.
|
||||||
let d = send_something(&mut client, now);
|
let d = send_something(&mut client, now);
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let ack = server.process(Some(&d), now).dgram();
|
let ack = server.process(Some(d), now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
let d = send_something(&mut client, now);
|
let d = send_something(&mut client, now);
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let delay = server.process(Some(&d), now).callback();
|
let delay = server.process(Some(d), now).callback();
|
||||||
assert_eq!(delay, RTT);
|
assert_eq!(delay, RTT);
|
||||||
|
|
||||||
assert_eq!(client.stats().frame_tx.ack_frequency, 1);
|
assert_eq!(client.stats().frame_tx.ack_frequency, 1);
|
||||||
|
@ -144,11 +144,11 @@ fn ack_rate_server_half_rtt() {
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
// The client now will acknowledge immediately because it has been more than
|
// The client now will acknowledge immediately because it has been more than
|
||||||
// an RTT since it last sent an acknowledgment.
|
// an RTT since it last sent an acknowledgment.
|
||||||
let ack = client.process(Some(&d), now);
|
let ack = client.process(Some(d), now);
|
||||||
assert!(ack.as_dgram_ref().is_some());
|
assert!(ack.as_dgram_ref().is_some());
|
||||||
let d = send_something(&mut server, now);
|
let d = send_something(&mut server, now);
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let delay = client.process(Some(&d), now).callback();
|
let delay = client.process(Some(d), now).callback();
|
||||||
assert_eq!(delay, RTT / 2);
|
assert_eq!(delay, RTT / 2);
|
||||||
|
|
||||||
assert_eq!(server.stats().frame_tx.ack_frequency, 1);
|
assert_eq!(server.stats().frame_tx.ack_frequency, 1);
|
||||||
|
@ -169,10 +169,11 @@ fn migrate_ack_delay() {
|
||||||
|
|
||||||
let client1 = send_something(&mut client, now);
|
let client1 = send_something(&mut client, now);
|
||||||
assertions::assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
|
assertions::assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &client1, now);
|
||||||
let client2 = send_something(&mut client, now);
|
let client2 = send_something(&mut client, now);
|
||||||
assertions::assert_v4_path(&client2, false); // Doesn't. Is dropped.
|
assertions::assert_v4_path(&client2, false); // Doesn't. Is dropped.
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
server.process_input(&client1, now);
|
server.process_input(client1, now);
|
||||||
|
|
||||||
let stream = client.stream_create(StreamType::UniDi).unwrap();
|
let stream = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
let now = increase_cwnd(&mut client, &mut server, stream, now);
|
let now = increase_cwnd(&mut client, &mut server, stream, now);
|
||||||
|
@ -188,7 +189,7 @@ fn migrate_ack_delay() {
|
||||||
// After noticing this new loss, the client sends ACK_FREQUENCY.
|
// After noticing this new loss, the client sends ACK_FREQUENCY.
|
||||||
// It has sent a few before (as we dropped `client2`), so ignore those.
|
// It has sent a few before (as we dropped `client2`), so ignore those.
|
||||||
let ad_before = client.stats().frame_tx.ack_frequency;
|
let ad_before = client.stats().frame_tx.ack_frequency;
|
||||||
let af = client.process(Some(&ack), now).dgram();
|
let af = client.process(Some(ack), now).dgram();
|
||||||
assert!(af.is_some());
|
assert!(af.is_some());
|
||||||
assert_eq!(client.stats().frame_tx.ack_frequency, ad_before + 1);
|
assert_eq!(client.stats().frame_tx.ack_frequency, ad_before + 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ fn cc_slow_start_pmtud() {
|
||||||
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
let cwnd = cwnd_avail(&client);
|
let cwnd = cwnd_avail(&client);
|
||||||
let (dgrams, _) = fill_cwnd(&mut client, stream_id, now);
|
let (dgrams, _) = fill_cwnd(&mut client, stream_id, now);
|
||||||
let dgrams_len = dgrams.iter().map(|d| d.len()).sum::<usize>();
|
let dgrams_len = dgrams.iter().map(Datagram::len).sum::<usize>();
|
||||||
assert_eq!(dgrams_len, cwnd);
|
assert_eq!(dgrams_len, cwnd);
|
||||||
assert!(cwnd_avail(&client) < ACK_ONLY_SIZE_LIMIT);
|
assert!(cwnd_avail(&client) < ACK_ONLY_SIZE_LIMIT);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ fn cc_slow_start_to_cong_avoidance_recovery_period(congestion_signal: Congestion
|
||||||
|
|
||||||
// Client: Process ack
|
// Client: Process ack
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client.stats().frame_rx.largest_acknowledged,
|
client.stats().frame_rx.largest_acknowledged,
|
||||||
flight1_largest
|
flight1_largest
|
||||||
|
@ -117,7 +117,7 @@ fn cc_slow_start_to_cong_avoidance_recovery_period(congestion_signal: Congestion
|
||||||
|
|
||||||
// Client: Process ack
|
// Client: Process ack
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client.stats().frame_rx.largest_acknowledged,
|
client.stats().frame_rx.largest_acknowledged,
|
||||||
flight2_largest
|
flight2_largest
|
||||||
|
@ -160,7 +160,7 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
|
||||||
|
|
||||||
// Server: Receive and generate ack
|
// Server: Receive and generate ack
|
||||||
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
|
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
|
|
||||||
let cwnd1 = cwnd(&client);
|
let cwnd1 = cwnd(&client);
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
|
||||||
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams2, now);
|
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams2, now);
|
||||||
|
|
||||||
// ACK more packets but they were sent before end of recovery period
|
// ACK more packets but they were sent before end of recovery period
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
|
|
||||||
// cwnd should not have changed since ACKed packets were sent before
|
// cwnd should not have changed since ACKed packets were sent before
|
||||||
// recovery period expired
|
// recovery period expired
|
||||||
|
@ -198,12 +198,12 @@ fn single_packet_on_recovery() {
|
||||||
|
|
||||||
// Acknowledge just one packet and cause one packet to be declared lost.
|
// Acknowledge just one packet and cause one packet to be declared lost.
|
||||||
// The length is the amount of credit the client should have.
|
// The length is the amount of credit the client should have.
|
||||||
let ack = server.process(Some(&delivered), now).dgram();
|
let ack = server.process(Some(delivered), now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
|
|
||||||
// The client should see the loss and enter recovery.
|
// The client should see the loss and enter recovery.
|
||||||
// As there are many outstanding packets, there should be no available cwnd.
|
// As there are many outstanding packets, there should be no available cwnd.
|
||||||
client.process_input(&ack.unwrap(), now);
|
client.process_input(ack.unwrap(), now);
|
||||||
assert_eq!(cwnd_avail(&client), 0);
|
assert_eq!(cwnd_avail(&client), 0);
|
||||||
|
|
||||||
// The client should send one packet, ignoring the cwnd.
|
// The client should send one packet, ignoring the cwnd.
|
||||||
|
@ -235,7 +235,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||||
|
|
||||||
// Client: Process ack
|
// Client: Process ack
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
|
|
||||||
// Should be in CARP now.
|
// Should be in CARP now.
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
|
@ -251,7 +251,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
qinfo!("iteration {}", i);
|
qinfo!("iteration {}", i);
|
||||||
|
|
||||||
let c_tx_size: usize = c_tx_dgrams.iter().map(|d| d.len()).sum();
|
let c_tx_size: usize = c_tx_dgrams.iter().map(Datagram::len).sum();
|
||||||
qinfo!(
|
qinfo!(
|
||||||
"client sending {} bytes into cwnd of {}",
|
"client sending {} bytes into cwnd of {}",
|
||||||
c_tx_size,
|
c_tx_size,
|
||||||
|
@ -269,7 +269,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||||
let most = c_tx_dgrams.len() - usize::try_from(DEFAULT_ACK_PACKET_TOLERANCE).unwrap() - 1;
|
let most = c_tx_dgrams.len() - usize::try_from(DEFAULT_ACK_PACKET_TOLERANCE).unwrap() - 1;
|
||||||
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams.drain(..most), now);
|
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams.drain(..most), now);
|
||||||
assert_eq!(cwnd(&client), expected_cwnd);
|
assert_eq!(cwnd(&client), expected_cwnd);
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
// make sure to fill cwnd again.
|
// make sure to fill cwnd again.
|
||||||
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
|
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
|
||||||
now = next_now;
|
now = next_now;
|
||||||
|
@ -277,7 +277,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
|
||||||
|
|
||||||
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
|
let s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams, now);
|
||||||
assert_eq!(cwnd(&client), expected_cwnd);
|
assert_eq!(cwnd(&client), expected_cwnd);
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
// make sure to fill cwnd again.
|
// make sure to fill cwnd again.
|
||||||
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
|
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
|
||||||
now = next_now;
|
now = next_now;
|
||||||
|
@ -329,7 +329,7 @@ fn cc_slow_start_to_persistent_congestion_some_acks() {
|
||||||
let s_ack = ack_bytes(&mut server, stream, c_tx_dgrams, now);
|
let s_ack = ack_bytes(&mut server, stream, c_tx_dgrams, now);
|
||||||
|
|
||||||
now += Duration::from_millis(100);
|
now += Duration::from_millis(100);
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
|
|
||||||
// send bytes that will be lost
|
// send bytes that will be lost
|
||||||
let (_, next_now) = fill_cwnd(&mut client, stream, now);
|
let (_, next_now) = fill_cwnd(&mut client, stream, now);
|
||||||
|
@ -375,7 +375,7 @@ fn cc_persistent_congestion_to_slow_start() {
|
||||||
|
|
||||||
// No longer in CARP. (pkts acked from after start of CARP)
|
// No longer in CARP. (pkts acked from after start of CARP)
|
||||||
// Should be in slow start now.
|
// Should be in slow start now.
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
|
|
||||||
// ACKing 2 packets should let client send 4.
|
// ACKing 2 packets should let client send 4.
|
||||||
let (c_tx_dgrams, _) = fill_cwnd(&mut client, stream, now);
|
let (c_tx_dgrams, _) = fill_cwnd(&mut client, stream, now);
|
||||||
|
@ -402,22 +402,22 @@ fn ack_are_not_cc() {
|
||||||
let other_stream = server.stream_create(StreamType::BiDi).unwrap();
|
let other_stream = server.stream_create(StreamType::BiDi).unwrap();
|
||||||
assert_eq!(other_stream, 1);
|
assert_eq!(other_stream, 1);
|
||||||
server.stream_send(other_stream, b"dropped").unwrap();
|
server.stream_send(other_stream, b"dropped").unwrap();
|
||||||
let dropped_packet = server.process(None, now).dgram();
|
let dropped_packet = server.process_output(now).dgram();
|
||||||
assert!(dropped_packet.is_some()); // Now drop this one.
|
assert!(dropped_packet.is_some()); // Now drop this one.
|
||||||
|
|
||||||
// Now the server sends a packet that will force an ACK,
|
// Now the server sends a packet that will force an ACK,
|
||||||
// because the client will detect a gap.
|
// because the client will detect a gap.
|
||||||
server.stream_send(other_stream, b"sent").unwrap();
|
server.stream_send(other_stream, b"sent").unwrap();
|
||||||
let ack_eliciting_packet = server.process(None, now).dgram();
|
let ack_eliciting_packet = server.process_output(now).dgram();
|
||||||
assert!(ack_eliciting_packet.is_some());
|
assert!(ack_eliciting_packet.is_some());
|
||||||
|
|
||||||
// The client can ack the server packet even if cc windows is full.
|
// The client can ack the server packet even if cc windows is full.
|
||||||
qdebug!([client], "Process ack-eliciting");
|
qdebug!([client], "Process ack-eliciting");
|
||||||
let ack_pkt = client.process(ack_eliciting_packet.as_ref(), now).dgram();
|
let ack_pkt = client.process(ack_eliciting_packet, now).dgram();
|
||||||
assert!(ack_pkt.is_some());
|
assert!(ack_pkt.is_some());
|
||||||
qdebug!([server], "Handle ACK");
|
qdebug!([server], "Handle ACK");
|
||||||
let prev_ack_count = server.stats().frame_rx.ack;
|
let prev_ack_count = server.stats().frame_rx.ack;
|
||||||
server.process_input(&ack_pkt.unwrap(), now);
|
server.process_input(ack_pkt.unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.ack, prev_ack_count + 1);
|
assert_eq!(server.stats().frame_rx.ack, prev_ack_count + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn connection_close() {
|
||||||
client.close(now, 42, "");
|
client.close(now, 42, "");
|
||||||
|
|
||||||
let stats_before = client.stats().frame_tx;
|
let stats_before = client.stats().frame_tx;
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
let stats_after = client.stats().frame_tx;
|
let stats_after = client.stats().frame_tx;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stats_after.connection_close,
|
stats_after.connection_close,
|
||||||
|
@ -49,7 +49,7 @@ fn connection_close() {
|
||||||
);
|
);
|
||||||
assert_eq!(stats_after.ack, stats_before.ack + 1);
|
assert_eq!(stats_after.ack, stats_before.ack + 1);
|
||||||
|
|
||||||
server.process_input(&out.dgram().unwrap(), now);
|
server.process_input(out.dgram().unwrap(), now);
|
||||||
assert_draining(&server, &Error::PeerApplicationError(42));
|
assert_draining(&server, &Error::PeerApplicationError(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ fn connection_close_with_long_reason_string() {
|
||||||
client.close(now, 42, long_reason);
|
client.close(now, 42, long_reason);
|
||||||
|
|
||||||
let stats_before = client.stats().frame_tx;
|
let stats_before = client.stats().frame_tx;
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
let stats_after = client.stats().frame_tx;
|
let stats_after = client.stats().frame_tx;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stats_after.connection_close,
|
stats_after.connection_close,
|
||||||
|
@ -73,7 +73,7 @@ fn connection_close_with_long_reason_string() {
|
||||||
);
|
);
|
||||||
assert_eq!(stats_after.ack, stats_before.ack + 1);
|
assert_eq!(stats_after.ack, stats_before.ack + 1);
|
||||||
|
|
||||||
server.process_input(&out.dgram().unwrap(), now);
|
server.process_input(out.dgram().unwrap(), now);
|
||||||
assert_draining(&server, &Error::PeerApplicationError(42));
|
assert_draining(&server, &Error::PeerApplicationError(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,17 +84,17 @@ fn early_application_close() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
// One flight each.
|
// One flight each.
|
||||||
let dgram = client.process(None, now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
server.close(now(), 77, String::new());
|
server.close(now(), 77, String::new());
|
||||||
assert!(server.state().closed());
|
assert!(server.state().closed());
|
||||||
let dgram = server.process(None, now()).dgram();
|
let dgram = server.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert_draining(&client, &Error::PeerError(ERROR_APPLICATION_CLOSE));
|
assert_draining(&client, &Error::PeerError(ERROR_APPLICATION_CLOSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,15 +109,15 @@ fn bad_tls_version() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*server.state(),
|
*server.state(),
|
||||||
State::Closed(CloseReason::Transport(Error::ProtocolViolation))
|
State::Closed(CloseReason::Transport(Error::ProtocolViolation))
|
||||||
);
|
);
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert_draining(&client, &Error::PeerError(Error::ProtocolViolation.code()));
|
assert_draining(&client, &Error::PeerError(Error::ProtocolViolation.code()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,21 +134,21 @@ fn closing_timers_interation() {
|
||||||
// We're going to induce time-based loss recovery so that timer is set.
|
// We're going to induce time-based loss recovery so that timer is set.
|
||||||
let _p1 = send_something(&mut client, now);
|
let _p1 = send_something(&mut client, now);
|
||||||
let p2 = send_something(&mut client, now);
|
let p2 = send_something(&mut client, now);
|
||||||
let ack = server.process(Some(&p2), now).dgram();
|
let ack = server.process(Some(p2), now).dgram();
|
||||||
assert!(ack.is_some()); // This is an ACK.
|
assert!(ack.is_some()); // This is an ACK.
|
||||||
|
|
||||||
// After processing the ACK, we should be on the loss recovery timer.
|
// After processing the ACK, we should be on the loss recovery timer.
|
||||||
let cb = client.process(ack.as_ref(), now).callback();
|
let cb = client.process(ack, now).callback();
|
||||||
assert_ne!(cb, Duration::from_secs(0));
|
assert_ne!(cb, Duration::from_secs(0));
|
||||||
now += cb;
|
now += cb;
|
||||||
|
|
||||||
// Rather than let the timer pop, close the connection.
|
// Rather than let the timer pop, close the connection.
|
||||||
client.close(now, 0, "");
|
client.close(now, 0, "");
|
||||||
let client_close = client.process(None, now).dgram();
|
let client_close = client.process_output(now).dgram();
|
||||||
assert!(client_close.is_some());
|
assert!(client_close.is_some());
|
||||||
// This should now report the end of the closing period, not a
|
// This should now report the end of the closing period, not a
|
||||||
// zero-duration wait driven by the (now defunct) loss recovery timer.
|
// zero-duration wait driven by the (now defunct) loss recovery timer.
|
||||||
let client_close_timer = client.process(None, now).callback();
|
let client_close_timer = client.process_output(now).callback();
|
||||||
assert_ne!(client_close_timer, Duration::from_secs(0));
|
assert_ne!(client_close_timer, Duration::from_secs(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,20 +164,20 @@ fn closing_and_draining() {
|
||||||
|
|
||||||
// Close the connection.
|
// Close the connection.
|
||||||
client.close(now(), APP_ERROR, "");
|
client.close(now(), APP_ERROR, "");
|
||||||
let client_close = client.process(None, now()).dgram();
|
let client_close = client.process_output(now()).dgram();
|
||||||
assert!(client_close.is_some());
|
assert!(client_close.is_some());
|
||||||
let client_close_timer = client.process(None, now()).callback();
|
let client_close_timer = client.process_output(now()).callback();
|
||||||
assert_ne!(client_close_timer, Duration::from_secs(0));
|
assert_ne!(client_close_timer, Duration::from_secs(0));
|
||||||
// The client will spit out the same packet in response to anything it receives.
|
// The client will spit out the same packet in response to anything it receives.
|
||||||
let p3 = send_something(&mut server, now());
|
let p3 = send_something(&mut server, now());
|
||||||
let client_close2 = client.process(Some(&p3), now()).dgram();
|
let client_close2 = client.process(Some(p3), now()).dgram();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client_close.as_ref().unwrap().len(),
|
client_close.as_ref().unwrap().len(),
|
||||||
client_close2.as_ref().unwrap().len()
|
client_close2.as_ref().unwrap().len()
|
||||||
);
|
);
|
||||||
|
|
||||||
// After this time, the client should transition to closed.
|
// After this time, the client should transition to closed.
|
||||||
let end = client.process(None, now() + client_close_timer);
|
let end = client.process_output(now() + client_close_timer);
|
||||||
assert_eq!(end, Output::None);
|
assert_eq!(end, Output::None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*client.state(),
|
*client.state(),
|
||||||
|
@ -185,17 +185,17 @@ fn closing_and_draining() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// When the server receives the close, it too should generate CONNECTION_CLOSE.
|
// When the server receives the close, it too should generate CONNECTION_CLOSE.
|
||||||
let server_close = server.process(client_close.as_ref(), now()).dgram();
|
let server_close = server.process(client_close, now()).dgram();
|
||||||
assert!(server.state().closed());
|
assert!(server.state().closed());
|
||||||
assert!(server_close.is_some());
|
assert!(server_close.is_some());
|
||||||
// .. but it ignores any further close packets.
|
// .. but it ignores any further close packets.
|
||||||
let server_close_timer = server.process(client_close2.as_ref(), now()).callback();
|
let server_close_timer = server.process(client_close2, now()).callback();
|
||||||
assert_ne!(server_close_timer, Duration::from_secs(0));
|
assert_ne!(server_close_timer, Duration::from_secs(0));
|
||||||
// Even a legitimate packet without a close in it.
|
// Even a legitimate packet without a close in it.
|
||||||
let server_close_timer2 = server.process(Some(&p1), now()).callback();
|
let server_close_timer2 = server.process(Some(p1), now()).callback();
|
||||||
assert_eq!(server_close_timer, server_close_timer2);
|
assert_eq!(server_close_timer, server_close_timer2);
|
||||||
|
|
||||||
let end = server.process(None, now() + server_close_timer);
|
let end = server.process_output(now() + server_close_timer);
|
||||||
assert_eq!(end, Output::None);
|
assert_eq!(end, Output::None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*server.state(),
|
*server.state(),
|
||||||
|
@ -218,6 +218,6 @@ fn stateless_reset_client() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
connect_force_idle(&mut client, &mut server);
|
connect_force_idle(&mut client, &mut server);
|
||||||
|
|
||||||
client.process_input(&datagram(vec![77; 21]), now());
|
client.process_input(datagram(vec![77; 21]), now());
|
||||||
assert_draining(&client, &Error::StatelessReset);
|
assert_draining(&client, &Error::StatelessReset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ fn datagram_enabled_on_client() {
|
||||||
let out = server.process_output(now()).dgram().unwrap();
|
let out = server.process_output(now()).dgram().unwrap();
|
||||||
assert_eq!(server.stats().frame_tx.datagram, dgram_sent + 1);
|
assert_eq!(server.stats().frame_tx.datagram, dgram_sent + 1);
|
||||||
|
|
||||||
client.process_input(&out, now());
|
client.process_input(out, now());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
client.next_event().unwrap(),
|
client.next_event().unwrap(),
|
||||||
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU
|
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU
|
||||||
|
@ -124,7 +124,7 @@ fn datagram_enabled_on_server() {
|
||||||
let out = client.process_output(now()).dgram().unwrap();
|
let out = client.process_output(now()).dgram().unwrap();
|
||||||
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
|
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
|
||||||
|
|
||||||
server.process_input(&out, now());
|
server.process_input(out, now());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
server.next_event().unwrap(),
|
server.next_event().unwrap(),
|
||||||
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU
|
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU
|
||||||
|
@ -240,7 +240,7 @@ fn datagram_acked() {
|
||||||
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
|
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
|
||||||
|
|
||||||
let dgram_received = server.stats().frame_rx.datagram;
|
let dgram_received = server.stats().frame_rx.datagram;
|
||||||
server.process_input(&out.unwrap(), now());
|
server.process_input(out.unwrap(), now());
|
||||||
assert_eq!(server.stats().frame_rx.datagram, dgram_received + 1);
|
assert_eq!(server.stats().frame_rx.datagram, dgram_received + 1);
|
||||||
let now = now() + AT_LEAST_PTO;
|
let now = now() + AT_LEAST_PTO;
|
||||||
// Ack should be sent
|
// Ack should be sent
|
||||||
|
@ -253,7 +253,7 @@ fn datagram_acked() {
|
||||||
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU
|
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU
|
||||||
));
|
));
|
||||||
|
|
||||||
client.process_input(&out.unwrap(), now);
|
client.process_input(out.unwrap(), now);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
client.next_event().unwrap(),
|
client.next_event().unwrap(),
|
||||||
ConnectionEvent::OutgoingDatagramOutcome { id, outcome } if id == 1 && outcome == OutgoingDatagramOutcome::Acked
|
ConnectionEvent::OutgoingDatagramOutcome { id, outcome } if id == 1 && outcome == OutgoingDatagramOutcome::Acked
|
||||||
|
@ -265,7 +265,7 @@ fn send_packet_and_get_server_event(
|
||||||
server: &mut Connection,
|
server: &mut Connection,
|
||||||
) -> ConnectionEvent {
|
) -> ConnectionEvent {
|
||||||
let out = client.process_output(now()).dgram();
|
let out = client.process_output(now()).dgram();
|
||||||
server.process_input(&out.unwrap(), now());
|
server.process_input(out.unwrap(), now());
|
||||||
let mut events: Vec<_> = server
|
let mut events: Vec<_> = server
|
||||||
.events()
|
.events()
|
||||||
.filter_map(|evt| match evt {
|
.filter_map(|evt| match evt {
|
||||||
|
@ -404,7 +404,7 @@ fn dgram_no_allowed() {
|
||||||
.test_write_frames(InsertDatagram { data: DATA_MTU }, now())
|
.test_write_frames(InsertDatagram { data: DATA_MTU }, now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client.process_input(&out, now());
|
client.process_input(out, now());
|
||||||
|
|
||||||
assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation));
|
assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation));
|
||||||
}
|
}
|
||||||
|
@ -420,7 +420,7 @@ fn dgram_too_big() {
|
||||||
.test_write_frames(InsertDatagram { data: DATA_MTU }, now())
|
.test_write_frames(InsertDatagram { data: DATA_MTU }, now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client.process_input(&out, now());
|
client.process_input(out, now());
|
||||||
|
|
||||||
assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation));
|
assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation));
|
||||||
}
|
}
|
||||||
|
@ -455,7 +455,7 @@ fn outgoing_datagram_queue_full() {
|
||||||
// Send DATA_SMALLER_THAN_MTU_2 datagram
|
// Send DATA_SMALLER_THAN_MTU_2 datagram
|
||||||
let out = client.process_output(now()).dgram();
|
let out = client.process_output(now()).dgram();
|
||||||
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
|
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
|
||||||
server.process_input(&out.unwrap(), now());
|
server.process_input(out.unwrap(), now());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
server.next_event().unwrap(),
|
server.next_event().unwrap(),
|
||||||
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU_2
|
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU_2
|
||||||
|
@ -465,7 +465,7 @@ fn outgoing_datagram_queue_full() {
|
||||||
let dgram_sent2 = client.stats().frame_tx.datagram;
|
let dgram_sent2 = client.stats().frame_tx.datagram;
|
||||||
let out = client.process_output(now()).dgram();
|
let out = client.process_output(now()).dgram();
|
||||||
assert_eq!(client.stats().frame_tx.datagram, dgram_sent2 + 1);
|
assert_eq!(client.stats().frame_tx.datagram, dgram_sent2 + 1);
|
||||||
server.process_input(&out.unwrap(), now());
|
server.process_input(out.unwrap(), now());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
server.next_event().unwrap(),
|
server.next_event().unwrap(),
|
||||||
ConnectionEvent::Datagram(data) if data == DATA_MTU
|
ConnectionEvent::Datagram(data) if data == DATA_MTU
|
||||||
|
@ -479,7 +479,7 @@ fn send_datagram(sender: &mut Connection, receiver: &mut Connection, data: Vec<u
|
||||||
assert_eq!(sender.stats().frame_tx.datagram, dgram_sent + 1);
|
assert_eq!(sender.stats().frame_tx.datagram, dgram_sent + 1);
|
||||||
|
|
||||||
let dgram_received = receiver.stats().frame_rx.datagram;
|
let dgram_received = receiver.stats().frame_rx.datagram;
|
||||||
receiver.process_input(&out, now());
|
receiver.process_input(out, now());
|
||||||
assert_eq!(receiver.stats().frame_rx.datagram, dgram_received + 1);
|
assert_eq!(receiver.stats().frame_rx.datagram, dgram_received + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ fn multiple_quic_datagrams_in_one_packet() {
|
||||||
|
|
||||||
let out = client.process_output(now()).dgram();
|
let out = client.process_output(now()).dgram();
|
||||||
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 2);
|
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 2);
|
||||||
server.process_input(&out.unwrap(), now());
|
server.process_input(out.unwrap(), now());
|
||||||
let datagram = |e: &_| matches!(e, ConnectionEvent::Datagram(..));
|
let datagram = |e: &_| matches!(e, ConnectionEvent::Datagram(..));
|
||||||
assert_eq!(server.events().filter(datagram).count(), 2);
|
assert_eq!(server.events().filter(datagram).count(), 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,10 @@ use test_fixture::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
connection::tests::{
|
connection::tests::{
|
||||||
connect_force_idle, connect_force_idle_with_modifier, default_client, default_server,
|
assert_path_challenge_min_len, connect_force_idle, connect_force_idle_with_modifier,
|
||||||
handshake_with_modifier, migration::get_cid, new_client, new_server, send_and_receive,
|
default_client, default_server, handshake_with_modifier, migration::get_cid, new_client,
|
||||||
send_something, send_something_with_modifier, send_with_modifier_and_receive, DEFAULT_RTT,
|
new_server, send_and_receive, send_something, send_something_with_modifier,
|
||||||
|
send_with_modifier_and_receive, DEFAULT_RTT,
|
||||||
},
|
},
|
||||||
ecn::ECN_TEST_COUNT,
|
ecn::ECN_TEST_COUNT,
|
||||||
path::MAX_PATH_PROBES,
|
path::MAX_PATH_PROBES,
|
||||||
|
@ -120,6 +121,7 @@ fn migration_delay_to_ecn_blackhole() {
|
||||||
// This should be a PATH_CHALLENGE.
|
// This should be a PATH_CHALLENGE.
|
||||||
probes += 1;
|
probes += 1;
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, probes);
|
assert_eq!(client.stats().frame_tx.path_challenge, probes);
|
||||||
|
assert_path_challenge_min_len(&client, &d, now);
|
||||||
if probes <= MAX_PATH_PROBES {
|
if probes <= MAX_PATH_PROBES {
|
||||||
// The first probes should be sent with ECN.
|
// The first probes should be sent with ECN.
|
||||||
assert_ecn_enabled(d.tos());
|
assert_ecn_enabled(d.tos());
|
||||||
|
@ -143,12 +145,12 @@ fn stats() {
|
||||||
|
|
||||||
for _ in 0..ECN_TEST_COUNT {
|
for _ in 0..ECN_TEST_COUNT {
|
||||||
let ack = send_and_receive(&mut client, &mut server, now);
|
let ack = send_and_receive(&mut client, &mut server, now);
|
||||||
client.process_input(&ack.unwrap(), now);
|
client.process_input(ack.unwrap(), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..ECN_TEST_COUNT {
|
for _ in 0..ECN_TEST_COUNT {
|
||||||
let ack = send_and_receive(&mut server, &mut client, now);
|
let ack = send_and_receive(&mut server, &mut client, now);
|
||||||
server.process_input(&ack.unwrap(), now);
|
server.process_input(ack.unwrap(), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
for stats in [client.stats(), server.stats()] {
|
for stats in [client.stats(), server.stats()] {
|
||||||
|
@ -194,7 +196,7 @@ fn disables_on_remark() {
|
||||||
|
|
||||||
for _ in 0..ECN_TEST_COUNT {
|
for _ in 0..ECN_TEST_COUNT {
|
||||||
if let Some(ack) = send_with_modifier_and_receive(&mut client, &mut server, now, remark()) {
|
if let Some(ack) = send_with_modifier_and_receive(&mut client, &mut server, now, remark()) {
|
||||||
client.process_input(&ack, now);
|
client.process_input(ack, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,21 +225,21 @@ pub fn migration_with_modifiers(
|
||||||
// Right after the handshake, the ECN validation should still be in progress.
|
// Right after the handshake, the ECN validation should still be in progress.
|
||||||
let client_pkt = send_something(&mut client, now);
|
let client_pkt = send_something(&mut client, now);
|
||||||
assert_ecn_enabled(client_pkt.tos());
|
assert_ecn_enabled(client_pkt.tos());
|
||||||
server.process_input(&orig_path_modifier(client_pkt).unwrap(), now);
|
server.process_input(orig_path_modifier(client_pkt).unwrap(), now);
|
||||||
|
|
||||||
// Send some data on the current path.
|
// Send some data on the current path.
|
||||||
for _ in 0..burst {
|
for _ in 0..burst {
|
||||||
let client_pkt = send_something_with_modifier(&mut client, now, orig_path_modifier);
|
let client_pkt = send_something_with_modifier(&mut client, now, orig_path_modifier);
|
||||||
server.process_input(&client_pkt, now);
|
server.process_input(client_pkt, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ack) = server.process_output(now).dgram() {
|
if let Some(ack) = server.process_output(now).dgram() {
|
||||||
client.process_input(&ack, now);
|
client.process_input(ack, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
let client_pkt = send_something(&mut client, now);
|
let client_pkt = send_something(&mut client, now);
|
||||||
let tos_before_migration = client_pkt.tos();
|
let tos_before_migration = client_pkt.tos();
|
||||||
server.process_input(&orig_path_modifier(client_pkt).unwrap(), now);
|
server.process_input(orig_path_modifier(client_pkt).unwrap(), now);
|
||||||
|
|
||||||
client
|
client
|
||||||
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), false, now)
|
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), false, now)
|
||||||
|
@ -247,25 +249,27 @@ pub fn migration_with_modifiers(
|
||||||
let probe = new_path_modifier(client.process_output(now).dgram().unwrap());
|
let probe = new_path_modifier(client.process_output(now).dgram().unwrap());
|
||||||
if let Some(probe) = probe {
|
if let Some(probe) = probe {
|
||||||
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now);
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
let probe_cid = ConnectionId::from(get_cid(&probe));
|
let probe_cid = ConnectionId::from(get_cid(&probe));
|
||||||
|
|
||||||
let resp = new_path_modifier(server.process(Some(&probe), now).dgram().unwrap()).unwrap();
|
let resp = new_path_modifier(server.process(Some(probe), now).dgram().unwrap()).unwrap();
|
||||||
assert_v4_path(&resp, true);
|
assert_v4_path(&resp, true);
|
||||||
assert_eq!(server.stats().frame_tx.path_response, 1);
|
assert_eq!(server.stats().frame_tx.path_response, 1);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&server, &resp, now);
|
||||||
|
|
||||||
// Data continues to be exchanged on the old path.
|
// Data continues to be exchanged on the old path.
|
||||||
let client_data = send_something_with_modifier(&mut client, now, orig_path_modifier);
|
let client_data = send_something_with_modifier(&mut client, now, orig_path_modifier);
|
||||||
assert_ne!(get_cid(&client_data), probe_cid);
|
assert_ne!(get_cid(&client_data), probe_cid);
|
||||||
assert_v6_path(&client_data, false);
|
assert_v6_path(&client_data, false);
|
||||||
server.process_input(&client_data, now);
|
server.process_input(client_data, now);
|
||||||
let server_data = send_something_with_modifier(&mut server, now, orig_path_modifier);
|
let server_data = send_something_with_modifier(&mut server, now, orig_path_modifier);
|
||||||
assert_v6_path(&server_data, false);
|
assert_v6_path(&server_data, false);
|
||||||
client.process_input(&server_data, now);
|
client.process_input(server_data, now);
|
||||||
|
|
||||||
// Once the client receives the probe response, it migrates to the new path.
|
// Once the client receives the probe response, it migrates to the new path.
|
||||||
client.process_input(&resp, now);
|
client.process_input(resp, now);
|
||||||
assert_eq!(client.stats().frame_rx.path_challenge, 1);
|
assert_eq!(client.stats().frame_rx.path_challenge, 1);
|
||||||
migrated = true;
|
migrated = true;
|
||||||
|
|
||||||
|
@ -276,7 +280,7 @@ pub fn migration_with_modifiers(
|
||||||
// However, it will probe the old path again, even though it has just
|
// However, it will probe the old path again, even though it has just
|
||||||
// received a response to its last probe, because it needs to verify
|
// received a response to its last probe, because it needs to verify
|
||||||
// that the migration is genuine.
|
// that the migration is genuine.
|
||||||
server.process_input(&migrate_client, now);
|
server.process_input(migrate_client, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream_before = server.stats().frame_tx.stream;
|
let stream_before = server.stats().frame_tx.stream;
|
||||||
|
@ -287,6 +291,10 @@ pub fn migration_with_modifiers(
|
||||||
server.stats().frame_tx.path_challenge,
|
server.stats().frame_tx.path_challenge,
|
||||||
if migrated { 2 } else { 0 }
|
if migrated { 2 } else { 0 }
|
||||||
);
|
);
|
||||||
|
if migrated {
|
||||||
|
assert_path_challenge_min_len(&server, &probe_old_server, now);
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server.stats().frame_tx.stream,
|
server.stats().frame_tx.stream,
|
||||||
if migrated { stream_before } else { 1 }
|
if migrated { stream_before } else { 1 }
|
||||||
|
@ -301,8 +309,8 @@ pub fn migration_with_modifiers(
|
||||||
assert_eq!(server.stats().frame_tx.stream, stream_before + 1);
|
assert_eq!(server.stats().frame_tx.stream, stream_before + 1);
|
||||||
|
|
||||||
// The client receives these checks and responds to the probe, but uses the new path.
|
// The client receives these checks and responds to the probe, but uses the new path.
|
||||||
client.process_input(&migrate_server, now);
|
client.process_input(migrate_server, now);
|
||||||
client.process_input(&probe_old_server, now);
|
client.process_input(probe_old_server, now);
|
||||||
let old_probe_resp = send_something_with_modifier(&mut client, now, new_path_modifier);
|
let old_probe_resp = send_something_with_modifier(&mut client, now, new_path_modifier);
|
||||||
assert_v6_path(&old_probe_resp, true);
|
assert_v6_path(&old_probe_resp, true);
|
||||||
let client_confirmation = client.process_output(now).dgram().unwrap();
|
let client_confirmation = client.process_output(now).dgram().unwrap();
|
||||||
|
@ -315,17 +323,17 @@ pub fn migration_with_modifiers(
|
||||||
let server_confirmation =
|
let server_confirmation =
|
||||||
send_something_with_modifier(&mut server, now + server_pacing, new_path_modifier);
|
send_something_with_modifier(&mut server, now + server_pacing, new_path_modifier);
|
||||||
assert_v4_path(&server_confirmation, false);
|
assert_v4_path(&server_confirmation, false);
|
||||||
client.process_input(&server_confirmation, now);
|
client.process_input(server_confirmation, now);
|
||||||
|
|
||||||
// Send some data on the new path.
|
// Send some data on the new path.
|
||||||
for _ in 0..burst {
|
for _ in 0..burst {
|
||||||
now += client.process_output(now).callback();
|
now += client.process_output(now).callback();
|
||||||
let client_pkt = send_something_with_modifier(&mut client, now, new_path_modifier);
|
let client_pkt = send_something_with_modifier(&mut client, now, new_path_modifier);
|
||||||
server.process_input(&client_pkt, now);
|
server.process_input(client_pkt, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ack) = server.process_output(now).dgram() {
|
if let Some(ack) = server.process_output(now).dgram() {
|
||||||
client.process_input(&ack, now);
|
client.process_input(ack, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,37 +48,37 @@ const ECH_PUBLIC_NAME: &str = "public.example";
|
||||||
fn full_handshake(pmtud: bool) {
|
fn full_handshake(pmtud: bool) {
|
||||||
qdebug!("---- client: generate CH");
|
qdebug!("---- client: generate CH");
|
||||||
let mut client = new_client(ConnectionParameters::default().pmtud(pmtud));
|
let mut client = new_client(ConnectionParameters::default().pmtud(pmtud));
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_eq!(out.as_dgram_ref().unwrap().len(), client.plpmtu());
|
assert_eq!(out.as_dgram_ref().unwrap().len(), client.plpmtu());
|
||||||
|
|
||||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||||
let mut server = new_server(ConnectionParameters::default().pmtud(pmtud));
|
let mut server = new_server(ConnectionParameters::default().pmtud(pmtud));
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_eq!(out.as_dgram_ref().unwrap().len(), server.plpmtu());
|
assert_eq!(out.as_dgram_ref().unwrap().len(), server.plpmtu());
|
||||||
|
|
||||||
qdebug!("---- client: cert verification");
|
qdebug!("---- client: cert verification");
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
assert!(maybe_authenticate(&mut client));
|
assert!(maybe_authenticate(&mut client));
|
||||||
|
|
||||||
qdebug!("---- client: SH..FIN -> FIN");
|
qdebug!("---- client: SH..FIN -> FIN");
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
qdebug!("---- server: FIN -> ACKS");
|
qdebug!("---- server: FIN -> ACKS");
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
|
|
||||||
qdebug!("---- client: ACKS -> 0");
|
qdebug!("---- client: ACKS -> 0");
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
if pmtud {
|
if pmtud {
|
||||||
// PMTUD causes a PING probe to be sent here
|
// PMTUD causes a PING probe to be sent here
|
||||||
let pkt = out.dgram().unwrap();
|
let pkt = out.dgram().unwrap();
|
||||||
|
@ -103,19 +103,19 @@ fn handshake_pmtud() {
|
||||||
fn handshake_failed_authentication() {
|
fn handshake_failed_authentication() {
|
||||||
qdebug!("---- client: generate CH");
|
qdebug!("---- client: generate CH");
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
qdebug!("---- client: cert verification");
|
qdebug!("---- client: cert verification");
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
let authentication_needed = |e| matches!(e, ConnectionEvent::AuthenticationNeeded);
|
let authentication_needed = |e| matches!(e, ConnectionEvent::AuthenticationNeeded);
|
||||||
|
@ -124,11 +124,11 @@ fn handshake_failed_authentication() {
|
||||||
client.authenticated(AuthenticationStatus::CertRevoked, now());
|
client.authenticated(AuthenticationStatus::CertRevoked, now());
|
||||||
|
|
||||||
qdebug!("---- client: -> Alert(certificate_revoked)");
|
qdebug!("---- client: -> Alert(certificate_revoked)");
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
qdebug!("---- server: Alert(certificate_revoked)");
|
qdebug!("---- server: Alert(certificate_revoked)");
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_error(&client, &CloseReason::Transport(Error::CryptoAlert(44)));
|
assert_error(&client, &CloseReason::Transport(Error::CryptoAlert(44)));
|
||||||
assert_error(&server, &CloseReason::Transport(Error::PeerError(300)));
|
assert_error(&server, &CloseReason::Transport(Error::PeerError(300)));
|
||||||
|
@ -160,29 +160,29 @@ fn no_alpn() {
|
||||||
fn dup_server_flight1() {
|
fn dup_server_flight1() {
|
||||||
qdebug!("---- client: generate CH");
|
qdebug!("---- client: generate CH");
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_eq!(out.as_dgram_ref().unwrap().len(), client.plpmtu());
|
assert_eq!(out.as_dgram_ref().unwrap().len(), client.plpmtu());
|
||||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||||
|
|
||||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let out_to_rep = server.process(out.as_dgram_ref(), now());
|
let out_to_rep = server.process(out.dgram(), now());
|
||||||
assert!(out_to_rep.as_dgram_ref().is_some());
|
assert!(out_to_rep.as_dgram_ref().is_some());
|
||||||
qdebug!("Output={:0x?}", out_to_rep.as_dgram_ref());
|
qdebug!("Output={:0x?}", out_to_rep.as_dgram_ref());
|
||||||
|
|
||||||
qdebug!("---- client: cert verification");
|
qdebug!("---- client: cert verification");
|
||||||
let out = client.process(Some(out_to_rep.as_dgram_ref().unwrap()), now());
|
let out = client.process(Some(out_to_rep.as_dgram_ref().cloned().unwrap()), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||||
|
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
assert!(maybe_authenticate(&mut client));
|
assert!(maybe_authenticate(&mut client));
|
||||||
|
|
||||||
qdebug!("---- client: SH..FIN -> FIN");
|
qdebug!("---- client: SH..FIN -> FIN");
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ fn dup_server_flight1() {
|
||||||
assert_eq!(1, client.stats().dropped_rx);
|
assert_eq!(1, client.stats().dropped_rx);
|
||||||
|
|
||||||
qdebug!("---- Dup, ignored");
|
qdebug!("---- Dup, ignored");
|
||||||
let out = client.process(out_to_rep.as_dgram_ref(), now());
|
let out = client.process(out_to_rep.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||||
|
|
||||||
|
@ -216,17 +216,17 @@ fn crypto_frame_split() {
|
||||||
)
|
)
|
||||||
.expect("create a server");
|
.expect("create a server");
|
||||||
|
|
||||||
let client1 = client.process(None, now());
|
let client1 = client.process_output(now());
|
||||||
assert!(client1.as_dgram_ref().is_some());
|
assert!(client1.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// The entire server flight doesn't fit in a single packet because the
|
// The entire server flight doesn't fit in a single packet because the
|
||||||
// certificate is large, therefore the server will produce 2 packets.
|
// certificate is large, therefore the server will produce 2 packets.
|
||||||
let server1 = server.process(client1.as_dgram_ref(), now());
|
let server1 = server.process(client1.dgram(), now());
|
||||||
assert!(server1.as_dgram_ref().is_some());
|
assert!(server1.as_dgram_ref().is_some());
|
||||||
let server2 = server.process(None, now());
|
let server2 = server.process_output(now());
|
||||||
assert!(server2.as_dgram_ref().is_some());
|
assert!(server2.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let client2 = client.process(server1.as_dgram_ref(), now());
|
let client2 = client.process(server1.dgram(), now());
|
||||||
// This is an ack.
|
// This is an ack.
|
||||||
assert!(client2.as_dgram_ref().is_some());
|
assert!(client2.as_dgram_ref().is_some());
|
||||||
// The client might have the certificate now, so we can't guarantee that
|
// The client might have the certificate now, so we can't guarantee that
|
||||||
|
@ -235,11 +235,11 @@ fn crypto_frame_split() {
|
||||||
assert_eq!(*client.state(), State::Handshaking);
|
assert_eq!(*client.state(), State::Handshaking);
|
||||||
|
|
||||||
// let server process the ack for the first packet.
|
// let server process the ack for the first packet.
|
||||||
let server3 = server.process(client2.as_dgram_ref(), now());
|
let server3 = server.process(client2.dgram(), now());
|
||||||
assert!(server3.as_dgram_ref().is_none());
|
assert!(server3.as_dgram_ref().is_none());
|
||||||
|
|
||||||
// Consume the second packet from the server.
|
// Consume the second packet from the server.
|
||||||
let client3 = client.process(server2.as_dgram_ref(), now());
|
let client3 = client.process(server2.dgram(), now());
|
||||||
|
|
||||||
// Check authentication.
|
// Check authentication.
|
||||||
let auth2 = maybe_authenticate(&mut client);
|
let auth2 = maybe_authenticate(&mut client);
|
||||||
|
@ -247,13 +247,13 @@ fn crypto_frame_split() {
|
||||||
// Now client has all data to finish handshake.
|
// Now client has all data to finish handshake.
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
let client4 = client.process(server3.as_dgram_ref(), now());
|
let client4 = client.process(server3.dgram(), now());
|
||||||
// One of these will contain data depending on whether Authentication was completed
|
// One of these will contain data depending on whether Authentication was completed
|
||||||
// after the first or second server packet.
|
// after the first or second server packet.
|
||||||
assert!(client3.as_dgram_ref().is_some() ^ client4.as_dgram_ref().is_some());
|
assert!(client3.as_dgram_ref().is_some() ^ client4.as_dgram_ref().is_some());
|
||||||
|
|
||||||
mem::drop(server.process(client3.as_dgram_ref(), now()));
|
mem::drop(server.process(client3.dgram(), now()));
|
||||||
mem::drop(server.process(client4.as_dgram_ref(), now()));
|
mem::drop(server.process(client4.dgram(), now()));
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
|
@ -283,21 +283,21 @@ fn send_05rtt() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let c1 = client.process(None, now()).dgram();
|
let c1 = client.process_output(now()).dgram();
|
||||||
assert!(c1.is_some());
|
assert!(c1.is_some());
|
||||||
let s1 = server.process(c1.as_ref(), now()).dgram().unwrap();
|
let s1 = server.process(c1, now()).dgram().unwrap();
|
||||||
assert_eq!(s1.len(), server.plpmtu());
|
assert_eq!(s1.len(), server.plpmtu());
|
||||||
|
|
||||||
// The server should accept writes at this point.
|
// The server should accept writes at this point.
|
||||||
let s2 = send_something(&mut server, now());
|
let s2 = send_something(&mut server, now());
|
||||||
|
|
||||||
// Complete the handshake at the client.
|
// Complete the handshake at the client.
|
||||||
client.process_input(&s1, now());
|
client.process_input(s1, now());
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
// The client should receive the 0.5-RTT data now.
|
// The client should receive the 0.5-RTT data now.
|
||||||
client.process_input(&s2, now());
|
client.process_input(s2, now());
|
||||||
let mut buf = vec![0; DEFAULT_STREAM_DATA.len() + 1];
|
let mut buf = vec![0; DEFAULT_STREAM_DATA.len() + 1];
|
||||||
let stream_id = client
|
let stream_id = client
|
||||||
.events()
|
.events()
|
||||||
|
@ -320,21 +320,21 @@ fn reorder_05rtt() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let c1 = client.process(None, now()).dgram();
|
let c1 = client.process_output(now()).dgram();
|
||||||
assert!(c1.is_some());
|
assert!(c1.is_some());
|
||||||
let s1 = server.process(c1.as_ref(), now()).dgram().unwrap();
|
let s1 = server.process(c1, now()).dgram().unwrap();
|
||||||
|
|
||||||
// The server should accept writes at this point.
|
// The server should accept writes at this point.
|
||||||
let s2 = send_something(&mut server, now());
|
let s2 = send_something(&mut server, now());
|
||||||
|
|
||||||
// We can't use the standard facility to complete the handshake, so
|
// We can't use the standard facility to complete the handshake, so
|
||||||
// drive it as aggressively as possible.
|
// drive it as aggressively as possible.
|
||||||
client.process_input(&s2, now());
|
client.process_input(s2, now());
|
||||||
assert_eq!(client.stats().saved_datagrams, 1);
|
assert_eq!(client.stats().saved_datagrams, 1);
|
||||||
|
|
||||||
// After processing the first packet, the client should go back and
|
// After processing the first packet, the client should go back and
|
||||||
// process the 0.5-RTT packet data, which should make data available.
|
// process the 0.5-RTT packet data, which should make data available.
|
||||||
client.process_input(&s1, now());
|
client.process_input(s1, now());
|
||||||
// We can't use `maybe_authenticate` here as that consumes events.
|
// We can't use `maybe_authenticate` here as that consumes events.
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
@ -372,7 +372,7 @@ fn reorder_05rtt_with_0rtt() {
|
||||||
server.send_ticket(now, &[]).unwrap();
|
server.send_ticket(now, &[]).unwrap();
|
||||||
let ticket = server.process_output(now).dgram().unwrap();
|
let ticket = server.process_output(now).dgram().unwrap();
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&ticket, now);
|
client.process_input(ticket, now);
|
||||||
|
|
||||||
let token = get_tokens(&mut client).pop().unwrap();
|
let token = get_tokens(&mut client).pop().unwrap();
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
@ -389,35 +389,35 @@ fn reorder_05rtt_with_0rtt() {
|
||||||
|
|
||||||
// Handle the first packet and send 0.5-RTT in response. Drop the response.
|
// Handle the first packet and send 0.5-RTT in response. Drop the response.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
mem::drop(server.process(Some(&c1), now).dgram().unwrap());
|
mem::drop(server.process(Some(c1), now).dgram().unwrap());
|
||||||
// The gap in 0-RTT will result in this 0.5 RTT containing an ACK.
|
// The gap in 0-RTT will result in this 0.5 RTT containing an ACK.
|
||||||
server.process_input(&c2, now);
|
server.process_input(c2, now);
|
||||||
let s2 = send_something(&mut server, now);
|
let s2 = send_something(&mut server, now);
|
||||||
|
|
||||||
// Save the 0.5 RTT.
|
// Save the 0.5 RTT.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&s2, now);
|
client.process_input(s2, now);
|
||||||
assert_eq!(client.stats().saved_datagrams, 1);
|
assert_eq!(client.stats().saved_datagrams, 1);
|
||||||
|
|
||||||
// Now PTO at the client and cause the server to re-send handshake packets.
|
// Now PTO at the client and cause the server to re-send handshake packets.
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
let c3 = client.process(None, now).dgram();
|
let c3 = client.process_output(now).dgram();
|
||||||
assert_coalesced_0rtt(c3.as_ref().unwrap());
|
assert_coalesced_0rtt(c3.as_ref().unwrap());
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s3 = server.process(c3.as_ref(), now).dgram().unwrap();
|
let s3 = server.process(c3, now).dgram().unwrap();
|
||||||
|
|
||||||
// The client should be able to process the 0.5 RTT now.
|
// The client should be able to process the 0.5 RTT now.
|
||||||
// This should contain an ACK, so we are processing an ACK from the past.
|
// This should contain an ACK, so we are processing an ACK from the past.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&s3, now);
|
client.process_input(s3, now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let c4 = client.process(None, now).dgram();
|
let c4 = client.process_output(now).dgram();
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
assert_eq!(client.paths.rtt(), RTT);
|
assert_eq!(client.paths.rtt(), RTT);
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
server.process_input(&c4.unwrap(), now);
|
server.process_input(c4.unwrap(), now);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
// Don't check server RTT as it will be massively inflated by a
|
// Don't check server RTT as it will be massively inflated by a
|
||||||
// poor initial estimate received when the server dropped the
|
// poor initial estimate received when the server dropped the
|
||||||
|
@ -435,10 +435,10 @@ fn coalesce_05rtt() {
|
||||||
|
|
||||||
// The first exchange doesn't offer a chance for the server to send.
|
// The first exchange doesn't offer a chance for the server to send.
|
||||||
// So drop the server flight and wait for the PTO.
|
// So drop the server flight and wait for the PTO.
|
||||||
let c1 = client.process(None, now).dgram();
|
let c1 = client.process_output(now).dgram();
|
||||||
assert!(c1.is_some());
|
assert!(c1.is_some());
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s1 = server.process(c1.as_ref(), now).dgram();
|
let s1 = server.process(c1, now).dgram();
|
||||||
assert!(s1.is_some());
|
assert!(s1.is_some());
|
||||||
|
|
||||||
// Drop the server flight. Then send some data.
|
// Drop the server flight. Then send some data.
|
||||||
|
@ -450,10 +450,10 @@ fn coalesce_05rtt() {
|
||||||
// The server should then send its entire flight again,
|
// The server should then send its entire flight again,
|
||||||
// including the application data, which it sends in a 1-RTT packet.
|
// including the application data, which it sends in a 1-RTT packet.
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
let c2 = client.process(None, now).dgram();
|
let c2 = client.process_output(now).dgram();
|
||||||
assert!(c2.is_some());
|
assert!(c2.is_some());
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s2 = server.process(c2.as_ref(), now).dgram();
|
let s2 = server.process(c2, now).dgram();
|
||||||
// Even though there is a 1-RTT packet at the end of the datagram, the
|
// Even though there is a 1-RTT packet at the end of the datagram, the
|
||||||
// flight should be padded to full size.
|
// flight should be padded to full size.
|
||||||
assert_eq!(s2.as_ref().unwrap().len(), server.plpmtu());
|
assert_eq!(s2.as_ref().unwrap().len(), server.plpmtu());
|
||||||
|
@ -462,7 +462,7 @@ fn coalesce_05rtt() {
|
||||||
// packet until authentication completes though. So it saves it.
|
// packet until authentication completes though. So it saves it.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
assert_eq!(client.stats().dropped_rx, 0);
|
assert_eq!(client.stats().dropped_rx, 0);
|
||||||
mem::drop(client.process(s2.as_ref(), now).dgram());
|
mem::drop(client.process(s2, now).dgram());
|
||||||
// This packet will contain an ACK, but we can ignore it.
|
// This packet will contain an ACK, but we can ignore it.
|
||||||
assert_eq!(client.stats().dropped_rx, 0);
|
assert_eq!(client.stats().dropped_rx, 0);
|
||||||
assert_eq!(client.stats().packets_rx, 3);
|
assert_eq!(client.stats().packets_rx, 3);
|
||||||
|
@ -470,7 +470,7 @@ fn coalesce_05rtt() {
|
||||||
|
|
||||||
// After (successful) authentication, the packet is processed.
|
// After (successful) authentication, the packet is processed.
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let c3 = client.process(None, now).dgram();
|
let c3 = client.process_output(now).dgram();
|
||||||
assert!(c3.is_some());
|
assert!(c3.is_some());
|
||||||
assert_eq!(client.stats().dropped_rx, 0); // No Initial padding.
|
assert_eq!(client.stats().dropped_rx, 0); // No Initial padding.
|
||||||
assert_eq!(client.stats().packets_rx, 4);
|
assert_eq!(client.stats().packets_rx, 4);
|
||||||
|
@ -479,11 +479,11 @@ fn coalesce_05rtt() {
|
||||||
|
|
||||||
// Allow the handshake to complete.
|
// Allow the handshake to complete.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s3 = server.process(c3.as_ref(), now).dgram();
|
let s3 = server.process(c3, now).dgram();
|
||||||
assert!(s3.is_some());
|
assert!(s3.is_some());
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
mem::drop(client.process(s3.as_ref(), now).dgram());
|
mem::drop(client.process(s3, now).dgram());
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
|
|
||||||
assert_eq!(client.stats().dropped_rx, 0); // No dropped packets.
|
assert_eq!(client.stats().dropped_rx, 0); // No dropped packets.
|
||||||
|
@ -496,11 +496,11 @@ fn reorder_handshake() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let c1 = client.process(None, now).dgram();
|
let c1 = client.process_output(now).dgram();
|
||||||
assert!(c1.is_some());
|
assert!(c1.is_some());
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s1 = server.process(c1.as_ref(), now).dgram();
|
let s1 = server.process(c1, now).dgram();
|
||||||
assert!(s1.is_some());
|
assert!(s1.is_some());
|
||||||
|
|
||||||
// Drop the Initial packet from this.
|
// Drop the Initial packet from this.
|
||||||
|
@ -510,7 +510,7 @@ fn reorder_handshake() {
|
||||||
// Pass just the handshake packet in and the client can't handle it yet.
|
// Pass just the handshake packet in and the client can't handle it yet.
|
||||||
// It can only send another Initial packet.
|
// It can only send another Initial packet.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let dgram = client.process(s_hs.as_ref(), now).dgram();
|
let dgram = client.process(s_hs, now).dgram();
|
||||||
assertions::assert_initial(dgram.as_ref().unwrap(), false);
|
assertions::assert_initial(dgram.as_ref().unwrap(), false);
|
||||||
assert_eq!(client.stats().saved_datagrams, 1);
|
assert_eq!(client.stats().saved_datagrams, 1);
|
||||||
assert_eq!(client.stats().packets_rx, 1);
|
assert_eq!(client.stats().packets_rx, 1);
|
||||||
|
@ -519,9 +519,9 @@ fn reorder_handshake() {
|
||||||
// Though we currently allow the server to arm its PTO timer, use
|
// Though we currently allow the server to arm its PTO timer, use
|
||||||
// a second client Initial packet to cause it to send again.
|
// a second client Initial packet to cause it to send again.
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
let c2 = client.process(None, now).dgram();
|
let c2 = client.process_output(now).dgram();
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s2 = server.process(c2.as_ref(), now).dgram();
|
let s2 = server.process(c2, now).dgram();
|
||||||
assert!(s2.is_some());
|
assert!(s2.is_some());
|
||||||
|
|
||||||
let (s_init, s_hs) = split_datagram(&s2.unwrap());
|
let (s_init, s_hs) = split_datagram(&s2.unwrap());
|
||||||
|
@ -529,28 +529,28 @@ fn reorder_handshake() {
|
||||||
|
|
||||||
// Processing the Handshake packet first should save it.
|
// Processing the Handshake packet first should save it.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&s_hs.unwrap(), now);
|
client.process_input(s_hs.unwrap(), now);
|
||||||
assert_eq!(client.stats().saved_datagrams, 2);
|
assert_eq!(client.stats().saved_datagrams, 2);
|
||||||
assert_eq!(client.stats().packets_rx, 2);
|
assert_eq!(client.stats().packets_rx, 2);
|
||||||
|
|
||||||
client.process_input(&s_init, now);
|
client.process_input(s_init, now);
|
||||||
// Each saved packet should now be "received" again.
|
// Each saved packet should now be "received" again.
|
||||||
assert_eq!(client.stats().packets_rx, 7);
|
assert_eq!(client.stats().packets_rx, 7);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let c3 = client.process(None, now).dgram();
|
let c3 = client.process_output(now).dgram();
|
||||||
assert!(c3.is_some());
|
assert!(c3.is_some());
|
||||||
|
|
||||||
// Note that though packets were saved and processed very late,
|
// Note that though packets were saved and processed very late,
|
||||||
// they don't cause the RTT to change.
|
// they don't cause the RTT to change.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s3 = server.process(c3.as_ref(), now).dgram();
|
let s3 = server.process(c3, now).dgram();
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
// Don't check server RTT estimate as it will be inflated due to
|
// Don't check server RTT estimate as it will be inflated due to
|
||||||
// it making a guess based on retransmissions when it dropped
|
// it making a guess based on retransmissions when it dropped
|
||||||
// the Initial packet number space.
|
// the Initial packet number space.
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&s3.unwrap(), now);
|
client.process_input(s3.unwrap(), now);
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
assert_eq!(client.paths.rtt(), RTT);
|
assert_eq!(client.paths.rtt(), RTT);
|
||||||
}
|
}
|
||||||
|
@ -563,24 +563,24 @@ fn reorder_1rtt() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let c1 = client.process(None, now).dgram();
|
let c1 = client.process_output(now).dgram();
|
||||||
assert!(c1.is_some());
|
assert!(c1.is_some());
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s1 = server.process(c1.as_ref(), now).dgram();
|
let s1 = server.process(c1, now).dgram();
|
||||||
assert!(s1.is_some());
|
assert!(s1.is_some());
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&s1.unwrap(), now);
|
client.process_input(s1.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let c2 = client.process(None, now).dgram();
|
let c2 = client.process_output(now).dgram();
|
||||||
assert!(c2.is_some());
|
assert!(c2.is_some());
|
||||||
|
|
||||||
// Now get a bunch of packets from the client.
|
// Now get a bunch of packets from the client.
|
||||||
// Give them to the server before giving it `c2`.
|
// Give them to the server before giving it `c2`.
|
||||||
for _ in 0..PACKETS {
|
for _ in 0..PACKETS {
|
||||||
let d = send_something(&mut client, now);
|
let d = send_something(&mut client, now);
|
||||||
server.process_input(&d, now + RTT / 2);
|
server.process_input(d, now + RTT / 2);
|
||||||
}
|
}
|
||||||
// The server has now received those packets, and saved them.
|
// The server has now received those packets, and saved them.
|
||||||
// The two extra received are Initial + the junk we use for padding.
|
// The two extra received are Initial + the junk we use for padding.
|
||||||
|
@ -589,7 +589,7 @@ fn reorder_1rtt() {
|
||||||
assert_eq!(server.stats().dropped_rx, 1);
|
assert_eq!(server.stats().dropped_rx, 1);
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s2 = server.process(c2.as_ref(), now).dgram();
|
let s2 = server.process(c2, now).dgram();
|
||||||
// The server has now received those packets, and saved them.
|
// The server has now received those packets, and saved them.
|
||||||
// The two additional are a Handshake and a 1-RTT (w/ NEW_CONNECTION_ID).
|
// The two additional are a Handshake and a 1-RTT (w/ NEW_CONNECTION_ID).
|
||||||
assert_eq!(server.stats().packets_rx, PACKETS * 2 + 4);
|
assert_eq!(server.stats().packets_rx, PACKETS * 2 + 4);
|
||||||
|
@ -599,7 +599,7 @@ fn reorder_1rtt() {
|
||||||
assert_eq!(server.paths.rtt(), RTT);
|
assert_eq!(server.paths.rtt(), RTT);
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&s2.unwrap(), now);
|
client.process_input(s2.unwrap(), now);
|
||||||
assert_eq!(client.paths.rtt(), RTT);
|
assert_eq!(client.paths.rtt(), RTT);
|
||||||
|
|
||||||
// All the stream data that was sent should now be available.
|
// All the stream data that was sent should now be available.
|
||||||
|
@ -627,7 +627,7 @@ fn reorder_1rtt() {
|
||||||
fn corrupted_initial() {
|
fn corrupted_initial() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let d = client.process(None, now()).dgram().unwrap();
|
let d = client.process_output(now()).dgram().unwrap();
|
||||||
let mut corrupted = Vec::from(&d[..]);
|
let mut corrupted = Vec::from(&d[..]);
|
||||||
// Find the last non-zero value and corrupt that.
|
// Find the last non-zero value and corrupt that.
|
||||||
let (idx, _) = corrupted
|
let (idx, _) = corrupted
|
||||||
|
@ -638,7 +638,7 @@ fn corrupted_initial() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
corrupted[idx] ^= 0x76;
|
corrupted[idx] ^= 0x76;
|
||||||
let dgram = Datagram::new(d.source(), d.destination(), d.tos(), corrupted);
|
let dgram = Datagram::new(d.source(), d.destination(), d.tos(), corrupted);
|
||||||
server.process_input(&dgram, now());
|
server.process_input(dgram, now());
|
||||||
// The server should have received two packets,
|
// The server should have received two packets,
|
||||||
// the first should be dropped, the second saved.
|
// the first should be dropped, the second saved.
|
||||||
assert_eq!(server.stats().packets_rx, 2);
|
assert_eq!(server.stats().packets_rx, 2);
|
||||||
|
@ -655,14 +655,14 @@ fn verify_pkt_honors_mtu() {
|
||||||
|
|
||||||
let now = now();
|
let now = now();
|
||||||
|
|
||||||
let res = client.process(None, now);
|
let res = client.process_output(now);
|
||||||
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
|
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
|
||||||
assert_eq!(res, Output::Callback(idle_timeout));
|
assert_eq!(res, Output::Callback(idle_timeout));
|
||||||
|
|
||||||
// Try to send a large stream and verify first packet is correctly sized
|
// Try to send a large stream and verify first packet is correctly sized
|
||||||
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
assert_eq!(client.stream_send(stream_id, &[0xbb; 2000]).unwrap(), 2000);
|
assert_eq!(client.stream_send(stream_id, &[0xbb; 2000]).unwrap(), 2000);
|
||||||
let pkt0 = client.process(None, now);
|
let pkt0 = client.process_output(now);
|
||||||
assert!(matches!(pkt0, Output::Datagram(_)));
|
assert!(matches!(pkt0, Output::Datagram(_)));
|
||||||
assert_eq!(pkt0.as_dgram_ref().unwrap().len(), client.plpmtu());
|
assert_eq!(pkt0.as_dgram_ref().unwrap().len(), client.plpmtu());
|
||||||
}
|
}
|
||||||
|
@ -673,10 +673,10 @@ fn extra_initial_hs() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let c_init = client.process(None, now).dgram();
|
let c_init = client.process_output(now).dgram();
|
||||||
assert!(c_init.is_some());
|
assert!(c_init.is_some());
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
let s_init = server.process(c_init.as_ref(), now).dgram();
|
let s_init = server.process(c_init, now).dgram();
|
||||||
assert!(s_init.is_some());
|
assert!(s_init.is_some());
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
|
|
||||||
|
@ -688,28 +688,28 @@ fn extra_initial_hs() {
|
||||||
// Do that EXTRA_INITIALS times and each time the client will emit
|
// Do that EXTRA_INITIALS times and each time the client will emit
|
||||||
// another Initial packet.
|
// another Initial packet.
|
||||||
for _ in 0..=super::super::EXTRA_INITIALS {
|
for _ in 0..=super::super::EXTRA_INITIALS {
|
||||||
let c_init = client.process(undecryptable.as_ref(), now).dgram();
|
let c_init = client.process(undecryptable.clone(), now).dgram();
|
||||||
assertions::assert_initial(c_init.as_ref().unwrap(), false);
|
assertions::assert_initial(c_init.as_ref().unwrap(), false);
|
||||||
now += DEFAULT_RTT / 10;
|
now += DEFAULT_RTT / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// After EXTRA_INITIALS, the client stops sending Initial packets.
|
// After EXTRA_INITIALS, the client stops sending Initial packets.
|
||||||
let nothing = client.process(undecryptable.as_ref(), now).dgram();
|
let nothing = client.process(undecryptable, now).dgram();
|
||||||
assert!(nothing.is_none());
|
assert!(nothing.is_none());
|
||||||
|
|
||||||
// Until PTO, where another Initial can be used to complete the handshake.
|
// Until PTO, where another Initial can be used to complete the handshake.
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
let c_init = client.process(None, now).dgram();
|
let c_init = client.process_output(now).dgram();
|
||||||
assertions::assert_initial(c_init.as_ref().unwrap(), false);
|
assertions::assert_initial(c_init.as_ref().unwrap(), false);
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
let s_init = server.process(c_init.as_ref(), now).dgram();
|
let s_init = server.process(c_init, now).dgram();
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
client.process_input(&s_init.unwrap(), now);
|
client.process_input(s_init.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let c_fin = client.process_output(now).dgram();
|
let c_fin = client.process_output(now).dgram();
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
server.process_input(&c_fin.unwrap(), now);
|
server.process_input(c_fin.unwrap(), now);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,10 +719,10 @@ fn extra_initial_invalid_cid() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let c_init = client.process(None, now).dgram();
|
let c_init = client.process_output(now).dgram();
|
||||||
assert!(c_init.is_some());
|
assert!(c_init.is_some());
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
let s_init = server.process(c_init.as_ref(), now).dgram();
|
let s_init = server.process(c_init, now).dgram();
|
||||||
assert!(s_init.is_some());
|
assert!(s_init.is_some());
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
|
|
||||||
|
@ -734,7 +734,7 @@ fn extra_initial_invalid_cid() {
|
||||||
assert_ne!(copy[5], 0); // The DCID should be non-zero length.
|
assert_ne!(copy[5], 0); // The DCID should be non-zero length.
|
||||||
copy[6] ^= 0xc4;
|
copy[6] ^= 0xc4;
|
||||||
let dgram_copy = Datagram::new(hs.destination(), hs.source(), hs.tos(), copy);
|
let dgram_copy = Datagram::new(hs.destination(), hs.source(), hs.tos(), copy);
|
||||||
let nothing = client.process(Some(&dgram_copy), now).dgram();
|
let nothing = client.process(Some(dgram_copy), now).dgram();
|
||||||
assert!(nothing.is_none());
|
assert!(nothing.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,7 +783,7 @@ fn anti_amplification() {
|
||||||
|
|
||||||
let c_init = client.process_output(now).dgram();
|
let c_init = client.process_output(now).dgram();
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
let s_init1 = server.process(c_init.as_ref(), now).dgram().unwrap();
|
let s_init1 = server.process(c_init, now).dgram().unwrap();
|
||||||
assert_eq!(s_init1.len(), server.plpmtu());
|
assert_eq!(s_init1.len(), server.plpmtu());
|
||||||
let s_init2 = server.process_output(now).dgram().unwrap();
|
let s_init2 = server.process_output(now).dgram().unwrap();
|
||||||
assert_eq!(s_init2.len(), server.plpmtu());
|
assert_eq!(s_init2.len(), server.plpmtu());
|
||||||
|
@ -795,11 +795,11 @@ fn anti_amplification() {
|
||||||
assert_eq!(cb, server.conn_params.get_idle_timeout());
|
assert_eq!(cb, server.conn_params.get_idle_timeout());
|
||||||
|
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
client.process_input(&s_init1, now);
|
client.process_input(s_init1, now);
|
||||||
client.process_input(&s_init2, now);
|
client.process_input(s_init2, now);
|
||||||
let ack_count = client.stats().frame_tx.ack;
|
let ack_count = client.stats().frame_tx.ack;
|
||||||
let frame_count = client.stats().frame_tx.all();
|
let frame_count = client.stats().frame_tx.all();
|
||||||
let ack = client.process(Some(&s_init3), now).dgram().unwrap();
|
let ack = client.process(Some(s_init3), now).dgram().unwrap();
|
||||||
assert!(!maybe_authenticate(&mut client)); // No need yet.
|
assert!(!maybe_authenticate(&mut client)); // No need yet.
|
||||||
|
|
||||||
// The client sends a padded datagram, with just ACK for Handshake.
|
// The client sends a padded datagram, with just ACK for Handshake.
|
||||||
|
@ -808,16 +808,16 @@ fn anti_amplification() {
|
||||||
assert_ne!(ack.len(), client.plpmtu()); // Not padded (it includes Handshake).
|
assert_ne!(ack.len(), client.plpmtu()); // Not padded (it includes Handshake).
|
||||||
|
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
let remainder = server.process(Some(&ack), now).dgram();
|
let remainder = server.process(Some(ack), now).dgram();
|
||||||
|
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
client.process_input(&remainder.unwrap(), now);
|
client.process_input(remainder.unwrap(), now);
|
||||||
assert!(maybe_authenticate(&mut client)); // OK, we have all of it.
|
assert!(maybe_authenticate(&mut client)); // OK, we have all of it.
|
||||||
let fin = client.process_output(now).dgram();
|
let fin = client.process_output(now).dgram();
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
server.process_input(&fin.unwrap(), now);
|
server.process_input(fin.unwrap(), now);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,17 +833,17 @@ fn garbage_initial() {
|
||||||
corrupted.push(initial[initial.len() - 1] ^ 0xb7);
|
corrupted.push(initial[initial.len() - 1] ^ 0xb7);
|
||||||
corrupted.extend_from_slice(rest.as_ref().map_or(&[], |r| &r[..]));
|
corrupted.extend_from_slice(rest.as_ref().map_or(&[], |r| &r[..]));
|
||||||
let garbage = datagram(corrupted);
|
let garbage = datagram(corrupted);
|
||||||
assert_eq!(Output::None, server.process(Some(&garbage), now()));
|
assert_eq!(Output::None, server.process(Some(garbage), now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drop_initial_packet_from_wrong_address() {
|
fn drop_initial_packet_from_wrong_address() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let p = out.dgram().unwrap();
|
let p = out.dgram().unwrap();
|
||||||
|
@ -854,24 +854,24 @@ fn drop_initial_packet_from_wrong_address() {
|
||||||
&p[..],
|
&p[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
let out = client.process(Some(&dgram), now());
|
let out = client.process(Some(dgram), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drop_handshake_packet_from_wrong_address() {
|
fn drop_handshake_packet_from_wrong_address() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let (s_in, s_hs) = split_datagram(&out.dgram().unwrap());
|
let (s_in, s_hs) = split_datagram(&out.dgram().unwrap());
|
||||||
|
|
||||||
// Pass the initial packet.
|
// Pass the initial packet.
|
||||||
mem::drop(client.process(Some(&s_in), now()).dgram());
|
mem::drop(client.process(Some(s_in), now()).dgram());
|
||||||
|
|
||||||
let p = s_hs.unwrap();
|
let p = s_hs.unwrap();
|
||||||
let dgram = Datagram::new(
|
let dgram = Datagram::new(
|
||||||
|
@ -881,7 +881,7 @@ fn drop_handshake_packet_from_wrong_address() {
|
||||||
&p[..],
|
&p[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
let out = client.process(Some(&dgram), now());
|
let out = client.process(Some(dgram), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,8 +930,8 @@ fn ech_retry() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
let auth_event = ConnectionEvent::EchFallbackAuthenticationNeeded {
|
let auth_event = ConnectionEvent::EchFallbackAuthenticationNeeded {
|
||||||
public_name: String::from(ECH_PUBLIC_NAME),
|
public_name: String::from(ECH_PUBLIC_NAME),
|
||||||
};
|
};
|
||||||
|
@ -941,7 +941,7 @@ fn ech_retry() {
|
||||||
|
|
||||||
// Tell the server about the error.
|
// Tell the server about the error.
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server.state().error(),
|
server.state().error(),
|
||||||
Some(&CloseReason::Transport(Error::PeerError(0x100 + 121)))
|
Some(&CloseReason::Transport(Error::PeerError(0x100 + 121)))
|
||||||
|
@ -985,8 +985,8 @@ fn ech_retry_fallback_rejected() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
let auth_event = ConnectionEvent::EchFallbackAuthenticationNeeded {
|
let auth_event = ConnectionEvent::EchFallbackAuthenticationNeeded {
|
||||||
public_name: String::from(ECH_PUBLIC_NAME),
|
public_name: String::from(ECH_PUBLIC_NAME),
|
||||||
};
|
};
|
||||||
|
@ -1000,7 +1000,7 @@ fn ech_retry_fallback_rejected() {
|
||||||
|
|
||||||
// Pass the error on.
|
// Pass the error on.
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server.state().error(),
|
server.state().error(),
|
||||||
Some(&CloseReason::Transport(Error::PeerError(298)))
|
Some(&CloseReason::Transport(Error::PeerError(298)))
|
||||||
|
@ -1018,13 +1018,13 @@ fn bad_min_ack_delay() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
assert_eq!(client.state().error(), Some(&EXPECTED_ERROR));
|
assert_eq!(client.state().error(), Some(&EXPECTED_ERROR));
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
|
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server.state().error(),
|
server.state().error(),
|
||||||
Some(&CloseReason::Transport(Error::PeerError(
|
Some(&CloseReason::Transport(Error::PeerError(
|
||||||
|
@ -1044,7 +1044,7 @@ fn only_server_initial() {
|
||||||
let client_dgram = client.process_output(now).dgram();
|
let client_dgram = client.process_output(now).dgram();
|
||||||
|
|
||||||
// Now fetch two flights of messages from the server.
|
// Now fetch two flights of messages from the server.
|
||||||
let server_dgram1 = server.process(client_dgram.as_ref(), now).dgram();
|
let server_dgram1 = server.process(client_dgram, now).dgram();
|
||||||
let server_dgram2 = server.process_output(now + AT_LEAST_PTO).dgram();
|
let server_dgram2 = server.process_output(now + AT_LEAST_PTO).dgram();
|
||||||
|
|
||||||
// Only pass on the Initial from the first. We should get a Handshake in return.
|
// Only pass on the Initial from the first. We should get a Handshake in return.
|
||||||
|
@ -1054,7 +1054,7 @@ fn only_server_initial() {
|
||||||
// The client will not acknowledge the Initial as it discards keys.
|
// The client will not acknowledge the Initial as it discards keys.
|
||||||
// It sends a Handshake probe instead, containing just a PING frame.
|
// It sends a Handshake probe instead, containing just a PING frame.
|
||||||
assert_eq!(client.stats().frame_tx.ping, 0);
|
assert_eq!(client.stats().frame_tx.ping, 0);
|
||||||
let probe = client.process(Some(&initial), now).dgram();
|
let probe = client.process(Some(initial), now).dgram();
|
||||||
assertions::assert_handshake(&probe.unwrap());
|
assertions::assert_handshake(&probe.unwrap());
|
||||||
assert_eq!(client.stats().dropped_rx, 0);
|
assert_eq!(client.stats().dropped_rx, 0);
|
||||||
assert_eq!(client.stats().frame_tx.ping, 1);
|
assert_eq!(client.stats().frame_tx.ping, 1);
|
||||||
|
@ -1066,17 +1066,17 @@ fn only_server_initial() {
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
assert_eq!(client.stats().frame_tx.ping, 1);
|
assert_eq!(client.stats().frame_tx.ping, 1);
|
||||||
let discarded = client.stats().dropped_rx;
|
let discarded = client.stats().dropped_rx;
|
||||||
let probe = client.process(Some(&initial), now).dgram();
|
let probe = client.process(Some(initial), now).dgram();
|
||||||
assertions::assert_handshake(&probe.unwrap());
|
assertions::assert_handshake(&probe.unwrap());
|
||||||
assert_eq!(client.stats().frame_tx.ping, 2);
|
assert_eq!(client.stats().frame_tx.ping, 2);
|
||||||
assert_eq!(client.stats().dropped_rx, discarded + 1);
|
assert_eq!(client.stats().dropped_rx, discarded + 1);
|
||||||
|
|
||||||
// Pass the Handshake packet and complete the handshake.
|
// Pass the Handshake packet and complete the handshake.
|
||||||
client.process_input(&handshake.unwrap(), now);
|
client.process_input(handshake.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
|
@ -1102,25 +1102,25 @@ fn no_extra_probes_after_confirmed() {
|
||||||
// Finally, run the handshake.
|
// Finally, run the handshake.
|
||||||
now += AT_LEAST_PTO * 2;
|
now += AT_LEAST_PTO * 2;
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
|
|
||||||
// The server should have dropped the Initial keys now, so passing in the Initial
|
// The server should have dropped the Initial keys now, so passing in the Initial
|
||||||
// should elicit a retransmit rather than having it completely ignored.
|
// should elicit a retransmit rather than having it completely ignored.
|
||||||
let spare_handshake = server.process(Some(&replay_initial), now).dgram();
|
let spare_handshake = server.process(Some(replay_initial), now).dgram();
|
||||||
assert!(spare_handshake.is_some());
|
assert!(spare_handshake.is_some());
|
||||||
|
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
|
|
||||||
let probe = server.process(spare_initial.as_ref(), now).dgram();
|
let probe = server.process(spare_initial, now).dgram();
|
||||||
assert!(probe.is_none());
|
assert!(probe.is_none());
|
||||||
let probe = client.process(spare_handshake.as_ref(), now).dgram();
|
let probe = client.process(spare_handshake, now).dgram();
|
||||||
assert!(probe.is_none());
|
assert!(probe.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,12 +1133,12 @@ fn implicit_rtt_server() {
|
||||||
|
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let dgram = client.process(dgram.as_ref(), now).dgram();
|
let dgram = client.process(dgram, now).dgram();
|
||||||
assertions::assert_handshake(dgram.as_ref().unwrap());
|
assertions::assert_handshake(dgram.as_ref().unwrap());
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
// The server doesn't receive any acknowledgments, but it can infer
|
// The server doesn't receive any acknowledgments, but it can infer
|
||||||
// an RTT estimate from having discarded the Initial packet number space.
|
// an RTT estimate from having discarded the Initial packet number space.
|
||||||
|
@ -1157,14 +1157,14 @@ fn emit_authentication_needed_once() {
|
||||||
)
|
)
|
||||||
.expect("create a server");
|
.expect("create a server");
|
||||||
|
|
||||||
let client1 = client.process(None, now());
|
let client1 = client.process_output(now());
|
||||||
assert!(client1.as_dgram_ref().is_some());
|
assert!(client1.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// The entire server flight doesn't fit in a single packet because the
|
// The entire server flight doesn't fit in a single packet because the
|
||||||
// certificate is large, therefore the server will produce 2 packets.
|
// certificate is large, therefore the server will produce 2 packets.
|
||||||
let server1 = server.process(client1.as_dgram_ref(), now());
|
let server1 = server.process(client1.dgram(), now());
|
||||||
assert!(server1.as_dgram_ref().is_some());
|
assert!(server1.as_dgram_ref().is_some());
|
||||||
let server2 = server.process(None, now());
|
let server2 = server.process_output(now());
|
||||||
assert!(server2.as_dgram_ref().is_some());
|
assert!(server2.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let authentication_needed_count = |client: &mut Connection| {
|
let authentication_needed_count = |client: &mut Connection| {
|
||||||
|
@ -1184,7 +1184,7 @@ fn emit_authentication_needed_once() {
|
||||||
// packet, but be large enough that the CertificateVerify message does not
|
// packet, but be large enough that the CertificateVerify message does not
|
||||||
// also fit in the same packet. Our default test setup achieves this, but
|
// also fit in the same packet. Our default test setup achieves this, but
|
||||||
// changes to the setup might invalidate this test.
|
// changes to the setup might invalidate this test.
|
||||||
_ = client.process(server1.as_dgram_ref(), now());
|
_ = client.process(server1.dgram(), now());
|
||||||
assert_eq!(1, authentication_needed_count(&mut client));
|
assert_eq!(1, authentication_needed_count(&mut client));
|
||||||
assert!(client.peer_certificate().is_some());
|
assert!(client.peer_certificate().is_some());
|
||||||
|
|
||||||
|
@ -1192,7 +1192,7 @@ fn emit_authentication_needed_once() {
|
||||||
// `Connection::authenticated`. On receiving the second packet from the
|
// `Connection::authenticated`. On receiving the second packet from the
|
||||||
// server, the client must not emit a another
|
// server, the client must not emit a another
|
||||||
// `ConnectionEvent::AuthenticationNeeded`.
|
// `ConnectionEvent::AuthenticationNeeded`.
|
||||||
_ = client.process(server2.as_dgram_ref(), now());
|
_ = client.process(server2.dgram(), now());
|
||||||
assert_eq!(0, authentication_needed_count(&mut client));
|
assert_eq!(0, authentication_needed_count(&mut client));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1204,7 +1204,7 @@ fn client_initial_retransmits_identical() {
|
||||||
// Force the client to retransmit its Initial packet a number of times and make sure the
|
// Force the client to retransmit its Initial packet a number of times and make sure the
|
||||||
// retranmissions are identical to the original. Also, verify the PTO durations.
|
// retranmissions are identical to the original. Also, verify the PTO durations.
|
||||||
for i in 1..=5 {
|
for i in 1..=5 {
|
||||||
let ci = client.process(None, now).dgram().unwrap();
|
let ci = client.process_output(now).dgram().unwrap();
|
||||||
assert_eq!(ci.len(), client.plpmtu());
|
assert_eq!(ci.len(), client.plpmtu());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client.stats().frame_tx,
|
client.stats().frame_tx,
|
||||||
|
@ -1213,7 +1213,7 @@ fn client_initial_retransmits_identical() {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let pto = client.process(None, now).callback();
|
let pto = client.process_output(now).callback();
|
||||||
assert_eq!(pto, DEFAULT_RTT * 3 * (1 << (i - 1)));
|
assert_eq!(pto, DEFAULT_RTT * 3 * (1 << (i - 1)));
|
||||||
now += pto;
|
now += pto;
|
||||||
}
|
}
|
||||||
|
@ -1223,14 +1223,14 @@ fn client_initial_retransmits_identical() {
|
||||||
fn server_initial_retransmits_identical() {
|
fn server_initial_retransmits_identical() {
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut ci = client.process(None, now).dgram();
|
let mut ci = client.process_output(now).dgram();
|
||||||
|
|
||||||
// Force the server to retransmit its Initial packet a number of times and make sure the
|
// Force the server to retransmit its Initial packet a number of times and make sure the
|
||||||
// retranmissions are identical to the original. Also, verify the PTO durations.
|
// retranmissions are identical to the original. Also, verify the PTO durations.
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut total_ptos: Duration = Duration::from_secs(0);
|
let mut total_ptos: Duration = Duration::from_secs(0);
|
||||||
for i in 1..=3 {
|
for i in 1..=3 {
|
||||||
let si = server.process(ci.take().as_ref(), now).dgram().unwrap();
|
let si = server.process(ci.take(), now).dgram().unwrap();
|
||||||
assert_eq!(si.len(), server.plpmtu());
|
assert_eq!(si.len(), server.plpmtu());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server.stats().frame_tx,
|
server.stats().frame_tx,
|
||||||
|
@ -1241,7 +1241,7 @@ fn server_initial_retransmits_identical() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let pto = server.process(None, now).callback();
|
let pto = server.process_output(now).callback();
|
||||||
if i < 3 {
|
if i < 3 {
|
||||||
assert_eq!(pto, DEFAULT_RTT * 3 * (1 << (i - 1)));
|
assert_eq!(pto, DEFAULT_RTT * 3 * (1 << (i - 1)));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -40,17 +40,14 @@ fn test_idle_timeout(client: &mut Connection, server: &mut Connection, timeout:
|
||||||
|
|
||||||
let now = now();
|
let now = now();
|
||||||
|
|
||||||
let res = client.process(None, now);
|
let res = client.process_output(now);
|
||||||
assert_eq!(res, Output::Callback(timeout));
|
assert_eq!(res, Output::Callback(timeout));
|
||||||
|
|
||||||
// Still connected after timeout-1 seconds. Idle timer not reset
|
// Still connected after timeout-1 seconds. Idle timer not reset
|
||||||
mem::drop(client.process(
|
mem::drop(client.process_output(now + timeout.checked_sub(Duration::from_secs(1)).unwrap()));
|
||||||
None,
|
|
||||||
now + timeout.checked_sub(Duration::from_secs(1)).unwrap(),
|
|
||||||
));
|
|
||||||
assert!(matches!(client.state(), State::Confirmed));
|
assert!(matches!(client.state(), State::Confirmed));
|
||||||
|
|
||||||
mem::drop(client.process(None, now + timeout));
|
mem::drop(client.process_output(now + timeout));
|
||||||
|
|
||||||
// Not connected after timeout.
|
// Not connected after timeout.
|
||||||
assert!(matches!(client.state(), State::Closed(_)));
|
assert!(matches!(client.state(), State::Closed(_)));
|
||||||
|
@ -112,19 +109,19 @@ fn asymmetric_idle_timeout() {
|
||||||
connect(&mut client, &mut server);
|
connect(&mut client, &mut server);
|
||||||
let c1 = send_something(&mut client, now());
|
let c1 = send_something(&mut client, now());
|
||||||
let c2 = send_something(&mut client, now());
|
let c2 = send_something(&mut client, now());
|
||||||
server.process_input(&c2, now());
|
server.process_input(c2, now());
|
||||||
server.process_input(&c1, now());
|
server.process_input(c1, now());
|
||||||
let s1 = send_something(&mut server, now());
|
let s1 = send_something(&mut server, now());
|
||||||
let s2 = send_something(&mut server, now());
|
let s2 = send_something(&mut server, now());
|
||||||
client.process_input(&s2, now());
|
client.process_input(s2, now());
|
||||||
let ack = client.process(Some(&s1), now()).dgram();
|
let ack = client.process(Some(s1), now()).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
// Now both should have received ACK frames so should be idle.
|
// Now both should have received ACK frames so should be idle.
|
||||||
|
assert_eq!(server.process(ack, now()), Output::Callback(LOWER_TIMEOUT));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server.process(ack.as_ref(), now()),
|
client.process_output(now()),
|
||||||
Output::Callback(LOWER_TIMEOUT)
|
Output::Callback(LOWER_TIMEOUT)
|
||||||
);
|
);
|
||||||
assert_eq!(client.process(None, now()), Output::Callback(LOWER_TIMEOUT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -152,17 +149,17 @@ fn tiny_idle_timeout() {
|
||||||
let c1 = send_something(&mut client, now);
|
let c1 = send_something(&mut client, now);
|
||||||
let c2 = send_something(&mut client, now);
|
let c2 = send_something(&mut client, now);
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
server.process_input(&c2, now);
|
server.process_input(c2, now);
|
||||||
server.process_input(&c1, now);
|
server.process_input(c1, now);
|
||||||
let s1 = send_something(&mut server, now);
|
let s1 = send_something(&mut server, now);
|
||||||
let s2 = send_something(&mut server, now);
|
let s2 = send_something(&mut server, now);
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&s2, now);
|
client.process_input(s2, now);
|
||||||
let ack = client.process(Some(&s1), now).dgram();
|
let ack = client.process(Some(s1), now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
|
|
||||||
// The client should be idle now, but with a different timer.
|
// The client should be idle now, but with a different timer.
|
||||||
if let Output::Callback(t) = client.process(None, now) {
|
if let Output::Callback(t) = client.process_output(now) {
|
||||||
assert!(t > LOWER_TIMEOUT);
|
assert!(t > LOWER_TIMEOUT);
|
||||||
} else {
|
} else {
|
||||||
panic!("Client not idle");
|
panic!("Client not idle");
|
||||||
|
@ -170,7 +167,7 @@ fn tiny_idle_timeout() {
|
||||||
|
|
||||||
// The server should go idle after the ACK, but again with a larger timeout.
|
// The server should go idle after the ACK, but again with a larger timeout.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
if let Output::Callback(t) = client.process(ack.as_ref(), now) {
|
if let Output::Callback(t) = client.process(ack, now) {
|
||||||
assert!(t > LOWER_TIMEOUT);
|
assert!(t > LOWER_TIMEOUT);
|
||||||
} else {
|
} else {
|
||||||
panic!("Client not idle");
|
panic!("Client not idle");
|
||||||
|
@ -186,7 +183,7 @@ fn idle_send_packet1() {
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
connect_force_idle(&mut client, &mut server);
|
connect_force_idle(&mut client, &mut server);
|
||||||
|
|
||||||
let timeout = client.process(None, now).callback();
|
let timeout = client.process_output(now).callback();
|
||||||
assert_eq!(timeout, default_timeout());
|
assert_eq!(timeout, default_timeout());
|
||||||
|
|
||||||
now += Duration::from_secs(10);
|
now += Duration::from_secs(10);
|
||||||
|
@ -196,13 +193,13 @@ fn idle_send_packet1() {
|
||||||
// Still connected after 39 seconds because idle timer reset by the
|
// Still connected after 39 seconds because idle timer reset by the
|
||||||
// outgoing packet.
|
// outgoing packet.
|
||||||
now += default_timeout() - DELTA;
|
now += default_timeout() - DELTA;
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
assert!(dgram.is_some()); // PTO
|
assert!(dgram.is_some()); // PTO
|
||||||
assert!(client.state().connected());
|
assert!(client.state().connected());
|
||||||
|
|
||||||
// Not connected after 40 seconds.
|
// Not connected after 40 seconds.
|
||||||
now += DELTA;
|
now += DELTA;
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
assert!(matches!(out, Output::None));
|
assert!(matches!(out, Output::None));
|
||||||
assert!(client.state().closed());
|
assert!(client.state().closed());
|
||||||
}
|
}
|
||||||
|
@ -218,7 +215,7 @@ fn idle_send_packet2() {
|
||||||
|
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let timeout = client.process(None, now).callback();
|
let timeout = client.process_output(now).callback();
|
||||||
assert_eq!(timeout, default_timeout());
|
assert_eq!(timeout, default_timeout());
|
||||||
|
|
||||||
// First transmission at t=GAP.
|
// First transmission at t=GAP.
|
||||||
|
@ -231,14 +228,14 @@ fn idle_send_packet2() {
|
||||||
|
|
||||||
// Still connected just before GAP + default_timeout().
|
// Still connected just before GAP + default_timeout().
|
||||||
now += default_timeout() - DELTA;
|
now += default_timeout() - DELTA;
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
assert!(dgram.is_some()); // PTO
|
assert!(dgram.is_some()); // PTO
|
||||||
assert!(matches!(client.state(), State::Confirmed));
|
assert!(matches!(client.state(), State::Confirmed));
|
||||||
|
|
||||||
// Not connected after 40 seconds because timer not reset by second
|
// Not connected after 40 seconds because timer not reset by second
|
||||||
// outgoing packet
|
// outgoing packet
|
||||||
now += DELTA;
|
now += DELTA;
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
assert!(matches!(out, Output::None));
|
assert!(matches!(out, Output::None));
|
||||||
assert!(matches!(client.state(), State::Closed(_)));
|
assert!(matches!(client.state(), State::Closed(_)));
|
||||||
}
|
}
|
||||||
|
@ -253,7 +250,7 @@ fn idle_recv_packet() {
|
||||||
|
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let res = client.process(None, now);
|
let res = client.process_output(now);
|
||||||
assert_eq!(res, Output::Callback(default_timeout()));
|
assert_eq!(res, Output::Callback(default_timeout()));
|
||||||
|
|
||||||
let stream = client.stream_create(StreamType::BiDi).unwrap();
|
let stream = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
|
@ -264,21 +261,21 @@ fn idle_recv_packet() {
|
||||||
// Note that it is important that this not result in the RTT increasing above 0.
|
// Note that it is important that this not result in the RTT increasing above 0.
|
||||||
// Otherwise, the eventual timeout will be extended (and we're not testing that).
|
// Otherwise, the eventual timeout will be extended (and we're not testing that).
|
||||||
now += Duration::from_secs(10);
|
now += Duration::from_secs(10);
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
server.process_input(&out.dgram().unwrap(), now);
|
server.process_input(out.dgram().unwrap(), now);
|
||||||
assert_eq!(server.stream_send(stream, b"world").unwrap(), 5);
|
assert_eq!(server.stream_send(stream, b"world").unwrap(), 5);
|
||||||
let out = server.process_output(now);
|
let out = server.process_output(now);
|
||||||
assert_ne!(out.as_dgram_ref(), None);
|
assert_ne!(out.as_dgram_ref(), None);
|
||||||
mem::drop(client.process(out.as_dgram_ref(), now));
|
mem::drop(client.process(out.dgram(), now));
|
||||||
assert!(matches!(client.state(), State::Confirmed));
|
assert!(matches!(client.state(), State::Confirmed));
|
||||||
|
|
||||||
// Add a little less than the idle timeout and we're still connected.
|
// Add a little less than the idle timeout and we're still connected.
|
||||||
now += default_timeout() - FUDGE;
|
now += default_timeout() - FUDGE;
|
||||||
mem::drop(client.process(None, now));
|
mem::drop(client.process_output(now));
|
||||||
assert!(matches!(client.state(), State::Confirmed));
|
assert!(matches!(client.state(), State::Confirmed));
|
||||||
|
|
||||||
now += FUDGE;
|
now += FUDGE;
|
||||||
mem::drop(client.process(None, now));
|
mem::drop(client.process_output(now));
|
||||||
|
|
||||||
assert!(matches!(client.state(), State::Closed(_)));
|
assert!(matches!(client.state(), State::Closed(_)));
|
||||||
}
|
}
|
||||||
|
@ -296,9 +293,9 @@ fn idle_caching() {
|
||||||
// Perform the first round trip, but drop the Initial from the server.
|
// Perform the first round trip, but drop the Initial from the server.
|
||||||
// The client then caches the Handshake packet.
|
// The client then caches the Handshake packet.
|
||||||
let dgram = client.process_output(start).dgram();
|
let dgram = client.process_output(start).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), start).dgram();
|
let dgram = server.process(dgram, start).dgram();
|
||||||
let (_, handshake) = split_datagram(&dgram.unwrap());
|
let (_, handshake) = split_datagram(&dgram.unwrap());
|
||||||
client.process_input(&handshake.unwrap(), start);
|
client.process_input(handshake.unwrap(), start);
|
||||||
|
|
||||||
// Perform an exchange and keep the connection alive.
|
// Perform an exchange and keep the connection alive.
|
||||||
let middle = start + AT_LEAST_PTO;
|
let middle = start + AT_LEAST_PTO;
|
||||||
|
@ -309,7 +306,7 @@ fn idle_caching() {
|
||||||
mem::drop(server.process_output(middle).dgram());
|
mem::drop(server.process_output(middle).dgram());
|
||||||
// Now let the server process the RTX'ed client Initial. This causes the server
|
// Now let the server process the RTX'ed client Initial. This causes the server
|
||||||
// to send CRYPTO frames again, so manually extract and discard those.
|
// to send CRYPTO frames again, so manually extract and discard those.
|
||||||
server.process_input(&dgram.unwrap(), middle);
|
server.process_input(dgram.unwrap(), middle);
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
server.crypto.streams.write_frame(
|
server.crypto.streams.write_frame(
|
||||||
PacketNumberSpace::Initial,
|
PacketNumberSpace::Initial,
|
||||||
|
@ -333,7 +330,7 @@ fn idle_caching() {
|
||||||
let (initial, _) = split_datagram(&dgram.unwrap());
|
let (initial, _) = split_datagram(&dgram.unwrap());
|
||||||
let crypto_before_c = client.stats().frame_rx.crypto;
|
let crypto_before_c = client.stats().frame_rx.crypto;
|
||||||
let ack_before = client.stats().frame_rx.ack;
|
let ack_before = client.stats().frame_rx.ack;
|
||||||
client.process_input(&initial, middle);
|
client.process_input(initial, middle);
|
||||||
assert_eq!(client.stats().frame_rx.crypto, crypto_before_c);
|
assert_eq!(client.stats().frame_rx.crypto, crypto_before_c);
|
||||||
assert_eq!(client.stats().frame_rx.ack, ack_before + 1);
|
assert_eq!(client.stats().frame_rx.ack, ack_before + 1);
|
||||||
|
|
||||||
|
@ -342,11 +339,11 @@ fn idle_caching() {
|
||||||
let dgram = server.process_output(end).dgram();
|
let dgram = server.process_output(end).dgram();
|
||||||
let (initial, _) = split_datagram(&dgram.unwrap());
|
let (initial, _) = split_datagram(&dgram.unwrap());
|
||||||
neqo_common::qwarn!("client ingests initial, finally");
|
neqo_common::qwarn!("client ingests initial, finally");
|
||||||
mem::drop(client.process(Some(&initial), end));
|
mem::drop(client.process(Some(initial), end));
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let dgram = client.process_output(end).dgram();
|
let dgram = client.process_output(end).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), end).dgram();
|
let dgram = server.process(dgram, end).dgram();
|
||||||
client.process_input(&dgram.unwrap(), end);
|
client.process_input(dgram.unwrap(), end);
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
}
|
}
|
||||||
|
@ -375,7 +372,7 @@ fn create_stream_idle_rtt(
|
||||||
_ = initiator.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
|
_ = initiator.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
|
||||||
let req = initiator.process_output(now).dgram();
|
let req = initiator.process_output(now).dgram();
|
||||||
now += rtt / 2;
|
now += rtt / 2;
|
||||||
responder.process_input(&req.unwrap(), now);
|
responder.process_input(req.unwrap(), now);
|
||||||
|
|
||||||
// Reordering two packets from the responder forces the initiator to be idle.
|
// Reordering two packets from the responder forces the initiator to be idle.
|
||||||
_ = responder.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
|
_ = responder.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
|
||||||
|
@ -384,15 +381,15 @@ fn create_stream_idle_rtt(
|
||||||
let resp2 = responder.process_output(now).dgram();
|
let resp2 = responder.process_output(now).dgram();
|
||||||
|
|
||||||
now += rtt / 2;
|
now += rtt / 2;
|
||||||
initiator.process_input(&resp2.unwrap(), now);
|
initiator.process_input(resp2.unwrap(), now);
|
||||||
initiator.process_input(&resp1.unwrap(), now);
|
initiator.process_input(resp1.unwrap(), now);
|
||||||
let ack = initiator.process_output(now).dgram();
|
let ack = initiator.process_output(now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
check_idle(initiator, now);
|
check_idle(initiator, now);
|
||||||
|
|
||||||
// Receiving the ACK should return the responder to idle too.
|
// Receiving the ACK should return the responder to idle too.
|
||||||
now += rtt / 2;
|
now += rtt / 2;
|
||||||
responder.process_input(&ack.unwrap(), now);
|
responder.process_input(ack.unwrap(), now);
|
||||||
check_idle(responder, now);
|
check_idle(responder, now);
|
||||||
|
|
||||||
(now, stream)
|
(now, stream)
|
||||||
|
@ -428,9 +425,9 @@ fn keep_alive_initiator() {
|
||||||
assert_eq!(server.stats().frame_tx.ping, pings_before + 1);
|
assert_eq!(server.stats().frame_tx.ping, pings_before + 1);
|
||||||
|
|
||||||
// Exchange ack for the PING.
|
// Exchange ack for the PING.
|
||||||
let out = client.process(ping.as_ref(), now).dgram();
|
let out = client.process(ping, now).dgram();
|
||||||
let out = server.process(out.as_ref(), now).dgram();
|
let out = server.process(out, now).dgram();
|
||||||
assert!(client.process(out.as_ref(), now).dgram().is_none());
|
assert!(client.process(out, now).dgram().is_none());
|
||||||
|
|
||||||
// Check that there will be next keep-alive ping after keep_alive_timeout().
|
// Check that there will be next keep-alive ping after keep_alive_timeout().
|
||||||
assert_idle(&mut server, now, keep_alive_timeout());
|
assert_idle(&mut server, now, keep_alive_timeout());
|
||||||
|
@ -469,12 +466,12 @@ fn keep_alive_lost() {
|
||||||
assert_eq!(server.stats().frame_tx.ping, pings_before2 + 1);
|
assert_eq!(server.stats().frame_tx.ping, pings_before2 + 1);
|
||||||
|
|
||||||
// Exchange ack for the PING.
|
// Exchange ack for the PING.
|
||||||
let out = client.process(ping.as_ref(), now).dgram();
|
let out = client.process(ping, now).dgram();
|
||||||
|
|
||||||
now += Duration::from_millis(20);
|
now += Duration::from_millis(20);
|
||||||
let out = server.process(out.as_ref(), now).dgram();
|
let out = server.process(out, now).dgram();
|
||||||
|
|
||||||
assert!(client.process(out.as_ref(), now).dgram().is_none());
|
assert!(client.process(out, now).dgram().is_none());
|
||||||
|
|
||||||
// TODO: if we run server.process with current value of now, the server will
|
// TODO: if we run server.process with current value of now, the server will
|
||||||
// return some small timeout for the recovry although it does not have
|
// return some small timeout for the recovry although it does not have
|
||||||
|
@ -527,10 +524,10 @@ fn keep_alive_unmark() {
|
||||||
fn transfer_force_idle(sender: &mut Connection, receiver: &mut Connection) {
|
fn transfer_force_idle(sender: &mut Connection, receiver: &mut Connection) {
|
||||||
let dgram = sender.process_output(now()).dgram();
|
let dgram = sender.process_output(now()).dgram();
|
||||||
let chaff = send_something(sender, now());
|
let chaff = send_something(sender, now());
|
||||||
receiver.process_input(&chaff, now());
|
receiver.process_input(chaff, now());
|
||||||
receiver.process_input(&dgram.unwrap(), now());
|
receiver.process_input(dgram.unwrap(), now());
|
||||||
let ack = receiver.process_output(now()).dgram();
|
let ack = receiver.process_output(now()).dgram();
|
||||||
sender.process_input(&ack.unwrap(), now());
|
sender.process_input(ack.unwrap(), now());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receiving the end of the stream stops keep-alives for that stream.
|
/// Receiving the end of the stream stops keep-alives for that stream.
|
||||||
|
@ -598,7 +595,7 @@ fn keep_alive_stop_sending() {
|
||||||
// The server will have sent RESET_STREAM, which the client will
|
// The server will have sent RESET_STREAM, which the client will
|
||||||
// want to acknowledge, so force that out.
|
// want to acknowledge, so force that out.
|
||||||
let junk = send_something(&mut server, now());
|
let junk = send_something(&mut server, now());
|
||||||
let ack = client.process(Some(&junk), now()).dgram();
|
let ack = client.process(Some(junk), now()).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
|
|
||||||
// Now the client should be idle.
|
// Now the client should be idle.
|
||||||
|
@ -661,7 +658,7 @@ fn keep_alive_uni() {
|
||||||
_ = client.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
|
_ = client.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
|
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
server.stream_keep_alive(stream, true).unwrap();
|
server.stream_keep_alive(stream, true).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ fn check_discarded(
|
||||||
mem::drop(peer.process_output(now()));
|
mem::drop(peer.process_output(now()));
|
||||||
|
|
||||||
let before = peer.stats();
|
let before = peer.stats();
|
||||||
let out = peer.process(Some(pkt), now());
|
let out = peer.process(Some(pkt.clone()), now());
|
||||||
assert_eq!(out.as_dgram_ref().is_some(), response);
|
assert_eq!(out.as_dgram_ref().is_some(), response);
|
||||||
let after = peer.stats();
|
let after = peer.stats();
|
||||||
assert_eq!(dropped, after.dropped_rx - before.dropped_rx);
|
assert_eq!(dropped, after.dropped_rx - before.dropped_rx);
|
||||||
|
@ -57,17 +57,17 @@ fn overwrite_invocations(n: PacketNumber) {
|
||||||
fn discarded_initial_keys() {
|
fn discarded_initial_keys() {
|
||||||
qdebug!("---- client: generate CH");
|
qdebug!("---- client: generate CH");
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let init_pkt_c = client.process(None, now()).dgram();
|
let init_pkt_c = client.process_output(now()).dgram();
|
||||||
assert!(init_pkt_c.is_some());
|
assert!(init_pkt_c.is_some());
|
||||||
assert_eq!(init_pkt_c.as_ref().unwrap().len(), client.plpmtu());
|
assert_eq!(init_pkt_c.as_ref().unwrap().len(), client.plpmtu());
|
||||||
|
|
||||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let init_pkt_s = server.process(init_pkt_c.as_ref(), now()).dgram();
|
let init_pkt_s = server.process(init_pkt_c.clone(), now()).dgram();
|
||||||
assert!(init_pkt_s.is_some());
|
assert!(init_pkt_s.is_some());
|
||||||
|
|
||||||
qdebug!("---- client: cert verification");
|
qdebug!("---- client: cert verification");
|
||||||
let out = client.process(init_pkt_s.as_ref(), now()).dgram();
|
let out = client.process(init_pkt_s.clone(), now()).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
|
|
||||||
// The client has received a handshake packet. It will remove the Initial keys.
|
// The client has received a handshake packet. It will remove the Initial keys.
|
||||||
|
@ -86,12 +86,12 @@ fn discarded_initial_keys() {
|
||||||
check_discarded(&mut server, &init_pkt_c.clone().unwrap(), false, 1, 1);
|
check_discarded(&mut server, &init_pkt_c.clone().unwrap(), false, 1, 1);
|
||||||
|
|
||||||
qdebug!("---- client: SH..FIN -> FIN");
|
qdebug!("---- client: SH..FIN -> FIN");
|
||||||
let out = client.process(None, now()).dgram();
|
let out = client.process_output(now()).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
|
|
||||||
// The server will process the first Handshake packet.
|
// The server will process the first Handshake packet.
|
||||||
// After this the Initial keys will be dropped.
|
// After this the Initial keys will be dropped.
|
||||||
let out = server.process(out.as_ref(), now()).dgram();
|
let out = server.process(out, now()).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
|
|
||||||
// Check that the Initial keys are dropped at the server
|
// Check that the Initial keys are dropped at the server
|
||||||
|
@ -116,7 +116,7 @@ fn key_update_client() {
|
||||||
|
|
||||||
// Initiating an update should only increase the write epoch.
|
// Initiating an update should only increase the write epoch.
|
||||||
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
|
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
|
||||||
assert_eq!(Output::Callback(idle_timeout), client.process(None, now));
|
assert_eq!(Output::Callback(idle_timeout), client.process_output(now));
|
||||||
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
|
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
|
||||||
|
|
||||||
// Send something to propagate the update.
|
// Send something to propagate the update.
|
||||||
|
@ -125,7 +125,7 @@ fn key_update_client() {
|
||||||
|
|
||||||
// The server should now be waiting to discharge read keys.
|
// The server should now be waiting to discharge read keys.
|
||||||
assert_eq!(server.get_epochs(), (Some(4), Some(3)));
|
assert_eq!(server.get_epochs(), (Some(4), Some(3)));
|
||||||
let res = server.process(None, now);
|
let res = server.process_output(now);
|
||||||
if let Output::Callback(t) = res {
|
if let Output::Callback(t) = res {
|
||||||
assert!(t < idle_timeout);
|
assert!(t < idle_timeout);
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,10 +142,10 @@ fn key_update_client() {
|
||||||
// But at this point the client hasn't received a key update from the server.
|
// But at this point the client hasn't received a key update from the server.
|
||||||
// It will be stuck with old keys.
|
// It will be stuck with old keys.
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
assert!(dgram.is_some()); // Drop this packet.
|
assert!(dgram.is_some()); // Drop this packet.
|
||||||
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
|
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
|
||||||
mem::drop(server.process(None, now));
|
mem::drop(server.process_output(now));
|
||||||
assert_eq!(server.get_epochs(), (Some(4), Some(4)));
|
assert_eq!(server.get_epochs(), (Some(4), Some(4)));
|
||||||
|
|
||||||
// Even though the server has updated, it hasn't received an ACK yet.
|
// Even though the server has updated, it hasn't received an ACK yet.
|
||||||
|
@ -155,7 +155,7 @@ fn key_update_client() {
|
||||||
// The previous PTO packet (see above) was dropped, so we should get an ACK here.
|
// The previous PTO packet (see above) was dropped, so we should get an ACK here.
|
||||||
let dgram = send_and_receive(&mut client, &mut server, now);
|
let dgram = send_and_receive(&mut client, &mut server, now);
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let res = client.process(dgram.as_ref(), now);
|
let res = client.process(dgram, now);
|
||||||
// This is the first packet that the client has received from the server
|
// This is the first packet that the client has received from the server
|
||||||
// with new keys, so its read timer just started.
|
// with new keys, so its read timer just started.
|
||||||
if let Output::Callback(t) = res {
|
if let Output::Callback(t) = res {
|
||||||
|
@ -170,7 +170,7 @@ fn key_update_client() {
|
||||||
assert_update_blocked(&mut server);
|
assert_update_blocked(&mut server);
|
||||||
|
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
mem::drop(client.process(None, now));
|
mem::drop(client.process_output(now));
|
||||||
assert_eq!(client.get_epochs(), (Some(4), Some(4)));
|
assert_eq!(client.get_epochs(), (Some(4), Some(4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,11 +194,11 @@ fn key_update_consecutive() {
|
||||||
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
|
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
|
||||||
|
|
||||||
// Have the server process the ACK.
|
// Have the server process the ACK.
|
||||||
if let Output::Callback(_) = server.process(dgram.as_ref(), now) {
|
if let Output::Callback(_) = server.process(dgram, now) {
|
||||||
assert_eq!(server.get_epochs(), (Some(4), Some(3)));
|
assert_eq!(server.get_epochs(), (Some(4), Some(3)));
|
||||||
// Now move the server temporarily into the future so that it
|
// Now move the server temporarily into the future so that it
|
||||||
// rotates the keys. The client stays in the present.
|
// rotates the keys. The client stays in the present.
|
||||||
mem::drop(server.process(None, now + AT_LEAST_PTO));
|
mem::drop(server.process_output(now + AT_LEAST_PTO));
|
||||||
assert_eq!(server.get_epochs(), (Some(4), Some(4)));
|
assert_eq!(server.get_epochs(), (Some(4), Some(4)));
|
||||||
} else {
|
} else {
|
||||||
panic!("server should have a timer set");
|
panic!("server should have a timer set");
|
||||||
|
@ -224,33 +224,33 @@ fn key_update_before_confirmed() {
|
||||||
assert_update_blocked(&mut server);
|
assert_update_blocked(&mut server);
|
||||||
|
|
||||||
// Client Initial
|
// Client Initial
|
||||||
let dgram = client.process(None, now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assert_update_blocked(&mut client);
|
assert_update_blocked(&mut client);
|
||||||
|
|
||||||
// Server Initial + Handshake
|
// Server Initial + Handshake
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assert_update_blocked(&mut server);
|
assert_update_blocked(&mut server);
|
||||||
|
|
||||||
// Client Handshake
|
// Client Handshake
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert_update_blocked(&mut client);
|
assert_update_blocked(&mut client);
|
||||||
|
|
||||||
assert!(maybe_authenticate(&mut client));
|
assert!(maybe_authenticate(&mut client));
|
||||||
assert_update_blocked(&mut client);
|
assert_update_blocked(&mut client);
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assert_update_blocked(&mut client);
|
assert_update_blocked(&mut client);
|
||||||
|
|
||||||
// Server HANDSHAKE_DONE
|
// Server HANDSHAKE_DONE
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assert!(server.initiate_key_update().is_ok());
|
assert!(server.initiate_key_update().is_ok());
|
||||||
|
|
||||||
// Client receives HANDSHAKE_DONE
|
// Client receives HANDSHAKE_DONE
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram();
|
let dgram = client.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
assert!(client.initiate_key_update().is_ok());
|
assert!(client.initiate_key_update().is_ok());
|
||||||
}
|
}
|
||||||
|
@ -281,13 +281,13 @@ fn exhaust_read_keys() {
|
||||||
let dgram = send_something(&mut client, now());
|
let dgram = send_something(&mut client, now());
|
||||||
|
|
||||||
overwrite_invocations(0);
|
overwrite_invocations(0);
|
||||||
let dgram = server.process(Some(&dgram), now()).dgram();
|
let dgram = server.process(Some(dgram), now()).dgram();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
server.state(),
|
server.state(),
|
||||||
State::Closed(CloseReason::Transport(Error::KeysExhausted))
|
State::Closed(CloseReason::Transport(Error::KeysExhausted))
|
||||||
));
|
));
|
||||||
|
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
client.state(),
|
client.state(),
|
||||||
State::Draining {
|
State::Draining {
|
||||||
|
|
|
@ -25,7 +25,7 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
cid::LOCAL_ACTIVE_CID_LIMIT,
|
cid::LOCAL_ACTIVE_CID_LIMIT,
|
||||||
connection::tests::{send_something_paced, send_with_extra},
|
connection::tests::{assert_path_challenge_min_len, send_something_paced, send_with_extra},
|
||||||
frame::FRAME_TYPE_NEW_CONNECTION_ID,
|
frame::FRAME_TYPE_NEW_CONNECTION_ID,
|
||||||
packet::PacketBuilder,
|
packet::PacketBuilder,
|
||||||
path::MAX_PATH_PROBES,
|
path::MAX_PATH_PROBES,
|
||||||
|
@ -75,7 +75,7 @@ fn rebinding_port() {
|
||||||
let dgram = send_something(&mut client, now());
|
let dgram = send_something(&mut client, now());
|
||||||
let dgram = change_source_port(&dgram);
|
let dgram = change_source_port(&dgram);
|
||||||
|
|
||||||
server.process_input(&dgram, now());
|
server.process_input(dgram, now());
|
||||||
// Have the server send something so that it generates a packet.
|
// Have the server send something so that it generates a packet.
|
||||||
let stream_id = server.stream_create(StreamType::UniDi).unwrap();
|
let stream_id = server.stream_create(StreamType::UniDi).unwrap();
|
||||||
server.stream_close_send(stream_id).unwrap();
|
server.stream_close_send(stream_id).unwrap();
|
||||||
|
@ -97,15 +97,17 @@ fn path_forwarding_attack() {
|
||||||
|
|
||||||
let dgram = send_something(&mut client, now);
|
let dgram = send_something(&mut client, now);
|
||||||
let dgram = change_path(&dgram, DEFAULT_ADDR_V4);
|
let dgram = change_path(&dgram, DEFAULT_ADDR_V4);
|
||||||
server.process_input(&dgram, now);
|
server.process_input(dgram, now);
|
||||||
|
|
||||||
// The server now probes the new (primary) path.
|
// 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_eq!(server.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&server, &new_probe, now);
|
||||||
assert_v4_path(&new_probe, false); // Can't be padded.
|
assert_v4_path(&new_probe, false); // Can't be padded.
|
||||||
|
|
||||||
// The server also probes the old path.
|
// 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_path_challenge_min_len(&server, &old_probe, now);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 2);
|
assert_eq!(server.stats().frame_tx.path_challenge, 2);
|
||||||
assert_v6_path(&old_probe, true);
|
assert_v6_path(&old_probe, true);
|
||||||
|
|
||||||
|
@ -117,14 +119,14 @@ fn path_forwarding_attack() {
|
||||||
|
|
||||||
// The client should respond to the challenge on the new path.
|
// The client should respond to the challenge on the new path.
|
||||||
// The server couldn't pad, so the client is also amplification limited.
|
// 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_rx.path_challenge, 1);
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
assert_eq!(client.stats().frame_tx.path_response, 1);
|
assert_eq!(client.stats().frame_tx.path_response, 1);
|
||||||
assert_v4_path(&new_resp, false);
|
assert_v4_path(&new_resp, false);
|
||||||
|
|
||||||
// The client also responds to probes on the old path.
|
// 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_rx.path_challenge, 2);
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
assert_eq!(client.stats().frame_tx.path_response, 2);
|
assert_eq!(client.stats().frame_tx.path_response, 2);
|
||||||
|
@ -137,12 +139,13 @@ fn path_forwarding_attack() {
|
||||||
// Receiving the PATH_RESPONSE from the client opens the amplification
|
// Receiving the PATH_RESPONSE from the client opens the amplification
|
||||||
// limit enough for the server to respond.
|
// limit enough for the server to respond.
|
||||||
// This is padded because it includes PATH_CHALLENGE.
|
// 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_v4_path(&server_data1, true);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 3);
|
assert_eq!(server.stats().frame_tx.path_challenge, 3);
|
||||||
|
assert_path_challenge_min_len(&server, &server_data1, now);
|
||||||
|
|
||||||
// The client responds to this probe on the new path.
|
// 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 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_eq!(stream_before, client.stats().frame_tx.stream);
|
||||||
|
@ -157,7 +160,7 @@ fn path_forwarding_attack() {
|
||||||
assert_v4_path(&server_data2, false);
|
assert_v4_path(&server_data2, false);
|
||||||
|
|
||||||
// Until new data is received from the client on the old path.
|
// 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 new path.
|
// The server sends a probe on the new path.
|
||||||
let server_data3 = send_something(&mut server, now);
|
let server_data3 = send_something(&mut server, now);
|
||||||
assert_v4_path(&server_data3, true);
|
assert_v4_path(&server_data3, true);
|
||||||
|
@ -179,13 +182,15 @@ fn migrate_immediate() {
|
||||||
|
|
||||||
let client1 = send_something(&mut client, now);
|
let client1 = send_something(&mut client, now);
|
||||||
assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
|
assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &client1, now);
|
||||||
|
|
||||||
let client2 = send_something(&mut client, now);
|
let client2 = send_something(&mut client, now);
|
||||||
assert_v4_path(&client2, false); // Doesn't.
|
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).
|
// 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);
|
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);
|
assert_v6_path(&server2, true);
|
||||||
|
@ -193,13 +198,13 @@ fn migrate_immediate() {
|
||||||
// The second packet has no real effect, it just elicits an ACK.
|
// The second packet has no real effect, it just elicits an ACK.
|
||||||
let all_before = server.stats().frame_tx.all();
|
let all_before = server.stats().frame_tx.all();
|
||||||
let ack_before = server.stats().frame_tx.ack;
|
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!(server3.is_some());
|
||||||
assert_eq!(server.stats().frame_tx.all(), all_before + 1);
|
assert_eq!(server.stats().frame_tx.all(), all_before + 1);
|
||||||
assert_eq!(server.stats().frame_tx.ack, ack_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.
|
// Receiving a packet sent by the server before migration doesn't change path.
|
||||||
client.process_input(&server_delayed, now);
|
client.process_input(server_delayed, now);
|
||||||
// The client has sent two unpaced packets and this new path has no RTT estimate
|
// The client has sent two unpaced packets and this new path has no RTT estimate
|
||||||
// so this might be paced.
|
// so this might be paced.
|
||||||
let (client3, _t) = send_something_paced(&mut client, now, true);
|
let (client3, _t) = send_something_paced(&mut client, now, true);
|
||||||
|
@ -236,6 +241,7 @@ fn migrate_immediate_fail() {
|
||||||
|
|
||||||
let probe = client.process_output(now).dgram().unwrap();
|
let probe = client.process_output(now).dgram().unwrap();
|
||||||
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now);
|
||||||
|
|
||||||
// -1 because first PATH_CHALLENGE already sent above
|
// -1 because first PATH_CHALLENGE already sent above
|
||||||
for _ in 0..MAX_PATH_PROBES * 2 - 1 {
|
for _ in 0..MAX_PATH_PROBES * 2 - 1 {
|
||||||
|
@ -246,6 +252,7 @@ fn migrate_immediate_fail() {
|
||||||
let before = client.stats().frame_tx;
|
let before = client.stats().frame_tx;
|
||||||
let probe = client.process_output(now).dgram().unwrap();
|
let probe = client.process_output(now).dgram().unwrap();
|
||||||
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now);
|
||||||
let after = client.stats().frame_tx;
|
let after = client.stats().frame_tx;
|
||||||
assert_eq!(after.path_challenge, before.path_challenge + 1);
|
assert_eq!(after.path_challenge, before.path_challenge + 1);
|
||||||
assert_eq!(after.padding, before.padding + 1);
|
assert_eq!(after.padding, before.padding + 1);
|
||||||
|
@ -253,8 +260,9 @@ fn migrate_immediate_fail() {
|
||||||
|
|
||||||
// This might be a PTO, which will result in sending a probe.
|
// This might be a PTO, which will result in sending a probe.
|
||||||
if let Some(probe) = client.process_output(now).dgram() {
|
if let Some(probe) = client.process_output(now).dgram() {
|
||||||
assert_v4_path(&probe, false); // Contains PATH_CHALLENGE.
|
assert_v4_path(&probe, false); // Contains PING.
|
||||||
let after = client.stats().frame_tx;
|
let after = client.stats().frame_tx;
|
||||||
|
assert_eq!(after.path_challenge, before.path_challenge + 1);
|
||||||
assert_eq!(after.ping, before.ping + 1);
|
assert_eq!(after.ping, before.ping + 1);
|
||||||
assert_eq!(after.all(), before.all() + 3);
|
assert_eq!(after.all(), before.all() + 3);
|
||||||
}
|
}
|
||||||
|
@ -286,14 +294,15 @@ fn migrate_same() {
|
||||||
let probe = client.process_output(now).dgram().unwrap();
|
let probe = client.process_output(now).dgram().unwrap();
|
||||||
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
|
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now);
|
||||||
|
|
||||||
let resp = server.process(Some(&probe), now).dgram().unwrap();
|
let resp = server.process(Some(probe), now).dgram().unwrap();
|
||||||
assert_v6_path(&resp, true);
|
assert_v6_path(&resp, true);
|
||||||
assert_eq!(server.stats().frame_tx.path_response, 1);
|
assert_eq!(server.stats().frame_tx.path_response, 1);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 0);
|
assert_eq!(server.stats().frame_tx.path_challenge, 0);
|
||||||
|
|
||||||
// Everything continues happily.
|
// Everything continues happily.
|
||||||
client.process_input(&resp, now);
|
client.process_input(resp, now);
|
||||||
let contd = send_something(&mut client, now);
|
let contd = send_something(&mut client, now);
|
||||||
assert_v6_path(&contd, false);
|
assert_v6_path(&contd, false);
|
||||||
}
|
}
|
||||||
|
@ -312,6 +321,7 @@ fn migrate_same_fail() {
|
||||||
|
|
||||||
let probe = client.process_output(now).dgram().unwrap();
|
let probe = client.process_output(now).dgram().unwrap();
|
||||||
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
|
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now);
|
||||||
|
|
||||||
// -1 because first PATH_CHALLENGE already sent above
|
// -1 because first PATH_CHALLENGE already sent above
|
||||||
for _ in 0..MAX_PATH_PROBES * 2 - 1 {
|
for _ in 0..MAX_PATH_PROBES * 2 - 1 {
|
||||||
|
@ -322,6 +332,7 @@ fn migrate_same_fail() {
|
||||||
let before = client.stats().frame_tx;
|
let before = client.stats().frame_tx;
|
||||||
let probe = client.process_output(now).dgram().unwrap();
|
let probe = client.process_output(now).dgram().unwrap();
|
||||||
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
|
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now);
|
||||||
let after = client.stats().frame_tx;
|
let after = client.stats().frame_tx;
|
||||||
assert_eq!(after.path_challenge, before.path_challenge + 1);
|
assert_eq!(after.path_challenge, before.path_challenge + 1);
|
||||||
assert_eq!(after.padding, before.padding + 1);
|
assert_eq!(after.padding, before.padding + 1);
|
||||||
|
@ -329,8 +340,9 @@ fn migrate_same_fail() {
|
||||||
|
|
||||||
// This might be a PTO, which will result in sending a probe.
|
// This might be a PTO, which will result in sending a probe.
|
||||||
if let Some(probe) = client.process_output(now).dgram() {
|
if let Some(probe) = client.process_output(now).dgram() {
|
||||||
assert_v6_path(&probe, false); // Contains PATH_CHALLENGE.
|
assert_v6_path(&probe, false); // Contains PING.
|
||||||
let after = client.stats().frame_tx;
|
let after = client.stats().frame_tx;
|
||||||
|
assert_eq!(after.path_challenge, before.path_challenge + 1);
|
||||||
assert_eq!(after.ping, before.ping + 1);
|
assert_eq!(after.ping, before.ping + 1);
|
||||||
assert_eq!(after.all(), before.all() + 3);
|
assert_eq!(after.all(), before.all() + 3);
|
||||||
}
|
}
|
||||||
|
@ -368,11 +380,13 @@ fn migration(mut client: Connection) {
|
||||||
|
|
||||||
let probe = client.process_output(now).dgram().unwrap();
|
let probe = client.process_output(now).dgram().unwrap();
|
||||||
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now);
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
let probe_cid = ConnectionId::from(get_cid(&probe));
|
let probe_cid = ConnectionId::from(get_cid(&probe));
|
||||||
|
|
||||||
let resp = server.process(Some(&probe), now).dgram().unwrap();
|
let resp = server.process(Some(probe), now).dgram().unwrap();
|
||||||
assert_v4_path(&resp, true);
|
assert_v4_path(&resp, true);
|
||||||
|
assert_path_challenge_min_len(&server, &resp, now);
|
||||||
assert_eq!(server.stats().frame_tx.path_response, 1);
|
assert_eq!(server.stats().frame_tx.path_response, 1);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
||||||
|
|
||||||
|
@ -380,12 +394,12 @@ fn migration(mut client: Connection) {
|
||||||
let client_data = send_something(&mut client, now);
|
let client_data = send_something(&mut client, now);
|
||||||
assert_ne!(get_cid(&client_data), probe_cid);
|
assert_ne!(get_cid(&client_data), probe_cid);
|
||||||
assert_v6_path(&client_data, false);
|
assert_v6_path(&client_data, false);
|
||||||
server.process_input(&client_data, now);
|
server.process_input(client_data, now);
|
||||||
let server_data = send_something(&mut server, now);
|
let server_data = send_something(&mut server, now);
|
||||||
assert_v6_path(&server_data, false);
|
assert_v6_path(&server_data, false);
|
||||||
|
|
||||||
// Once the client receives the probe response, it migrates to the new path.
|
// Once the client receives the probe response, it migrates to the new path.
|
||||||
client.process_input(&resp, now);
|
client.process_input(resp, now);
|
||||||
assert_eq!(client.stats().frame_rx.path_challenge, 1);
|
assert_eq!(client.stats().frame_rx.path_challenge, 1);
|
||||||
let migrate_client = send_something(&mut client, now);
|
let migrate_client = send_something(&mut client, now);
|
||||||
assert_v4_path(&migrate_client, true); // Responds to server probe.
|
assert_v4_path(&migrate_client, true); // Responds to server probe.
|
||||||
|
@ -394,11 +408,12 @@ fn migration(mut client: Connection) {
|
||||||
// However, it will probe the old path again, even though it has just
|
// However, it will probe the old path again, even though it has just
|
||||||
// received a response to its last probe, because it needs to verify
|
// received a response to its last probe, because it needs to verify
|
||||||
// that the migration is genuine.
|
// that the migration is genuine.
|
||||||
server.process_input(&migrate_client, now);
|
server.process_input(migrate_client, now);
|
||||||
let stream_before = server.stats().frame_tx.stream;
|
let stream_before = server.stats().frame_tx.stream;
|
||||||
let probe_old_server = send_something(&mut server, now);
|
let probe_old_server = send_something(&mut server, now);
|
||||||
// This is just the double-check probe; no STREAM frames.
|
// This is just the double-check probe; no STREAM frames.
|
||||||
assert_v6_path(&probe_old_server, true);
|
assert_v6_path(&probe_old_server, true);
|
||||||
|
assert_path_challenge_min_len(&server, &probe_old_server, now);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 2);
|
assert_eq!(server.stats().frame_tx.path_challenge, 2);
|
||||||
assert_eq!(server.stats().frame_tx.stream, stream_before);
|
assert_eq!(server.stats().frame_tx.stream, stream_before);
|
||||||
|
|
||||||
|
@ -409,8 +424,8 @@ fn migration(mut client: Connection) {
|
||||||
assert_eq!(server.stats().frame_tx.stream, stream_before + 1);
|
assert_eq!(server.stats().frame_tx.stream, stream_before + 1);
|
||||||
|
|
||||||
// The client receives these checks and responds to the probe, but uses the new path.
|
// The client receives these checks and responds to the probe, but uses the new path.
|
||||||
client.process_input(&migrate_server, now);
|
client.process_input(migrate_server, now);
|
||||||
client.process_input(&probe_old_server, now);
|
client.process_input(probe_old_server, now);
|
||||||
let old_probe_resp = send_something(&mut client, now);
|
let old_probe_resp = send_something(&mut client, now);
|
||||||
assert_v6_path(&old_probe_resp, true);
|
assert_v6_path(&old_probe_resp, true);
|
||||||
let client_confirmation = client.process_output(now).dgram().unwrap();
|
let client_confirmation = client.process_output(now).dgram().unwrap();
|
||||||
|
@ -450,11 +465,11 @@ fn migration_client_empty_cid() {
|
||||||
/// Returns the packet containing `HANDSHAKE_DONE` from the server.
|
/// Returns the packet containing `HANDSHAKE_DONE` from the server.
|
||||||
fn fast_handshake(client: &mut Connection, server: &mut Connection) -> Option<Datagram> {
|
fn fast_handshake(client: &mut Connection, server: &mut Connection) -> Option<Datagram> {
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert!(maybe_authenticate(client));
|
assert!(maybe_authenticate(client));
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
server.process(dgram.as_ref(), now()).dgram()
|
server.process(dgram, now()).dgram()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preferred_address(hs_client: SocketAddr, hs_server: SocketAddr, preferred: SocketAddr) {
|
fn preferred_address(hs_client: SocketAddr, hs_server: SocketAddr, preferred: SocketAddr) {
|
||||||
|
@ -512,9 +527,10 @@ fn preferred_address(hs_client: SocketAddr, hs_server: SocketAddr, preferred: So
|
||||||
|
|
||||||
// The client is about to process HANDSHAKE_DONE.
|
// The client is about to process HANDSHAKE_DONE.
|
||||||
// It should start probing toward the server's preferred address.
|
// It should start probing toward the server's preferred address.
|
||||||
let probe = client.process(dgram.as_ref(), now()).dgram().unwrap();
|
let probe = client.process(dgram, now()).dgram().unwrap();
|
||||||
assert_toward_spa(&probe, true);
|
assert_toward_spa(&probe, true);
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now());
|
||||||
assert_ne!(client.process_output(now()).callback(), Duration::new(0, 0));
|
assert_ne!(client.process_output(now()).callback(), Duration::new(0, 0));
|
||||||
|
|
||||||
// Data continues on the main path for the client.
|
// Data continues on the main path for the client.
|
||||||
|
@ -522,28 +538,30 @@ fn preferred_address(hs_client: SocketAddr, hs_server: SocketAddr, preferred: So
|
||||||
assert_orig_path(&data, false);
|
assert_orig_path(&data, false);
|
||||||
|
|
||||||
// The server responds to the probe.
|
// The server responds to the probe.
|
||||||
let resp = server.process(Some(&probe), now()).dgram().unwrap();
|
let resp = server.process(Some(probe), now()).dgram().unwrap();
|
||||||
assert_from_spa(&resp, true);
|
assert_from_spa(&resp, true);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&server, &resp, now());
|
||||||
assert_eq!(server.stats().frame_tx.path_response, 1);
|
assert_eq!(server.stats().frame_tx.path_response, 1);
|
||||||
|
|
||||||
// Data continues on the main path for the server.
|
// Data continues on the main path for the server.
|
||||||
server.process_input(&data, now());
|
server.process_input(data, now());
|
||||||
let data = send_something(&mut server, now());
|
let data = send_something(&mut server, now());
|
||||||
assert_orig_path(&data, false);
|
assert_orig_path(&data, false);
|
||||||
|
|
||||||
// Client gets the probe response back and it migrates.
|
// Client gets the probe response back and it migrates.
|
||||||
client.process_input(&resp, now());
|
client.process_input(resp, now());
|
||||||
client.process_input(&data, now());
|
client.process_input(data, now());
|
||||||
let data = send_something(&mut client, now());
|
let data = send_something(&mut client, now());
|
||||||
assert_toward_spa(&data, true);
|
assert_toward_spa(&data, true);
|
||||||
assert_eq!(client.stats().frame_tx.stream, 2);
|
assert_eq!(client.stats().frame_tx.stream, 2);
|
||||||
assert_eq!(client.stats().frame_tx.path_response, 1);
|
assert_eq!(client.stats().frame_tx.path_response, 1);
|
||||||
|
|
||||||
// The server sees the migration and probes the old path.
|
// The server sees the migration and probes the old path.
|
||||||
let probe = server.process(Some(&data), now()).dgram().unwrap();
|
let probe = server.process(Some(data), now()).dgram().unwrap();
|
||||||
assert_orig_path(&probe, true);
|
assert_orig_path(&probe, true);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 2);
|
assert_eq!(server.stats().frame_tx.path_challenge, 2);
|
||||||
|
assert_path_challenge_min_len(&server, &probe, now());
|
||||||
|
|
||||||
// But data now goes on the new path.
|
// But data now goes on the new path.
|
||||||
let data = send_something(&mut server, now());
|
let data = send_something(&mut server, now());
|
||||||
|
@ -583,7 +601,7 @@ fn expect_no_migration(client: &mut Connection, server: &mut Connection) {
|
||||||
let dgram = fast_handshake(client, server);
|
let dgram = fast_handshake(client, server);
|
||||||
|
|
||||||
// The client won't probe now, though it could; it remains idle.
|
// The client won't probe now, though it could; it remains idle.
|
||||||
let out = client.process(dgram.as_ref(), now());
|
let out = client.process(dgram, now());
|
||||||
assert_ne!(out.callback(), Duration::new(0, 0));
|
assert_ne!(out.callback(), Duration::new(0, 0));
|
||||||
|
|
||||||
// Data continues on the main path for the client.
|
// Data continues on the main path for the client.
|
||||||
|
@ -708,14 +726,14 @@ fn migration_invalid_state() {
|
||||||
assert!(client
|
assert!(client
|
||||||
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
|
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
|
||||||
.is_err());
|
.is_err());
|
||||||
let close = client.process(None, now()).dgram();
|
let close = client.process_output(now()).dgram();
|
||||||
|
|
||||||
let dgram = server.process(close.as_ref(), now()).dgram();
|
let dgram = server.process(close, now()).dgram();
|
||||||
assert!(server
|
assert!(server
|
||||||
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
|
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
|
||||||
.is_err());
|
.is_err());
|
||||||
|
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert!(client
|
assert!(client
|
||||||
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
|
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
|
||||||
.is_err());
|
.is_err());
|
||||||
|
@ -814,7 +832,7 @@ fn retire_all() {
|
||||||
|
|
||||||
let new_cid_before = client.stats().frame_rx.new_connection_id;
|
let new_cid_before = client.stats().frame_rx.new_connection_id;
|
||||||
let retire_cid_before = client.stats().frame_tx.retire_connection_id;
|
let retire_cid_before = client.stats().frame_tx.retire_connection_id;
|
||||||
client.process_input(&ncid, now());
|
client.process_input(ncid, now());
|
||||||
let retire = send_something(&mut client, now());
|
let retire = send_something(&mut client, now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client.stats().frame_rx.new_connection_id,
|
client.stats().frame_rx.new_connection_id,
|
||||||
|
@ -854,6 +872,7 @@ fn retire_prior_to_migration_failure() {
|
||||||
let probe = client.process_output(now()).dgram().unwrap();
|
let probe = client.process_output(now()).dgram().unwrap();
|
||||||
assert_v4_path(&probe, true);
|
assert_v4_path(&probe, true);
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now());
|
||||||
let probe_cid = ConnectionId::from(get_cid(&probe));
|
let probe_cid = ConnectionId::from(get_cid(&probe));
|
||||||
assert_ne!(original_cid, probe_cid);
|
assert_ne!(original_cid, probe_cid);
|
||||||
|
|
||||||
|
@ -861,17 +880,18 @@ fn retire_prior_to_migration_failure() {
|
||||||
// retire all of the available connection IDs.
|
// retire all of the available connection IDs.
|
||||||
let retire_all = send_with_extra(&mut server, RetireAll { cid_gen }, now());
|
let retire_all = send_with_extra(&mut server, RetireAll { cid_gen }, now());
|
||||||
|
|
||||||
let resp = server.process(Some(&probe), now()).dgram().unwrap();
|
let resp = server.process(Some(probe), now()).dgram().unwrap();
|
||||||
assert_v4_path(&resp, true);
|
assert_v4_path(&resp, true);
|
||||||
assert_eq!(server.stats().frame_tx.path_response, 1);
|
assert_eq!(server.stats().frame_tx.path_response, 1);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&server, &resp, now());
|
||||||
|
|
||||||
// Have the client receive the NEW_CONNECTION_ID with Retire Prior To.
|
// Have the client receive the NEW_CONNECTION_ID with Retire Prior To.
|
||||||
client.process_input(&retire_all, now());
|
client.process_input(retire_all, now());
|
||||||
// This packet contains the probe response, which should be fine, but it
|
// This packet contains the probe response, which should be fine, but it
|
||||||
// also includes PATH_CHALLENGE for the new path, and the client can't
|
// also includes PATH_CHALLENGE for the new path, and the client can't
|
||||||
// respond without a connection ID. We treat this as a connection error.
|
// respond without a connection ID. We treat this as a connection error.
|
||||||
client.process_input(&resp, now());
|
client.process_input(resp, now());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
client.state(),
|
client.state(),
|
||||||
State::Closing {
|
State::Closing {
|
||||||
|
@ -907,6 +927,7 @@ fn retire_prior_to_migration_success() {
|
||||||
let probe = client.process_output(now()).dgram().unwrap();
|
let probe = client.process_output(now()).dgram().unwrap();
|
||||||
assert_v4_path(&probe, true);
|
assert_v4_path(&probe, true);
|
||||||
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
assert_eq!(client.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&client, &probe, now());
|
||||||
let probe_cid = ConnectionId::from(get_cid(&probe));
|
let probe_cid = ConnectionId::from(get_cid(&probe));
|
||||||
assert_ne!(original_cid, probe_cid);
|
assert_ne!(original_cid, probe_cid);
|
||||||
|
|
||||||
|
@ -914,15 +935,16 @@ fn retire_prior_to_migration_success() {
|
||||||
// retire all of the available connection IDs.
|
// retire all of the available connection IDs.
|
||||||
let retire_all = send_with_extra(&mut server, RetireAll { cid_gen }, now());
|
let retire_all = send_with_extra(&mut server, RetireAll { cid_gen }, now());
|
||||||
|
|
||||||
let resp = server.process(Some(&probe), now()).dgram().unwrap();
|
let resp = server.process(Some(probe), now()).dgram().unwrap();
|
||||||
assert_v4_path(&resp, true);
|
assert_v4_path(&resp, true);
|
||||||
assert_eq!(server.stats().frame_tx.path_response, 1);
|
assert_eq!(server.stats().frame_tx.path_response, 1);
|
||||||
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
assert_eq!(server.stats().frame_tx.path_challenge, 1);
|
||||||
|
assert_path_challenge_min_len(&server, &resp, now());
|
||||||
|
|
||||||
// Have the client receive the NEW_CONNECTION_ID with Retire Prior To second.
|
// Have the client receive the NEW_CONNECTION_ID with Retire Prior To second.
|
||||||
// As this occurs in a very specific order, migration succeeds.
|
// As this occurs in a very specific order, migration succeeds.
|
||||||
client.process_input(&resp, now());
|
client.process_input(resp, now());
|
||||||
client.process_input(&retire_all, now());
|
client.process_input(retire_all, now());
|
||||||
|
|
||||||
// Migration succeeds and the new path gets the last connection ID.
|
// Migration succeeds and the new path gets the last connection ID.
|
||||||
let dgram = send_something(&mut client, now());
|
let dgram = send_something(&mut client, now());
|
||||||
|
@ -952,12 +974,12 @@ fn error_on_new_path_with_no_connection_id() {
|
||||||
Rc::new(RefCell::new(CountingConnectionIdGenerator::default()));
|
Rc::new(RefCell::new(CountingConnectionIdGenerator::default()));
|
||||||
let retire_all = send_with_extra(&mut server, RetireAll { cid_gen }, now());
|
let retire_all = send_with_extra(&mut server, RetireAll { cid_gen }, now());
|
||||||
|
|
||||||
client.process_input(&retire_all, now());
|
client.process_input(retire_all, now());
|
||||||
|
|
||||||
let garbage = send_with_extra(&mut server, GarbageWriter {}, now());
|
let garbage = send_with_extra(&mut server, GarbageWriter {}, now());
|
||||||
|
|
||||||
let dgram = change_path(&garbage, DEFAULT_ADDR_V4);
|
let dgram = change_path(&garbage, DEFAULT_ADDR_V4);
|
||||||
client.process_input(&dgram, now());
|
client.process_input(dgram, now());
|
||||||
|
|
||||||
// See issue #1697. We had a crash when the client had a temporary path and
|
// See issue #1697. We had a crash when the client had a temporary path and
|
||||||
// process_output is called.
|
// process_output is called.
|
||||||
|
@ -972,7 +994,7 @@ fn error_on_new_path_with_no_connection_id() {
|
||||||
));
|
));
|
||||||
// Wait until the connection is closed.
|
// Wait until the connection is closed.
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
now += client.process(None, now).callback();
|
now += client.process_output(now).callback();
|
||||||
_ = client.process_output(now);
|
_ = client.process_output(now);
|
||||||
// No closing frames should be sent, and the connection should be closed.
|
// No closing frames should be sent, and the connection should be closed.
|
||||||
assert_eq!(client.stats().frame_tx.connection_close, closing_frames);
|
assert_eq!(client.stats().frame_tx.connection_close, closing_frames);
|
||||||
|
|
|
@ -30,7 +30,7 @@ use crate::{
|
||||||
stats::{FrameStats, Stats, MAX_PTO_COUNTS},
|
stats::{FrameStats, Stats, MAX_PTO_COUNTS},
|
||||||
tparams::{DISABLE_MIGRATION, GREASE_QUIC_BIT},
|
tparams::{DISABLE_MIGRATION, GREASE_QUIC_BIT},
|
||||||
ConnectionIdDecoder, ConnectionIdGenerator, ConnectionParameters, Error, StreamId, StreamType,
|
ConnectionIdDecoder, ConnectionIdGenerator, ConnectionParameters, Error, StreamId, StreamType,
|
||||||
Version,
|
Version, MIN_INITIAL_PACKET_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
// All the tests.
|
// All the tests.
|
||||||
|
@ -208,7 +208,7 @@ fn handshake_with_modifier(
|
||||||
if should_ping {
|
if should_ping {
|
||||||
a.test_frame_writer = Some(Box::new(PingWriter {}));
|
a.test_frame_writer = Some(Box::new(PingWriter {}));
|
||||||
}
|
}
|
||||||
let output = a.process(input.as_ref(), now).dgram();
|
let output = a.process(input, now).dgram();
|
||||||
if should_ping {
|
if should_ping {
|
||||||
a.test_frame_writer = None;
|
a.test_frame_writer = None;
|
||||||
did_ping[a.role()] = true;
|
did_ping[a.role()] = true;
|
||||||
|
@ -219,7 +219,7 @@ fn handshake_with_modifier(
|
||||||
mem::swap(&mut a, &mut b);
|
mem::swap(&mut a, &mut b);
|
||||||
}
|
}
|
||||||
if let Some(d) = input {
|
if let Some(d) = input {
|
||||||
a.process_input(&d, now);
|
a.process_input(d, now);
|
||||||
}
|
}
|
||||||
now
|
now
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ fn exchange_ticket(
|
||||||
server.send_ticket(now, &[]).expect("can send ticket");
|
server.send_ticket(now, &[]).expect("can send ticket");
|
||||||
let ticket = server.process_output(now).dgram();
|
let ticket = server.process_output(now).dgram();
|
||||||
assert!(ticket.is_some());
|
assert!(ticket.is_some());
|
||||||
client.process_input(&ticket.unwrap(), now);
|
client.process_input(ticket.unwrap(), now);
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
get_tokens(client).pop().expect("should have token")
|
get_tokens(client).pop().expect("should have token")
|
||||||
}
|
}
|
||||||
|
@ -397,7 +397,7 @@ fn fill_cwnd(c: &mut Connection, stream: StreamId, mut now: Instant) -> (Vec<Dat
|
||||||
|
|
||||||
qtrace!(
|
qtrace!(
|
||||||
"fill_cwnd sent {} bytes",
|
"fill_cwnd sent {} bytes",
|
||||||
total_dgrams.iter().map(|d| d.len()).sum::<usize>()
|
total_dgrams.iter().map(Datagram::len).sum::<usize>()
|
||||||
);
|
);
|
||||||
(total_dgrams, now)
|
(total_dgrams, now)
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,7 @@ fn increase_cwnd(
|
||||||
let pkt = sender.process_output(now);
|
let pkt = sender.process_output(now);
|
||||||
match pkt {
|
match pkt {
|
||||||
Output::Datagram(dgram) => {
|
Output::Datagram(dgram) => {
|
||||||
receiver.process_input(&dgram, now + DEFAULT_RTT / 2);
|
receiver.process_input(dgram, now + DEFAULT_RTT / 2);
|
||||||
}
|
}
|
||||||
Output::Callback(t) => {
|
Output::Callback(t) => {
|
||||||
if t < DEFAULT_RTT {
|
if t < DEFAULT_RTT {
|
||||||
|
@ -432,7 +432,7 @@ fn increase_cwnd(
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
let ack = receiver.process_output(now).dgram();
|
let ack = receiver.process_output(now).dgram();
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
sender.process_input(&ack.unwrap(), now);
|
sender.process_input(ack.unwrap(), now);
|
||||||
now
|
now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ where
|
||||||
let in_dgrams = in_dgrams.into_iter();
|
let in_dgrams = in_dgrams.into_iter();
|
||||||
qdebug!([dest], "ack_bytes {} datagrams", in_dgrams.len());
|
qdebug!([dest], "ack_bytes {} datagrams", in_dgrams.len());
|
||||||
for dgram in in_dgrams {
|
for dgram in in_dgrams {
|
||||||
dest.process_input(&dgram, now);
|
dest.process_input(dgram, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -524,7 +524,7 @@ fn induce_persistent_congestion(
|
||||||
|
|
||||||
// An ACK for the third PTO causes persistent congestion.
|
// An ACK for the third PTO causes persistent congestion.
|
||||||
let s_ack = ack_bytes(server, stream, c_tx_dgrams, now);
|
let s_ack = ack_bytes(server, stream, c_tx_dgrams, now);
|
||||||
client.process_input(&s_ack, now);
|
client.process_input(s_ack, now);
|
||||||
assert_eq!(cwnd(client), cwnd_min(client));
|
assert_eq!(cwnd(client), cwnd_min(client));
|
||||||
now
|
now
|
||||||
}
|
}
|
||||||
|
@ -635,7 +635,7 @@ fn send_with_modifier_and_receive(
|
||||||
modifier: fn(Datagram) -> Option<Datagram>,
|
modifier: fn(Datagram) -> Option<Datagram>,
|
||||||
) -> Option<Datagram> {
|
) -> Option<Datagram> {
|
||||||
let dgram = send_something_with_modifier(sender, now, modifier);
|
let dgram = send_something_with_modifier(sender, now, modifier);
|
||||||
receiver.process(Some(&dgram), now).dgram()
|
receiver.process(Some(dgram), now).dgram()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send something on a stream from `sender` to `receiver`.
|
/// Send something on a stream from `sender` to `receiver`.
|
||||||
|
@ -669,6 +669,27 @@ fn assert_default_stats(stats: &Stats) {
|
||||||
assert_eq!(stats.frame_tx, dflt_frames);
|
assert_eq!(stats.frame_tx, dflt_frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assert_path_challenge_min_len(c: &Connection, d: &Datagram, now: Instant) {
|
||||||
|
let path = c.paths.find_path(
|
||||||
|
d.source(),
|
||||||
|
d.destination(),
|
||||||
|
c.conn_params.get_cc_algorithm(),
|
||||||
|
c.conn_params.pacing_enabled(),
|
||||||
|
now,
|
||||||
|
);
|
||||||
|
if path.borrow().amplification_limit() < path.borrow().plpmtu() {
|
||||||
|
// If the amplification limit is less than the PLPMTU, then the path
|
||||||
|
// challenge will not have been padded.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
d.len() >= MIN_INITIAL_PACKET_SIZE,
|
||||||
|
"{} < {}",
|
||||||
|
d.len(),
|
||||||
|
MIN_INITIAL_PACKET_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_client() {
|
fn create_client() {
|
||||||
let client = default_client();
|
let client = default_client();
|
||||||
|
|
|
@ -26,7 +26,7 @@ fn no_encryption() {
|
||||||
let client_pkt = client.process_output(now()).dgram().unwrap();
|
let client_pkt = client.process_output(now()).dgram().unwrap();
|
||||||
assert!(client_pkt[..client_pkt.len() - AEAD_NULL_TAG.len()].ends_with(DATA_CLIENT));
|
assert!(client_pkt[..client_pkt.len() - AEAD_NULL_TAG.len()].ends_with(DATA_CLIENT));
|
||||||
|
|
||||||
server.process_input(&client_pkt, now());
|
server.process_input(client_pkt, now());
|
||||||
let mut buf = vec![0; 100];
|
let mut buf = vec![0; 100];
|
||||||
let (len, _) = server.stream_recv(stream_id, &mut buf).unwrap();
|
let (len, _) = server.stream_recv(stream_id, &mut buf).unwrap();
|
||||||
assert_eq!(len, DATA_CLIENT.len());
|
assert_eq!(len, DATA_CLIENT.len());
|
||||||
|
@ -35,7 +35,7 @@ fn no_encryption() {
|
||||||
let server_pkt = server.process_output(now()).dgram().unwrap();
|
let server_pkt = server.process_output(now()).dgram().unwrap();
|
||||||
assert!(server_pkt[..server_pkt.len() - AEAD_NULL_TAG.len()].ends_with(DATA_SERVER));
|
assert!(server_pkt[..server_pkt.len() - AEAD_NULL_TAG.len()].ends_with(DATA_SERVER));
|
||||||
|
|
||||||
client.process_input(&server_pkt, now());
|
client.process_input(server_pkt, now());
|
||||||
let (len, _) = client.stream_recv(stream_id, &mut buf).unwrap();
|
let (len, _) = client.stream_recv(stream_id, &mut buf).unwrap();
|
||||||
assert_eq!(len, DATA_SERVER.len());
|
assert_eq!(len, DATA_SERVER.len());
|
||||||
assert_eq!(&buf[..len], DATA_SERVER);
|
assert_eq!(&buf[..len], DATA_SERVER);
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn receive_stream() {
|
||||||
assert_eq!(MESSAGE.len(), client.stream_send(id, MESSAGE).unwrap());
|
assert_eq!(MESSAGE.len(), client.stream_send(id, MESSAGE).unwrap());
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
|
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server
|
server
|
||||||
.stream_priority(
|
.stream_priority(
|
||||||
|
@ -83,7 +83,7 @@ fn relative() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
// The "id_normal" stream will get a `NewStream` event, but no data.
|
// The "id_normal" stream will get a `NewStream` event, but no data.
|
||||||
for e in server.events() {
|
for e in server.events() {
|
||||||
|
@ -114,7 +114,7 @@ fn reprioritize() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
// The "id_normal" stream will get a `NewStream` event, but no data.
|
// The "id_normal" stream will get a `NewStream` event, but no data.
|
||||||
for e in server.events() {
|
for e in server.events() {
|
||||||
|
@ -133,7 +133,7 @@ fn reprioritize() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
for e in server.events() {
|
for e in server.events() {
|
||||||
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
|
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
|
||||||
|
@ -164,7 +164,7 @@ fn repairing_loss() {
|
||||||
let _lost = client.process_output(now).dgram();
|
let _lost = client.process_output(now).dgram();
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
match client.process_output(now) {
|
match client.process_output(now) {
|
||||||
Output::Datagram(d) => server.process_input(&d, now),
|
Output::Datagram(d) => server.process_input(d, now),
|
||||||
Output::Callback(delay) => now += delay,
|
Output::Callback(delay) => now += delay,
|
||||||
Output::None => unreachable!(),
|
Output::None => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -177,9 +177,9 @@ fn repairing_loss() {
|
||||||
let id_normal = client.stream_create(StreamType::UniDi).unwrap();
|
let id_normal = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
fill_stream(&mut client, id_normal);
|
fill_stream(&mut client, id_normal);
|
||||||
|
|
||||||
let dgram = client.process(ack.as_ref(), now).dgram();
|
let dgram = client.process(ack, now).dgram();
|
||||||
assert_eq!(client.stats().lost, 1); // Client should have noticed the loss.
|
assert_eq!(client.stats().lost, 1); // Client should have noticed the loss.
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
// Only the low priority stream has data as the retransmission of the data from
|
// 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.
|
// the lost packet is now more important than new data from the high priority stream.
|
||||||
|
@ -195,7 +195,7 @@ fn repairing_loss() {
|
||||||
// the retransmitted data into a second packet, it will also contain data from the
|
// the retransmitted data into a second packet, it will also contain data from the
|
||||||
// normal priority stream.
|
// normal priority stream.
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
assert!(server.events().any(
|
assert!(server.events().any(
|
||||||
|e| matches!(e, ConnectionEvent::RecvStreamReadable { stream_id } if stream_id == id_normal),
|
|e| matches!(e, ConnectionEvent::RecvStreamReadable { stream_id } if stream_id == id_normal),
|
||||||
));
|
));
|
||||||
|
@ -210,8 +210,8 @@ fn critical() {
|
||||||
// Rather than connect, send stream data in 0.5-RTT.
|
// Rather than connect, send stream data in 0.5-RTT.
|
||||||
// That allows this to test that critical streams pre-empt most frame types.
|
// That allows this to test that critical streams pre-empt most frame types.
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
|
|
||||||
let id = server.stream_create(StreamType::UniDi).unwrap();
|
let id = server.stream_create(StreamType::UniDi).unwrap();
|
||||||
|
@ -238,8 +238,8 @@ fn critical() {
|
||||||
assert_eq!(stats_after.handshake_done, 0);
|
assert_eq!(stats_after.handshake_done, 0);
|
||||||
|
|
||||||
// Complete the handshake.
|
// Complete the handshake.
|
||||||
let dgram = client.process(dgram.as_ref(), now).dgram();
|
let dgram = client.process(dgram, now).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
// Critical beats everything but HANDSHAKE_DONE.
|
// Critical beats everything but HANDSHAKE_DONE.
|
||||||
let stats_before = server.stats().frame_tx;
|
let stats_before = server.stats().frame_tx;
|
||||||
|
@ -261,8 +261,8 @@ fn important() {
|
||||||
// Rather than connect, send stream data in 0.5-RTT.
|
// Rather than connect, send stream data in 0.5-RTT.
|
||||||
// That allows this to test that important streams pre-empt most frame types.
|
// That allows this to test that important streams pre-empt most frame types.
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
|
|
||||||
let id = server.stream_create(StreamType::UniDi).unwrap();
|
let id = server.stream_create(StreamType::UniDi).unwrap();
|
||||||
|
@ -290,8 +290,8 @@ fn important() {
|
||||||
assert_eq!(stats_after.stream, stats_before.stream + 1);
|
assert_eq!(stats_after.stream, stats_before.stream + 1);
|
||||||
|
|
||||||
// Complete the handshake.
|
// Complete the handshake.
|
||||||
let dgram = client.process(dgram.as_ref(), now).dgram();
|
let dgram = client.process(dgram, now).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
// Important beats everything but flow control.
|
// Important beats everything but flow control.
|
||||||
let stats_before = server.stats().frame_tx;
|
let stats_before = server.stats().frame_tx;
|
||||||
|
@ -314,8 +314,8 @@ fn high_normal() {
|
||||||
// Rather than connect, send stream data in 0.5-RTT.
|
// Rather than connect, send stream data in 0.5-RTT.
|
||||||
// That allows this to test that important streams pre-empt most frame types.
|
// That allows this to test that important streams pre-empt most frame types.
|
||||||
let dgram = client.process_output(now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
|
|
||||||
let id = server.stream_create(StreamType::UniDi).unwrap();
|
let id = server.stream_create(StreamType::UniDi).unwrap();
|
||||||
|
@ -343,8 +343,8 @@ fn high_normal() {
|
||||||
assert_eq!(stats_after.stream, stats_before.stream + 1);
|
assert_eq!(stats_after.stream, stats_before.stream + 1);
|
||||||
|
|
||||||
// Complete the handshake.
|
// Complete the handshake.
|
||||||
let dgram = client.process(dgram.as_ref(), now).dgram();
|
let dgram = client.process(dgram, now).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
// High or Normal doesn't beat NEW_CONNECTION_ID,
|
// High or Normal doesn't beat NEW_CONNECTION_ID,
|
||||||
// but they beat CRYPTO/NEW_TOKEN.
|
// but they beat CRYPTO/NEW_TOKEN.
|
||||||
|
|
|
@ -45,7 +45,7 @@ fn pto_works_basic() {
|
||||||
|
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let res = client.process(None, now);
|
let res = client.process_output(now);
|
||||||
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
|
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
|
||||||
assert_eq!(res, Output::Callback(idle_timeout));
|
assert_eq!(res, Output::Callback(idle_timeout));
|
||||||
|
|
||||||
|
@ -59,19 +59,19 @@ fn pto_works_basic() {
|
||||||
|
|
||||||
// Send a packet after some time.
|
// Send a packet after some time.
|
||||||
now += Duration::from_secs(10);
|
now += Duration::from_secs(10);
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
assert!(out.dgram().is_some());
|
assert!(out.dgram().is_some());
|
||||||
|
|
||||||
// Nothing to do, should return callback
|
// Nothing to do, should return callback
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
assert!(matches!(out, Output::Callback(_)));
|
assert!(matches!(out, Output::Callback(_)));
|
||||||
|
|
||||||
// One second later, it should want to send PTO packet
|
// One second later, it should want to send PTO packet
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
|
|
||||||
let stream_before = server.stats().frame_rx.stream;
|
let stream_before = server.stats().frame_rx.stream;
|
||||||
server.process_input(&out.dgram().unwrap(), now);
|
server.process_input(out.dgram().unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.stream, stream_before + 2);
|
assert_eq!(server.stats().frame_rx.stream, stream_before + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ fn pto_works_full_cwnd() {
|
||||||
// Both datagrams contain one or more STREAM frames.
|
// Both datagrams contain one or more STREAM frames.
|
||||||
for d in dgrams {
|
for d in dgrams {
|
||||||
let stream_before = server.stats().frame_rx.stream;
|
let stream_before = server.stats().frame_rx.stream;
|
||||||
server.process_input(&d, now);
|
server.process_input(d, now);
|
||||||
assert!(server.stats().frame_rx.stream > stream_before);
|
assert!(server.stats().frame_rx.stream > stream_before);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,49 +115,49 @@ fn pto_works_ping() {
|
||||||
let pkt3 = send_something(&mut client, now);
|
let pkt3 = send_something(&mut client, now);
|
||||||
|
|
||||||
// Nothing to do, should return callback
|
// Nothing to do, should return callback
|
||||||
let cb = client.process(None, now).callback();
|
let cb = client.process_output(now).callback();
|
||||||
// The PTO timer is calculated with:
|
// The PTO timer is calculated with:
|
||||||
// RTT + max(rttvar * 4, GRANULARITY) + max_ack_delay
|
// RTT + max(rttvar * 4, GRANULARITY) + max_ack_delay
|
||||||
// With zero RTT and rttvar, max_ack_delay is minimum too (GRANULARITY)
|
// With zero RTT and rttvar, max_ack_delay is minimum too (GRANULARITY)
|
||||||
assert_eq!(cb, GRANULARITY * 2);
|
assert_eq!(cb, GRANULARITY * 2);
|
||||||
|
|
||||||
// Process these by server, skipping pkt0
|
// Process these by server, skipping pkt0
|
||||||
let srv0 = server.process(Some(&pkt1), now).dgram();
|
let srv0 = server.process(Some(pkt1), now).dgram();
|
||||||
assert!(srv0.is_some()); // ooo, ack client pkt1
|
assert!(srv0.is_some()); // ooo, ack client pkt1
|
||||||
|
|
||||||
now += Duration::from_millis(20);
|
now += Duration::from_millis(20);
|
||||||
|
|
||||||
// process pkt2 (immediate ack because last ack was more than an RTT ago; RTT=0)
|
// process pkt2 (immediate ack because last ack was more than an RTT ago; RTT=0)
|
||||||
let srv1 = server.process(Some(&pkt2), now).dgram();
|
let srv1 = server.process(Some(pkt2), now).dgram();
|
||||||
assert!(srv1.is_some()); // this is now dropped
|
assert!(srv1.is_some()); // this is now dropped
|
||||||
|
|
||||||
now += Duration::from_millis(20);
|
now += Duration::from_millis(20);
|
||||||
// process pkt3 (acked for same reason)
|
// process pkt3 (acked for same reason)
|
||||||
let srv2 = server.process(Some(&pkt3), now).dgram();
|
let srv2 = server.process(Some(pkt3), now).dgram();
|
||||||
// ack client pkt 2 & 3
|
// ack client pkt 2 & 3
|
||||||
assert!(srv2.is_some());
|
assert!(srv2.is_some());
|
||||||
|
|
||||||
// client processes ack
|
// client processes ack
|
||||||
let pkt4 = client.process(srv2.as_ref(), now).dgram();
|
let pkt4 = client.process(srv2, now).dgram();
|
||||||
// client resends data from pkt0
|
// client resends data from pkt0
|
||||||
assert!(pkt4.is_some());
|
assert!(pkt4.is_some());
|
||||||
|
|
||||||
// server sees ooo pkt0 and generates immediate ack
|
// server sees ooo pkt0 and generates immediate ack
|
||||||
let srv3 = server.process(Some(&pkt0), now).dgram();
|
let srv3 = server.process(Some(pkt0), now).dgram();
|
||||||
assert!(srv3.is_some());
|
assert!(srv3.is_some());
|
||||||
|
|
||||||
// Accept the acknowledgment.
|
// Accept the acknowledgment.
|
||||||
let pkt5 = client.process(srv3.as_ref(), now).dgram();
|
let pkt5 = client.process(srv3, now).dgram();
|
||||||
assert!(pkt5.is_none());
|
assert!(pkt5.is_none());
|
||||||
|
|
||||||
now += Duration::from_millis(70);
|
now += Duration::from_millis(70);
|
||||||
// PTO expires. No unacked data. Only send PING.
|
// PTO expires. No unacked data. Only send PING.
|
||||||
let client_pings = client.stats().frame_tx.ping;
|
let client_pings = client.stats().frame_tx.ping;
|
||||||
let pkt6 = client.process(None, now).dgram();
|
let pkt6 = client.process_output(now).dgram();
|
||||||
assert_eq!(client.stats().frame_tx.ping, client_pings + 1);
|
assert_eq!(client.stats().frame_tx.ping, client_pings + 1);
|
||||||
|
|
||||||
let server_pings = server.stats().frame_rx.ping;
|
let server_pings = server.stats().frame_rx.ping;
|
||||||
server.process_input(&pkt6.unwrap(), now);
|
server.process_input(pkt6.unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.ping, server_pings + 1);
|
assert_eq!(server.stats().frame_rx.ping, server_pings + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,40 +168,40 @@ fn pto_initial() {
|
||||||
|
|
||||||
qdebug!("---- client: generate CH");
|
qdebug!("---- client: generate CH");
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let pkt1 = client.process(None, now).dgram();
|
let pkt1 = client.process_output(now).dgram();
|
||||||
assert!(pkt1.is_some());
|
assert!(pkt1.is_some());
|
||||||
assert_eq!(pkt1.clone().unwrap().len(), client.plpmtu());
|
assert_eq!(pkt1.clone().unwrap().len(), client.plpmtu());
|
||||||
|
|
||||||
let delay = client.process(None, now).callback();
|
let delay = client.process_output(now).callback();
|
||||||
assert_eq!(delay, INITIAL_PTO);
|
assert_eq!(delay, INITIAL_PTO);
|
||||||
|
|
||||||
// Resend initial after PTO.
|
// Resend initial after PTO.
|
||||||
now += delay;
|
now += delay;
|
||||||
let pkt2 = client.process(None, now).dgram();
|
let pkt2 = client.process_output(now).dgram();
|
||||||
assert!(pkt2.is_some());
|
assert!(pkt2.is_some());
|
||||||
assert_eq!(pkt2.unwrap().len(), client.plpmtu());
|
assert_eq!(pkt2.unwrap().len(), client.plpmtu());
|
||||||
|
|
||||||
let delay = client.process(None, now).callback();
|
let delay = client.process_output(now).callback();
|
||||||
// PTO has doubled.
|
// PTO has doubled.
|
||||||
assert_eq!(delay, INITIAL_PTO * 2);
|
assert_eq!(delay, INITIAL_PTO * 2);
|
||||||
|
|
||||||
// Server process the first initial pkt.
|
// Server process the first initial pkt.
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let out = server.process(pkt1.as_ref(), now).dgram();
|
let out = server.process(pkt1, now).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
|
|
||||||
// Client receives ack for the first initial packet as well a Handshake packet.
|
// Client receives ack for the first initial packet as well a Handshake packet.
|
||||||
// After the handshake packet the initial keys and the crypto stream for the initial
|
// After the handshake packet the initial keys and the crypto stream for the initial
|
||||||
// packet number space will be discarded.
|
// packet number space will be discarded.
|
||||||
// Here only an ack for the Handshake packet will be sent.
|
// Here only an ack for the Handshake packet will be sent.
|
||||||
let out = client.process(out.as_ref(), now).dgram();
|
let out = client.process(out, now).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
|
|
||||||
// We do not have PTO for the resent initial packet any more, but
|
// We do not have PTO for the resent initial packet any more, but
|
||||||
// the Handshake PTO timer should be armed. As the RTT is apparently
|
// the Handshake PTO timer should be armed. As the RTT is apparently
|
||||||
// the same as the initial PTO value, and there is only one sample,
|
// the same as the initial PTO value, and there is only one sample,
|
||||||
// the PTO will be 3x the INITIAL PTO.
|
// the PTO will be 3x the INITIAL PTO.
|
||||||
let delay = client.process(None, now).callback();
|
let delay = client.process_output(now).callback();
|
||||||
assert_eq!(delay, INITIAL_PTO * 3);
|
assert_eq!(delay, INITIAL_PTO * 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,37 +215,37 @@ fn pto_handshake_complete() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let pkt = client.process(None, now).dgram();
|
let pkt = client.process_output(now).dgram();
|
||||||
assert_initial(pkt.as_ref().unwrap(), false);
|
assert_initial(pkt.as_ref().unwrap(), false);
|
||||||
let cb = client.process(None, now).callback();
|
let cb = client.process_output(now).callback();
|
||||||
assert_eq!(cb, Duration::from_millis(300));
|
assert_eq!(cb, Duration::from_millis(300));
|
||||||
|
|
||||||
now += HALF_RTT;
|
now += HALF_RTT;
|
||||||
let pkt = server.process(pkt.as_ref(), now).dgram();
|
let pkt = server.process(pkt, now).dgram();
|
||||||
assert_initial(pkt.as_ref().unwrap(), false);
|
assert_initial(pkt.as_ref().unwrap(), false);
|
||||||
|
|
||||||
now += HALF_RTT;
|
now += HALF_RTT;
|
||||||
let pkt = client.process(pkt.as_ref(), now).dgram();
|
let pkt = client.process(pkt, now).dgram();
|
||||||
assert_handshake(pkt.as_ref().unwrap());
|
assert_handshake(pkt.as_ref().unwrap());
|
||||||
|
|
||||||
let cb = client.process(None, now).callback();
|
let cb = client.process_output(now).callback();
|
||||||
// The client now has a single RTT estimate (20ms), so
|
// The client now has a single RTT estimate (20ms), so
|
||||||
// the handshake PTO is set based on that.
|
// the handshake PTO is set based on that.
|
||||||
assert_eq!(cb, HALF_RTT * 6);
|
assert_eq!(cb, HALF_RTT * 6);
|
||||||
|
|
||||||
now += HALF_RTT;
|
now += HALF_RTT;
|
||||||
let pkt = server.process(pkt.as_ref(), now).dgram();
|
let pkt = server.process(pkt, now).dgram();
|
||||||
assert!(pkt.is_none());
|
assert!(pkt.is_none());
|
||||||
|
|
||||||
now += HALF_RTT;
|
now += HALF_RTT;
|
||||||
client.authenticated(AuthenticationStatus::Ok, now);
|
client.authenticated(AuthenticationStatus::Ok, now);
|
||||||
|
|
||||||
qdebug!("---- client: SH..FIN -> FIN");
|
qdebug!("---- client: SH..FIN -> FIN");
|
||||||
let pkt1 = client.process(None, now).dgram();
|
let pkt1 = client.process_output(now).dgram();
|
||||||
assert_handshake(pkt1.as_ref().unwrap());
|
assert_handshake(pkt1.as_ref().unwrap());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
let cb = client.process(None, now).callback();
|
let cb = client.process_output(now).callback();
|
||||||
assert_eq!(cb, HALF_RTT * 6);
|
assert_eq!(cb, HALF_RTT * 6);
|
||||||
|
|
||||||
let mut pto_counts = [0; MAX_PTO_COUNTS];
|
let mut pto_counts = [0; MAX_PTO_COUNTS];
|
||||||
|
@ -255,7 +255,7 @@ fn pto_handshake_complete() {
|
||||||
// Wait long enough that the 1-RTT PTO also fires.
|
// Wait long enough that the 1-RTT PTO also fires.
|
||||||
qdebug!("---- client: PTO");
|
qdebug!("---- client: PTO");
|
||||||
now += HALF_RTT * 6;
|
now += HALF_RTT * 6;
|
||||||
let pkt2 = client.process(None, now).dgram();
|
let pkt2 = client.process_output(now).dgram();
|
||||||
assert_handshake(pkt2.as_ref().unwrap());
|
assert_handshake(pkt2.as_ref().unwrap());
|
||||||
|
|
||||||
pto_counts[0] = 1;
|
pto_counts[0] = 1;
|
||||||
|
@ -267,14 +267,14 @@ fn pto_handshake_complete() {
|
||||||
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_close_send(stream_id).unwrap();
|
client.stream_close_send(stream_id).unwrap();
|
||||||
now += HALF_RTT * 6;
|
now += HALF_RTT * 6;
|
||||||
let pkt3 = client.process(None, now).dgram();
|
let pkt3 = client.process_output(now).dgram();
|
||||||
assert_handshake(pkt3.as_ref().unwrap());
|
assert_handshake(pkt3.as_ref().unwrap());
|
||||||
let (pkt3_hs, pkt3_1rtt) = split_datagram(&pkt3.unwrap());
|
let (pkt3_hs, pkt3_1rtt) = split_datagram(&pkt3.unwrap());
|
||||||
assert_handshake(&pkt3_hs);
|
assert_handshake(&pkt3_hs);
|
||||||
assert!(pkt3_1rtt.is_some());
|
assert!(pkt3_1rtt.is_some());
|
||||||
|
|
||||||
// PTO has been doubled.
|
// PTO has been doubled.
|
||||||
let cb = client.process(None, now).callback();
|
let cb = client.process_output(now).callback();
|
||||||
assert_eq!(cb, HALF_RTT * 12);
|
assert_eq!(cb, HALF_RTT * 12);
|
||||||
|
|
||||||
// We still have only a single PTO
|
// We still have only a single PTO
|
||||||
|
@ -288,8 +288,8 @@ fn pto_handshake_complete() {
|
||||||
// This should remove the 1-RTT PTO from messing this test up.
|
// This should remove the 1-RTT PTO from messing this test up.
|
||||||
let server_acks = server.stats().frame_tx.ack;
|
let server_acks = server.stats().frame_tx.ack;
|
||||||
let server_done = server.stats().frame_tx.handshake_done;
|
let server_done = server.stats().frame_tx.handshake_done;
|
||||||
server.process_input(&pkt3_1rtt.unwrap(), now);
|
server.process_input(pkt3_1rtt.unwrap(), now);
|
||||||
let ack = server.process(pkt1.as_ref(), now).dgram();
|
let ack = server.process(pkt1, now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
assert_eq!(server.stats().frame_tx.ack, server_acks + 2);
|
assert_eq!(server.stats().frame_tx.ack, server_acks + 2);
|
||||||
assert_eq!(server.stats().frame_tx.handshake_done, server_done + 1);
|
assert_eq!(server.stats().frame_tx.handshake_done, server_done + 1);
|
||||||
|
@ -302,14 +302,14 @@ fn pto_handshake_complete() {
|
||||||
assert!(pkt2_1rtt.is_some());
|
assert!(pkt2_1rtt.is_some());
|
||||||
let dropped_before1 = server.stats().dropped_rx;
|
let dropped_before1 = server.stats().dropped_rx;
|
||||||
let server_frames = server.stats().frame_rx.all();
|
let server_frames = server.stats().frame_rx.all();
|
||||||
server.process_input(&pkt2_hs, now);
|
server.process_input(pkt2_hs, now);
|
||||||
assert_eq!(1, server.stats().dropped_rx - dropped_before1);
|
assert_eq!(1, server.stats().dropped_rx - dropped_before1);
|
||||||
assert_eq!(server.stats().frame_rx.all(), server_frames);
|
assert_eq!(server.stats().frame_rx.all(), server_frames);
|
||||||
|
|
||||||
server.process_input(&pkt2_1rtt.unwrap(), now);
|
server.process_input(pkt2_1rtt.unwrap(), now);
|
||||||
let server_frames2 = server.stats().frame_rx.all();
|
let server_frames2 = server.stats().frame_rx.all();
|
||||||
let dropped_before2 = server.stats().dropped_rx;
|
let dropped_before2 = server.stats().dropped_rx;
|
||||||
server.process_input(&pkt3_hs, now);
|
server.process_input(pkt3_hs, now);
|
||||||
assert_eq!(1, server.stats().dropped_rx - dropped_before2);
|
assert_eq!(1, server.stats().dropped_rx - dropped_before2);
|
||||||
assert_eq!(server.stats().frame_rx.all(), server_frames2);
|
assert_eq!(server.stats().frame_rx.all(), server_frames2);
|
||||||
|
|
||||||
|
@ -317,14 +317,14 @@ fn pto_handshake_complete() {
|
||||||
|
|
||||||
// Let the client receive the ACK.
|
// Let the client receive the ACK.
|
||||||
// It should now be wait to acknowledge the HANDSHAKE_DONE.
|
// It should now be wait to acknowledge the HANDSHAKE_DONE.
|
||||||
let cb = client.process(ack.as_ref(), now).callback();
|
let cb = client.process(ack, now).callback();
|
||||||
// The default ack delay is the RTT divided by the default ACK ratio of 4.
|
// The default ack delay is the RTT divided by the default ACK ratio of 4.
|
||||||
let expected_ack_delay = HALF_RTT * 2 / 4;
|
let expected_ack_delay = HALF_RTT * 2 / 4;
|
||||||
assert_eq!(cb, expected_ack_delay);
|
assert_eq!(cb, expected_ack_delay);
|
||||||
|
|
||||||
// Let the ACK delay timer expire.
|
// Let the ACK delay timer expire.
|
||||||
now += cb;
|
now += cb;
|
||||||
let out = client.process(None, now).dgram();
|
let out = client.process_output(now).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,19 +334,19 @@ fn pto_handshake_frames() {
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
qdebug!("---- client: generate CH");
|
qdebug!("---- client: generate CH");
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let pkt = client.process(None, now);
|
let pkt = client.process_output(now);
|
||||||
|
|
||||||
now += Duration::from_millis(10);
|
now += Duration::from_millis(10);
|
||||||
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let pkt = server.process(pkt.as_dgram_ref(), now);
|
let pkt = server.process(pkt.dgram(), now);
|
||||||
|
|
||||||
now += Duration::from_millis(10);
|
now += Duration::from_millis(10);
|
||||||
qdebug!("---- client: cert verification");
|
qdebug!("---- client: cert verification");
|
||||||
let pkt = client.process(pkt.as_dgram_ref(), now);
|
let pkt = client.process(pkt.dgram(), now);
|
||||||
|
|
||||||
now += Duration::from_millis(10);
|
now += Duration::from_millis(10);
|
||||||
mem::drop(server.process(pkt.as_dgram_ref(), now));
|
mem::drop(server.process(pkt.dgram(), now));
|
||||||
|
|
||||||
now += Duration::from_millis(10);
|
now += Duration::from_millis(10);
|
||||||
client.authenticated(AuthenticationStatus::Ok, now);
|
client.authenticated(AuthenticationStatus::Ok, now);
|
||||||
|
@ -355,21 +355,21 @@ fn pto_handshake_frames() {
|
||||||
assert_eq!(stream, 2);
|
assert_eq!(stream, 2);
|
||||||
assert_eq!(client.stream_send(stream, b"zero").unwrap(), 4);
|
assert_eq!(client.stream_send(stream, b"zero").unwrap(), 4);
|
||||||
qdebug!("---- client: SH..FIN -> FIN and 1RTT packet");
|
qdebug!("---- client: SH..FIN -> FIN and 1RTT packet");
|
||||||
let pkt1 = client.process(None, now).dgram();
|
let pkt1 = client.process_output(now).dgram();
|
||||||
assert!(pkt1.is_some());
|
assert!(pkt1.is_some());
|
||||||
|
|
||||||
// Get PTO timer.
|
// Get PTO timer.
|
||||||
let out = client.process(None, now);
|
let out = client.process_output(now);
|
||||||
assert_eq!(out, Output::Callback(Duration::from_millis(60)));
|
assert_eq!(out, Output::Callback(Duration::from_millis(60)));
|
||||||
|
|
||||||
// Wait for PTO to expire and resend a handshake packet.
|
// Wait for PTO to expire and resend a handshake packet.
|
||||||
now += Duration::from_millis(60);
|
now += Duration::from_millis(60);
|
||||||
let pkt2 = client.process(None, now).dgram();
|
let pkt2 = client.process_output(now).dgram();
|
||||||
assert!(pkt2.is_some());
|
assert!(pkt2.is_some());
|
||||||
|
|
||||||
now += Duration::from_millis(10);
|
now += Duration::from_millis(10);
|
||||||
let crypto_before = server.stats().frame_rx.crypto;
|
let crypto_before = server.stats().frame_rx.crypto;
|
||||||
server.process_input(&pkt2.unwrap(), now);
|
server.process_input(pkt2.unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.crypto, crypto_before + 1);
|
assert_eq!(server.stats().frame_rx.crypto, crypto_before + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,21 +388,21 @@ fn handshake_ack_pto() {
|
||||||
let big = TransportParameter::Bytes(vec![0; Pmtud::default_plpmtu(DEFAULT_ADDR.ip())]);
|
let big = TransportParameter::Bytes(vec![0; Pmtud::default_plpmtu(DEFAULT_ADDR.ip())]);
|
||||||
server.set_local_tparam(0xce16, big).unwrap();
|
server.set_local_tparam(0xce16, big).unwrap();
|
||||||
|
|
||||||
let c1 = client.process(None, now).dgram();
|
let c1 = client.process_output(now).dgram();
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s1 = server.process(c1.as_ref(), now).dgram();
|
let s1 = server.process(c1, now).dgram();
|
||||||
assert!(s1.is_some());
|
assert!(s1.is_some());
|
||||||
let s2 = server.process(None, now).dgram();
|
let s2 = server.process_output(now).dgram();
|
||||||
assert!(s1.is_some());
|
assert!(s1.is_some());
|
||||||
|
|
||||||
// Now let the client have the Initial, but drop the first coalesced Handshake packet.
|
// Now let the client have the Initial, but drop the first coalesced Handshake packet.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let (initial, _) = split_datagram(&s1.unwrap());
|
let (initial, _) = split_datagram(&s1.unwrap());
|
||||||
client.process_input(&initial, now);
|
client.process_input(initial, now);
|
||||||
let c2 = client.process(s2.as_ref(), now).dgram();
|
let c2 = client.process(s2, now).dgram();
|
||||||
assert!(c2.is_some()); // This is an ACK. Drop it.
|
assert!(c2.is_some()); // This is an ACK. Drop it.
|
||||||
let delay = client.process(None, now).callback();
|
let delay = client.process_output(now).callback();
|
||||||
assert_eq!(delay, RTT * 3);
|
assert_eq!(delay, RTT * 3);
|
||||||
|
|
||||||
let mut pto_counts = [0; MAX_PTO_COUNTS];
|
let mut pto_counts = [0; MAX_PTO_COUNTS];
|
||||||
|
@ -410,26 +410,26 @@ fn handshake_ack_pto() {
|
||||||
|
|
||||||
// Wait for the PTO and ensure that the client generates a packet.
|
// Wait for the PTO and ensure that the client generates a packet.
|
||||||
now += delay;
|
now += delay;
|
||||||
let c3 = client.process(None, now).dgram();
|
let c3 = client.process_output(now).dgram();
|
||||||
assert!(c3.is_some());
|
assert!(c3.is_some());
|
||||||
|
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let ping_before = server.stats().frame_rx.ping;
|
let ping_before = server.stats().frame_rx.ping;
|
||||||
server.process_input(&c3.unwrap(), now);
|
server.process_input(c3.unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.ping, ping_before + 1);
|
assert_eq!(server.stats().frame_rx.ping, ping_before + 1);
|
||||||
|
|
||||||
pto_counts[0] = 1;
|
pto_counts[0] = 1;
|
||||||
assert_eq!(client.stats.borrow().pto_counts, pto_counts);
|
assert_eq!(client.stats.borrow().pto_counts, pto_counts);
|
||||||
|
|
||||||
// Now complete the handshake as cheaply as possible.
|
// Now complete the handshake as cheaply as possible.
|
||||||
let dgram = server.process(None, now).dgram();
|
let dgram = server.process_output(now).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
|
|
||||||
assert_eq!(client.stats.borrow().pto_counts, pto_counts);
|
assert_eq!(client.stats.borrow().pto_counts, pto_counts);
|
||||||
|
@ -450,12 +450,12 @@ fn loss_recovery_crash() {
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
|
|
||||||
// Have the server process the ACK.
|
// Have the server process the ACK.
|
||||||
let cb = server.process(ack.as_ref(), now).callback();
|
let cb = server.process(ack, now).callback();
|
||||||
assert!(cb > Duration::from_secs(0));
|
assert!(cb > Duration::from_secs(0));
|
||||||
|
|
||||||
// Now we leap into the future. The server should regard the first
|
// Now we leap into the future. The server should regard the first
|
||||||
// packet as lost based on time alone.
|
// packet as lost based on time alone.
|
||||||
let dgram = server.process(None, now + AT_LEAST_PTO).dgram();
|
let dgram = server.process_output(now + AT_LEAST_PTO).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
// This crashes.
|
// This crashes.
|
||||||
|
@ -480,10 +480,10 @@ fn ack_after_pto() {
|
||||||
now += AT_LEAST_PTO;
|
now += AT_LEAST_PTO;
|
||||||
// We can use MAX_PTO_PACKET_COUNT, because we know the handshake is over.
|
// We can use MAX_PTO_PACKET_COUNT, because we know the handshake is over.
|
||||||
for _ in 0..MAX_PTO_PACKET_COUNT {
|
for _ in 0..MAX_PTO_PACKET_COUNT {
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
}
|
}
|
||||||
assert!(client.process(None, now).dgram().is_none());
|
assert!(client.process_output(now).dgram().is_none());
|
||||||
|
|
||||||
// The server now needs to send something that will cause the
|
// The server now needs to send something that will cause the
|
||||||
// client to want to acknowledge it. A little out of order
|
// client to want to acknowledge it. A little out of order
|
||||||
|
@ -495,13 +495,13 @@ fn ack_after_pto() {
|
||||||
|
|
||||||
// The client is now after a PTO, but if it receives something
|
// The client is now after a PTO, but if it receives something
|
||||||
// that demands acknowledgment, it will send just the ACK.
|
// that demands acknowledgment, it will send just the ACK.
|
||||||
let ack = client.process(Some(&dgram), now).dgram();
|
let ack = client.process(Some(dgram), now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
|
|
||||||
// Make sure that the packet only contained an ACK frame.
|
// Make sure that the packet only contained an ACK frame.
|
||||||
let all_frames_before = server.stats().frame_rx.all();
|
let all_frames_before = server.stats().frame_rx.all();
|
||||||
let ack_before = server.stats().frame_rx.ack;
|
let ack_before = server.stats().frame_rx.ack;
|
||||||
server.process_input(&ack.unwrap(), now);
|
server.process_input(ack.unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.all(), all_frames_before + 1);
|
assert_eq!(server.stats().frame_rx.all(), all_frames_before + 1);
|
||||||
assert_eq!(server.stats().frame_rx.ack, ack_before + 1);
|
assert_eq!(server.stats().frame_rx.ack, ack_before + 1);
|
||||||
}
|
}
|
||||||
|
@ -522,7 +522,7 @@ fn lost_but_kept_and_lr_timer() {
|
||||||
|
|
||||||
// At t=RTT/2 the server receives the packet and ACKs it.
|
// At t=RTT/2 the server receives the packet and ACKs it.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let ack = server.process(Some(&p2), now).dgram();
|
let ack = server.process(Some(p2), now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
// The client also sends another two packets (p3, p4), again losing the first.
|
// The client also sends another two packets (p3, p4), again losing the first.
|
||||||
let _p3 = send_something(&mut client, now);
|
let _p3 = send_something(&mut client, now);
|
||||||
|
@ -531,24 +531,24 @@ fn lost_but_kept_and_lr_timer() {
|
||||||
// At t=RTT the client receives the ACK and goes into timed loss recovery.
|
// At t=RTT the client receives the ACK and goes into timed loss recovery.
|
||||||
// The client doesn't call p1 lost at this stage, but it will soon.
|
// The client doesn't call p1 lost at this stage, but it will soon.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let res = client.process(ack.as_ref(), now);
|
let res = client.process(ack, now);
|
||||||
// The client should be on a loss recovery timer as p1 is missing.
|
// The client should be on a loss recovery timer as p1 is missing.
|
||||||
let lr_timer = res.callback();
|
let lr_timer = res.callback();
|
||||||
// Loss recovery timer should be RTT/8, but only check for 0 or >=RTT/2.
|
// Loss recovery timer should be RTT/8, but only check for 0 or >=RTT/2.
|
||||||
assert_ne!(lr_timer, Duration::from_secs(0));
|
assert_ne!(lr_timer, Duration::from_secs(0));
|
||||||
assert!(lr_timer < (RTT / 2));
|
assert!(lr_timer < (RTT / 2));
|
||||||
// The server also receives and acknowledges p4, again sending an ACK.
|
// The server also receives and acknowledges p4, again sending an ACK.
|
||||||
let ack = server.process(Some(&p4), now).dgram();
|
let ack = server.process(Some(p4), now).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
|
|
||||||
// At t=RTT*3/2 the client should declare p1 to be lost.
|
// At t=RTT*3/2 the client should declare p1 to be lost.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
// So the client will send the data from p1 again.
|
// So the client will send the data from p1 again.
|
||||||
let res = client.process(None, now);
|
let res = client.process_output(now);
|
||||||
assert!(res.dgram().is_some());
|
assert!(res.dgram().is_some());
|
||||||
// When the client processes the ACK, it should engage the
|
// When the client processes the ACK, it should engage the
|
||||||
// loss recovery timer for p3, not p1 (even though it still tracks p1).
|
// loss recovery timer for p3, not p1 (even though it still tracks p1).
|
||||||
let res = client.process(ack.as_ref(), now);
|
let res = client.process(ack, now);
|
||||||
let lr_timer2 = res.callback();
|
let lr_timer2 = res.callback();
|
||||||
assert_eq!(lr_timer, lr_timer2);
|
assert_eq!(lr_timer, lr_timer2);
|
||||||
}
|
}
|
||||||
|
@ -569,9 +569,9 @@ fn loss_time_past_largest_acked() {
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let c_in = client.process(None, now).dgram();
|
let c_in = client.process_output(now).dgram();
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let s_hs1 = server.process(c_in.as_ref(), now).dgram();
|
let s_hs1 = server.process(c_in, now).dgram();
|
||||||
|
|
||||||
// Get some spare server handshake packets for the client to ACK.
|
// Get some spare server handshake packets for the client to ACK.
|
||||||
// This involves a time machine, so be a little cautious.
|
// This involves a time machine, so be a little cautious.
|
||||||
|
@ -579,15 +579,15 @@ fn loss_time_past_largest_acked() {
|
||||||
// with a much lower RTT estimate, so the PTO at this point should
|
// with a much lower RTT estimate, so the PTO at this point should
|
||||||
// be much smaller than an RTT and so the server shouldn't see
|
// be much smaller than an RTT and so the server shouldn't see
|
||||||
// time go backwards.
|
// time go backwards.
|
||||||
let s_pto = server.process(None, now).callback();
|
let s_pto = server.process_output(now).callback();
|
||||||
assert_ne!(s_pto, Duration::from_secs(0));
|
assert_ne!(s_pto, Duration::from_secs(0));
|
||||||
assert!(s_pto < RTT);
|
assert!(s_pto < RTT);
|
||||||
let s_hs2 = server.process(None, now + s_pto).dgram();
|
let s_hs2 = server.process_output(now + s_pto).dgram();
|
||||||
assert!(s_hs2.is_some());
|
assert!(s_hs2.is_some());
|
||||||
let s_pto = server.process(None, now).callback();
|
let s_pto = server.process_output(now).callback();
|
||||||
assert_ne!(s_pto, Duration::from_secs(0));
|
assert_ne!(s_pto, Duration::from_secs(0));
|
||||||
assert!(s_pto < RTT);
|
assert!(s_pto < RTT);
|
||||||
let s_hs3 = server.process(None, now + s_pto).dgram();
|
let s_hs3 = server.process_output(now + s_pto).dgram();
|
||||||
assert!(s_hs3.is_some());
|
assert!(s_hs3.is_some());
|
||||||
|
|
||||||
// We are blocked by the amplification limit now.
|
// We are blocked by the amplification limit now.
|
||||||
|
@ -601,26 +601,26 @@ fn loss_time_past_largest_acked() {
|
||||||
// to generate an ack-eliciting packet. For that, we use the Finished message.
|
// to generate an ack-eliciting packet. For that, we use the Finished message.
|
||||||
// Reordering delivery ensures that the later packet is also acknowledged.
|
// Reordering delivery ensures that the later packet is also acknowledged.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let c_hs1 = client.process(s_hs1.as_ref(), now).dgram();
|
let c_hs1 = client.process(s_hs1, now).dgram();
|
||||||
assert!(c_hs1.is_some()); // This comes first, so it's useless.
|
assert!(c_hs1.is_some()); // This comes first, so it's useless.
|
||||||
maybe_authenticate(&mut client);
|
maybe_authenticate(&mut client);
|
||||||
let c_hs2 = client.process(None, now).dgram();
|
let c_hs2 = client.process_output(now).dgram();
|
||||||
assert!(c_hs2.is_some()); // This one will elicit an ACK.
|
assert!(c_hs2.is_some()); // This one will elicit an ACK.
|
||||||
|
|
||||||
// The we need the outstanding packet to be sent after the
|
// The we need the outstanding packet to be sent after the
|
||||||
// application data packet, so space these out a tiny bit.
|
// application data packet, so space these out a tiny bit.
|
||||||
let _p1 = send_something(&mut client, now + INCR);
|
let _p1 = send_something(&mut client, now + INCR);
|
||||||
let c_hs3 = client.process(s_hs2.as_ref(), now + (INCR * 2)).dgram();
|
let c_hs3 = client.process(s_hs2, now + (INCR * 2)).dgram();
|
||||||
assert!(c_hs3.is_some()); // This will be left outstanding.
|
assert!(c_hs3.is_some()); // This will be left outstanding.
|
||||||
let c_hs4 = client.process(s_hs3.as_ref(), now + (INCR * 3)).dgram();
|
let c_hs4 = client.process(s_hs3, now + (INCR * 3)).dgram();
|
||||||
assert!(c_hs4.is_some()); // This will be acknowledged.
|
assert!(c_hs4.is_some()); // This will be acknowledged.
|
||||||
|
|
||||||
// Process c_hs2 and c_hs4, but skip c_hs3.
|
// Process c_hs2 and c_hs4, but skip c_hs3.
|
||||||
// Then get an ACK for the client.
|
// Then get an ACK for the client.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
// Deliver c_hs4 first, but don't generate a packet.
|
// Deliver c_hs4 first, but don't generate a packet.
|
||||||
server.process_input(&c_hs4.unwrap(), now);
|
server.process_input(c_hs4.unwrap(), now);
|
||||||
let s_ack = server.process(c_hs2.as_ref(), now).dgram();
|
let s_ack = server.process(c_hs2, now).dgram();
|
||||||
assert!(s_ack.is_some());
|
assert!(s_ack.is_some());
|
||||||
// This includes an ACK, but it also includes HANDSHAKE_DONE,
|
// This includes an ACK, but it also includes HANDSHAKE_DONE,
|
||||||
// which we need to remove because that will cause the Handshake loss
|
// which we need to remove because that will cause the Handshake loss
|
||||||
|
@ -629,12 +629,12 @@ fn loss_time_past_largest_acked() {
|
||||||
|
|
||||||
// Now the client should start its loss recovery timer based on the ACK.
|
// Now the client should start its loss recovery timer based on the ACK.
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let _c_ack = client.process(Some(&s_hs_ack), now).dgram();
|
let _c_ack = client.process(Some(s_hs_ack), now).dgram();
|
||||||
// This ACK triggers an immediate ACK, due to an ACK loss during handshake.
|
// This ACK triggers an immediate ACK, due to an ACK loss during handshake.
|
||||||
let c_ack = client.process(None, now).dgram();
|
let c_ack = client.process_output(now).dgram();
|
||||||
assert!(c_ack.is_none());
|
assert!(c_ack.is_none());
|
||||||
// The client should now have the loss recovery timer active.
|
// The client should now have the loss recovery timer active.
|
||||||
let lr_time = client.process(None, now).callback();
|
let lr_time = client.process_output(now).callback();
|
||||||
assert_ne!(lr_time, Duration::from_secs(0));
|
assert_ne!(lr_time, Duration::from_secs(0));
|
||||||
assert!(lr_time < (RTT / 2));
|
assert!(lr_time < (RTT / 2));
|
||||||
}
|
}
|
||||||
|
@ -648,12 +648,12 @@ fn trickle(sender: &mut Connection, receiver: &mut Connection, mut count: usize,
|
||||||
while count > 0 {
|
while count > 0 {
|
||||||
qdebug!("trickle: remaining={}", count);
|
qdebug!("trickle: remaining={}", count);
|
||||||
assert_eq!(sender.stream_send(id, &[9]).unwrap(), 1);
|
assert_eq!(sender.stream_send(id, &[9]).unwrap(), 1);
|
||||||
let dgram = sender.process(maybe_ack.as_ref(), now).dgram();
|
let dgram = sender.process(maybe_ack, now).dgram();
|
||||||
|
|
||||||
maybe_ack = receiver.process(dgram.as_ref(), now).dgram();
|
maybe_ack = receiver.process(dgram, now).dgram();
|
||||||
count -= usize::from(maybe_ack.is_some());
|
count -= usize::from(maybe_ack.is_some());
|
||||||
}
|
}
|
||||||
sender.process_input(&maybe_ack.unwrap(), now);
|
sender.process_input(maybe_ack.unwrap(), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that a PING frame is sent with ACK sometimes.
|
/// Ensure that a PING frame is sent with ACK sometimes.
|
||||||
|
@ -744,7 +744,7 @@ fn fast_pto() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
|
let mut now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
|
||||||
|
|
||||||
let res = client.process(None, now);
|
let res = client.process_output(now);
|
||||||
let idle_timeout = ConnectionParameters::default().get_idle_timeout() - (DEFAULT_RTT / 2);
|
let idle_timeout = ConnectionParameters::default().get_idle_timeout() - (DEFAULT_RTT / 2);
|
||||||
assert_eq!(res, Output::Callback(idle_timeout));
|
assert_eq!(res, Output::Callback(idle_timeout));
|
||||||
|
|
||||||
|
@ -766,10 +766,10 @@ fn fast_pto() {
|
||||||
|
|
||||||
// Once the PTO timer expires, a PTO packet should be sent should want to send PTO packet.
|
// Once the PTO timer expires, a PTO packet should be sent should want to send PTO packet.
|
||||||
now += cb;
|
now += cb;
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
|
|
||||||
let stream_before = server.stats().frame_rx.stream;
|
let stream_before = server.stats().frame_rx.stream;
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.stream, stream_before + 1);
|
assert_eq!(server.stats().frame_rx.stream, stream_before + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +781,7 @@ fn fast_pto_persistent_congestion() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
|
let mut now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
|
||||||
|
|
||||||
let res = client.process(None, now);
|
let res = client.process_output(now);
|
||||||
let idle_timeout = ConnectionParameters::default().get_idle_timeout() - (DEFAULT_RTT / 2);
|
let idle_timeout = ConnectionParameters::default().get_idle_timeout() - (DEFAULT_RTT / 2);
|
||||||
assert_eq!(res, Output::Callback(idle_timeout));
|
assert_eq!(res, Output::Callback(idle_timeout));
|
||||||
|
|
||||||
|
@ -809,9 +809,9 @@ fn fast_pto_persistent_congestion() {
|
||||||
|
|
||||||
// Now acknowledge the tail packet and enter persistent congestion.
|
// Now acknowledge the tail packet and enter persistent congestion.
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
let ack = server.process(Some(&dgram), now).dgram();
|
let ack = server.process(Some(dgram), now).dgram();
|
||||||
now += DEFAULT_RTT / 2;
|
now += DEFAULT_RTT / 2;
|
||||||
client.process_input(&ack.unwrap(), now);
|
client.process_input(ack.unwrap(), now);
|
||||||
assert_eq!(cwnd(&client), cwnd_min(&client));
|
assert_eq!(cwnd(&client), cwnd_min(&client));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,7 +841,7 @@ fn ack_for_unsent() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Now deliver the packet with the spoofed ACK frame
|
// Now deliver the packet with the spoofed ACK frame
|
||||||
client.process_input(&spoofed, now());
|
client.process_input(spoofed, now());
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
client.state(),
|
client.state(),
|
||||||
State::Closing {
|
State::Closing {
|
||||||
|
|
|
@ -66,7 +66,7 @@ fn remember_smoothed_rtt() {
|
||||||
let ticket = server.process_output(now).dgram();
|
let ticket = server.process_output(now).dgram();
|
||||||
assert!(ticket.is_some());
|
assert!(ticket.is_some());
|
||||||
now += RTT1 / 2;
|
now += RTT1 / 2;
|
||||||
client.process_input(&ticket.unwrap(), now);
|
client.process_input(ticket.unwrap(), now);
|
||||||
let token = get_tokens(&mut client).pop().unwrap();
|
let token = get_tokens(&mut client).pop().unwrap();
|
||||||
|
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
@ -102,7 +102,7 @@ fn ticket_rtt(rtt: Duration) -> Duration {
|
||||||
let client_dcid = client_dcid.to_owned();
|
let client_dcid = client_dcid.to_owned();
|
||||||
|
|
||||||
now += rtt / 2;
|
now += rtt / 2;
|
||||||
let server_packet = server.process(client_initial.as_dgram_ref(), now).dgram();
|
let server_packet = server.process(client_initial.dgram(), now).dgram();
|
||||||
let (server_initial, server_hs) = split_datagram(server_packet.as_ref().unwrap());
|
let (server_initial, server_hs) = split_datagram(server_packet.as_ref().unwrap());
|
||||||
let (protected_header, _, _, payload) =
|
let (protected_header, _, _, payload) =
|
||||||
decode_initial_header(&server_initial, Role::Server).unwrap();
|
decode_initial_header(&server_initial, Role::Server).unwrap();
|
||||||
|
@ -143,15 +143,15 @@ fn ticket_rtt(rtt: Duration) -> Duration {
|
||||||
|
|
||||||
// Now a connection can be made successfully.
|
// Now a connection can be made successfully.
|
||||||
now += rtt / 2;
|
now += rtt / 2;
|
||||||
client.process_input(&si, now);
|
client.process_input(si, now);
|
||||||
client.process_input(&server_hs.unwrap(), now);
|
client.process_input(server_hs.unwrap(), now);
|
||||||
client.authenticated(AuthenticationStatus::Ok, now);
|
client.authenticated(AuthenticationStatus::Ok, now);
|
||||||
let finished = client.process_output(now);
|
let finished = client.process_output(now);
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
now += rtt / 2;
|
now += rtt / 2;
|
||||||
_ = server.process(finished.as_dgram_ref(), now);
|
_ = server.process(finished.dgram(), now);
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
|
|
||||||
// Don't deliver the server's handshake finished, it has ACKs.
|
// Don't deliver the server's handshake finished, it has ACKs.
|
||||||
|
@ -164,7 +164,7 @@ fn ticket_rtt(rtt: Duration) -> Duration {
|
||||||
let ticket = server.process_output(now).dgram();
|
let ticket = server.process_output(now).dgram();
|
||||||
assert!(ticket.is_some());
|
assert!(ticket.is_some());
|
||||||
now += rtt / 2;
|
now += rtt / 2;
|
||||||
client.process_input(&ticket.unwrap(), now);
|
client.process_input(ticket.unwrap(), now);
|
||||||
let token = get_tokens(&mut client).pop().unwrap();
|
let token = get_tokens(&mut client).pop().unwrap();
|
||||||
|
|
||||||
// And connect again.
|
// And connect again.
|
||||||
|
@ -213,7 +213,7 @@ fn address_validation_token_resume() {
|
||||||
let mut server = resumed_server(&client);
|
let mut server = resumed_server(&client);
|
||||||
|
|
||||||
// Grab an Initial packet from the client.
|
// Grab an Initial packet from the client.
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
||||||
|
|
||||||
// Now try to complete the handshake after giving time for a client PTO.
|
// Now try to complete the handshake after giving time for a client PTO.
|
||||||
|
@ -242,26 +242,26 @@ fn two_tickets_on_timer() {
|
||||||
let pkt = send_something(&mut server, now());
|
let pkt = send_something(&mut server, now());
|
||||||
|
|
||||||
// process() will return an ack first
|
// process() will return an ack first
|
||||||
assert!(client.process(Some(&pkt), now()).dgram().is_some());
|
assert!(client.process(Some(pkt), now()).dgram().is_some());
|
||||||
// We do not have a ResumptionToken event yet, because NEW_TOKEN was not sent.
|
// We do not have a ResumptionToken event yet, because NEW_TOKEN was not sent.
|
||||||
assert_eq!(get_tokens(&mut client).len(), 0);
|
assert_eq!(get_tokens(&mut client).len(), 0);
|
||||||
|
|
||||||
// We need to wait for release_resumption_token_timer to expire. The timer will be
|
// We need to wait for release_resumption_token_timer to expire. The timer will be
|
||||||
// set to 3 * PTO
|
// set to 3 * PTO
|
||||||
let mut now = now() + 3 * client.pto();
|
let mut now = now() + 3 * client.pto();
|
||||||
mem::drop(client.process(None, now));
|
mem::drop(client.process_output(now));
|
||||||
let mut recv_tokens = get_tokens(&mut client);
|
let mut recv_tokens = get_tokens(&mut client);
|
||||||
assert_eq!(recv_tokens.len(), 1);
|
assert_eq!(recv_tokens.len(), 1);
|
||||||
let token1 = recv_tokens.pop().unwrap();
|
let token1 = recv_tokens.pop().unwrap();
|
||||||
// Wai for anottheer 3 * PTO to get the nex okeen.
|
// Wai for anottheer 3 * PTO to get the nex okeen.
|
||||||
now += 3 * client.pto();
|
now += 3 * client.pto();
|
||||||
mem::drop(client.process(None, now));
|
mem::drop(client.process_output(now));
|
||||||
let mut recv_tokens = get_tokens(&mut client);
|
let mut recv_tokens = get_tokens(&mut client);
|
||||||
assert_eq!(recv_tokens.len(), 1);
|
assert_eq!(recv_tokens.len(), 1);
|
||||||
let token2 = recv_tokens.pop().unwrap();
|
let token2 = recv_tokens.pop().unwrap();
|
||||||
// Wait for 3 * PTO, but now there are no more tokens.
|
// Wait for 3 * PTO, but now there are no more tokens.
|
||||||
now += 3 * client.pto();
|
now += 3 * client.pto();
|
||||||
mem::drop(client.process(None, now));
|
mem::drop(client.process_output(now));
|
||||||
assert_eq!(get_tokens(&mut client).len(), 0);
|
assert_eq!(get_tokens(&mut client).len(), 0);
|
||||||
assert_ne!(token1.as_ref(), token2.as_ref());
|
assert_ne!(token1.as_ref(), token2.as_ref());
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ fn two_tickets_with_new_token() {
|
||||||
server.send_ticket(now(), &[]).expect("send ticket2");
|
server.send_ticket(now(), &[]).expect("send ticket2");
|
||||||
let pkt = send_something(&mut server, now());
|
let pkt = send_something(&mut server, now());
|
||||||
|
|
||||||
client.process_input(&pkt, now());
|
client.process_input(pkt, now());
|
||||||
let mut all_tokens = get_tokens(&mut client);
|
let mut all_tokens = get_tokens(&mut client);
|
||||||
assert_eq!(all_tokens.len(), 2);
|
assert_eq!(all_tokens.len(), 2);
|
||||||
let token1 = all_tokens.pop().unwrap();
|
let token1 = all_tokens.pop().unwrap();
|
||||||
|
@ -303,8 +303,8 @@ fn take_token() {
|
||||||
connect(&mut client, &mut server);
|
connect(&mut client, &mut server);
|
||||||
|
|
||||||
server.send_ticket(now(), &[]).unwrap();
|
server.send_ticket(now(), &[]).unwrap();
|
||||||
let dgram = server.process(None, now()).dgram();
|
let dgram = server.process_output(now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
// There should be no ResumptionToken event here.
|
// There should be no ResumptionToken event here.
|
||||||
let tokens = get_tokens(&mut client);
|
let tokens = get_tokens(&mut client);
|
||||||
|
|
|
@ -32,14 +32,14 @@ use crate::{
|
||||||
fn stream_create() {
|
fn stream_create() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
|
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(server.process(out.dgram(), now()));
|
||||||
assert!(maybe_authenticate(&mut client));
|
assert!(maybe_authenticate(&mut client));
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
|
|
||||||
// client now in State::Connected
|
// client now in State::Connected
|
||||||
assert_eq!(client.stream_create(StreamType::UniDi).unwrap(), 2);
|
assert_eq!(client.stream_create(StreamType::UniDi).unwrap(), 2);
|
||||||
|
@ -47,7 +47,7 @@ fn stream_create() {
|
||||||
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
|
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
|
||||||
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 4);
|
assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 4);
|
||||||
|
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(server.process(out.dgram(), now()));
|
||||||
// server now in State::Connected
|
// server now in State::Connected
|
||||||
assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 3);
|
assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 3);
|
||||||
assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 7);
|
assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 7);
|
||||||
|
@ -86,7 +86,7 @@ fn transfer() {
|
||||||
|
|
||||||
qdebug!("---- server receives");
|
qdebug!("---- server receives");
|
||||||
for d in datagrams {
|
for d in datagrams {
|
||||||
let out = server.process(Some(&d), now());
|
let out = server.process(Some(d), now());
|
||||||
// With an RTT of zero, the server will acknowledge every packet immediately.
|
// With an RTT of zero, the server will acknowledge every packet immediately.
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||||
|
@ -151,7 +151,7 @@ fn sendorder_test(order_of_sendorder: &[Option<SendOrder>]) {
|
||||||
|
|
||||||
qdebug!("---- server receives");
|
qdebug!("---- server receives");
|
||||||
for d in datagrams {
|
for d in datagrams {
|
||||||
let out = server.process(Some(&d), now());
|
let out = server.process(Some(d), now());
|
||||||
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
qdebug!("Output={:0x?}", out.as_dgram_ref());
|
||||||
}
|
}
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
|
@ -317,12 +317,12 @@ fn report_fin_when_stream_closed_wo_data() {
|
||||||
// create a stream
|
// create a stream
|
||||||
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(server.process(out.dgram(), now()));
|
||||||
|
|
||||||
server.stream_close_send(stream_id).unwrap();
|
server.stream_close_send(stream_id).unwrap();
|
||||||
let out = server.process(None, now());
|
let out = server.process_output(now());
|
||||||
mem::drop(client.process(out.as_dgram_ref(), now()));
|
mem::drop(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));
|
assert!(client.events().any(stream_readable));
|
||||||
}
|
}
|
||||||
|
@ -330,9 +330,9 @@ fn report_fin_when_stream_closed_wo_data() {
|
||||||
fn exchange_data(client: &mut Connection, server: &mut Connection) {
|
fn exchange_data(client: &mut Connection, server: &mut Connection) {
|
||||||
let mut input = None;
|
let mut input = None;
|
||||||
loop {
|
loop {
|
||||||
let out = client.process(input.as_ref(), now()).dgram();
|
let out = client.process(input, now()).dgram();
|
||||||
let c_done = out.is_none();
|
let c_done = out.is_none();
|
||||||
let out = server.process(out.as_ref(), now()).dgram();
|
let out = server.process(out, now()).dgram();
|
||||||
if out.is_none() && c_done {
|
if out.is_none() && c_done {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -373,8 +373,8 @@ fn sending_max_data() {
|
||||||
assert_eq!(received, SMALL_MAX_DATA);
|
assert_eq!(received, SMALL_MAX_DATA);
|
||||||
assert!(!fin);
|
assert!(!fin);
|
||||||
|
|
||||||
let out = server.process(None, now()).dgram();
|
let out = server.process_output(now()).dgram();
|
||||||
client.process_input(&out.unwrap(), now());
|
client.process_input(out.unwrap(), now());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client
|
client
|
||||||
|
@ -511,8 +511,8 @@ fn do_not_accept_data_after_stop_sending() {
|
||||||
// create a stream
|
// create a stream
|
||||||
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(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));
|
assert!(server.events().any(stream_readable));
|
||||||
|
@ -520,7 +520,7 @@ fn do_not_accept_data_after_stop_sending() {
|
||||||
// Send one more packet from client. The packet should arrive after the server
|
// Send one more packet from client. The packet should arrive after the server
|
||||||
// has already requested stop_sending.
|
// has already requested stop_sending.
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
let out_second_data_frame = client.process(None, now());
|
let out_second_data_frame = client.process_output(now());
|
||||||
// Call stop sending.
|
// Call stop sending.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok(()),
|
Ok(()),
|
||||||
|
@ -529,10 +529,10 @@ fn do_not_accept_data_after_stop_sending() {
|
||||||
|
|
||||||
// Receive the second data frame. The frame should be ignored and
|
// Receive the second data frame. The frame should be ignored and
|
||||||
// DataReadable events shouldn't be posted.
|
// DataReadable events shouldn't be posted.
|
||||||
let out = server.process(out_second_data_frame.as_dgram_ref(), now());
|
let out = server.process(out_second_data_frame.dgram(), now());
|
||||||
assert!(!server.events().any(stream_readable));
|
assert!(!server.events().any(stream_readable));
|
||||||
|
|
||||||
mem::drop(client.process(out.as_dgram_ref(), now()));
|
mem::drop(client.process(out.dgram(), now()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(Error::FinalSizeError),
|
Err(Error::FinalSizeError),
|
||||||
client.stream_send(stream_id, &[0x00])
|
client.stream_send(stream_id, &[0x00])
|
||||||
|
@ -549,8 +549,8 @@ fn simultaneous_stop_sending_and_reset() {
|
||||||
// create a stream
|
// create a stream
|
||||||
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
let ack = server.process(out.as_dgram_ref(), now()).dgram();
|
let ack = server.process(out.dgram(), now()).dgram();
|
||||||
|
|
||||||
let stream_readable =
|
let stream_readable =
|
||||||
|e| matches!(e, ConnectionEvent::RecvStreamReadable { stream_id: id } if id == stream_id);
|
|e| matches!(e, ConnectionEvent::RecvStreamReadable { stream_id: id } if id == stream_id);
|
||||||
|
@ -559,23 +559,23 @@ fn simultaneous_stop_sending_and_reset() {
|
||||||
// The client resets the stream. The packet with reset should arrive after the server
|
// The client resets the stream. The packet with reset should arrive after the server
|
||||||
// has already requested stop_sending.
|
// has already requested stop_sending.
|
||||||
client.stream_reset_send(stream_id, 0).unwrap();
|
client.stream_reset_send(stream_id, 0).unwrap();
|
||||||
let out_reset_frame = client.process(ack.as_ref(), now()).dgram();
|
let out_reset_frame = client.process(ack, now()).dgram();
|
||||||
|
|
||||||
// Send something out of order to force the server to generate an
|
// Send something out of order to force the server to generate an
|
||||||
// acknowledgment at the next opportunity.
|
// acknowledgment at the next opportunity.
|
||||||
let force_ack = send_something(&mut client, now());
|
let force_ack = send_something(&mut client, now());
|
||||||
server.process_input(&force_ack, now());
|
server.process_input(force_ack, now());
|
||||||
|
|
||||||
// Call stop sending.
|
// Call stop sending.
|
||||||
server.stream_stop_sending(stream_id, 0).unwrap();
|
server.stream_stop_sending(stream_id, 0).unwrap();
|
||||||
// Receive the second data frame. The frame should be ignored and
|
// Receive the second data frame. The frame should be ignored and
|
||||||
// DataReadable events shouldn't be posted.
|
// DataReadable events shouldn't be posted.
|
||||||
let ack = server.process(out_reset_frame.as_ref(), now()).dgram();
|
let ack = server.process(out_reset_frame, now()).dgram();
|
||||||
assert!(ack.is_some());
|
assert!(ack.is_some());
|
||||||
assert!(!server.events().any(stream_readable));
|
assert!(!server.events().any(stream_readable));
|
||||||
|
|
||||||
// The client gets the STOP_SENDING frame.
|
// The client gets the STOP_SENDING frame.
|
||||||
client.process_input(&ack.unwrap(), now());
|
client.process_input(ack.unwrap(), now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(Error::InvalidStreamId),
|
Err(Error::InvalidStreamId),
|
||||||
client.stream_send(stream_id, &[0x00])
|
client.stream_send(stream_id, &[0x00])
|
||||||
|
@ -588,35 +588,35 @@ fn client_fin_reorder() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
// Send ClientHello.
|
// Send ClientHello.
|
||||||
let client_hs = client.process(None, now());
|
let client_hs = client.process_output(now());
|
||||||
assert!(client_hs.as_dgram_ref().is_some());
|
assert!(client_hs.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let server_hs = server.process(client_hs.as_dgram_ref(), now());
|
let server_hs = server.process(client_hs.dgram(), now());
|
||||||
assert!(server_hs.as_dgram_ref().is_some()); // ServerHello, etc...
|
assert!(server_hs.as_dgram_ref().is_some()); // ServerHello, etc...
|
||||||
|
|
||||||
let client_ack = client.process(server_hs.as_dgram_ref(), now());
|
let client_ack = client.process(server_hs.dgram(), now());
|
||||||
assert!(client_ack.as_dgram_ref().is_some());
|
assert!(client_ack.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let server_out = server.process(client_ack.as_dgram_ref(), now());
|
let server_out = server.process(client_ack.dgram(), now());
|
||||||
assert!(server_out.as_dgram_ref().is_none());
|
assert!(server_out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
assert!(maybe_authenticate(&mut client));
|
assert!(maybe_authenticate(&mut client));
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
let client_fin = client.process(None, now());
|
let client_fin = client.process_output(now());
|
||||||
assert!(client_fin.as_dgram_ref().is_some());
|
assert!(client_fin.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
|
client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
|
||||||
let client_stream_data = client.process(None, now());
|
let client_stream_data = client.process_output(now());
|
||||||
assert!(client_stream_data.as_dgram_ref().is_some());
|
assert!(client_stream_data.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// Now stream data gets before client_fin
|
// Now stream data gets before client_fin
|
||||||
let server_out = server.process(client_stream_data.as_dgram_ref(), now());
|
let server_out = server.process(client_stream_data.dgram(), now());
|
||||||
assert!(server_out.as_dgram_ref().is_none()); // the packet will be discarded
|
assert!(server_out.as_dgram_ref().is_none()); // the packet will be discarded
|
||||||
|
|
||||||
assert_eq!(*server.state(), State::Handshaking);
|
assert_eq!(*server.state(), State::Handshaking);
|
||||||
let server_out = server.process(client_fin.as_dgram_ref(), now());
|
let server_out = server.process(client_fin.dgram(), now());
|
||||||
assert!(server_out.as_dgram_ref().is_some());
|
assert!(server_out.as_dgram_ref().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,10 +629,10 @@ fn after_fin_is_read_conn_events_for_stream_should_be_removed() {
|
||||||
let id = server.stream_create(StreamType::BiDi).unwrap();
|
let id = server.stream_create(StreamType::BiDi).unwrap();
|
||||||
server.stream_send(id, &[6; 10]).unwrap();
|
server.stream_send(id, &[6; 10]).unwrap();
|
||||||
server.stream_close_send(id).unwrap();
|
server.stream_close_send(id).unwrap();
|
||||||
let out = server.process(None, now()).dgram();
|
let out = server.process_output(now()).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
|
|
||||||
mem::drop(client.process(out.as_ref(), now()));
|
mem::drop(client.process(out, now()));
|
||||||
|
|
||||||
// read from the stream before checking connection events.
|
// read from the stream before checking connection events.
|
||||||
let mut buf = vec![0; 4000];
|
let mut buf = vec![0; 4000];
|
||||||
|
@ -654,10 +654,10 @@ fn after_stream_stop_sending_is_called_conn_events_for_stream_should_be_removed(
|
||||||
let id = server.stream_create(StreamType::BiDi).unwrap();
|
let id = server.stream_create(StreamType::BiDi).unwrap();
|
||||||
server.stream_send(id, &[6; 10]).unwrap();
|
server.stream_send(id, &[6; 10]).unwrap();
|
||||||
server.stream_close_send(id).unwrap();
|
server.stream_close_send(id).unwrap();
|
||||||
let out = server.process(None, now()).dgram();
|
let out = server.process_output(now()).dgram();
|
||||||
assert!(out.is_some());
|
assert!(out.is_some());
|
||||||
|
|
||||||
mem::drop(client.process(out.as_ref(), now()));
|
mem::drop(client.process(out, now()));
|
||||||
|
|
||||||
// send stop seending.
|
// send stop seending.
|
||||||
client
|
client
|
||||||
|
@ -682,11 +682,11 @@ fn stream_data_blocked_generates_max_stream_data() {
|
||||||
// Send some data and consume some flow control.
|
// Send some data and consume some flow control.
|
||||||
let stream_id = server.stream_create(StreamType::UniDi).unwrap();
|
let stream_id = server.stream_create(StreamType::UniDi).unwrap();
|
||||||
_ = server.stream_send(stream_id, DEFAULT_STREAM_DATA).unwrap();
|
_ = server.stream_send(stream_id, DEFAULT_STREAM_DATA).unwrap();
|
||||||
let dgram = server.process(None, now).dgram();
|
let dgram = server.process_output(now).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
// Consume the data.
|
// Consume the data.
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
let mut buf = [0; 10];
|
let mut buf = [0; 10];
|
||||||
let (count, end) = client.stream_recv(stream_id, &mut buf[..]).unwrap();
|
let (count, end) = client.stream_recv(stream_id, &mut buf[..]).unwrap();
|
||||||
assert_eq!(count, DEFAULT_STREAM_DATA.len());
|
assert_eq!(count, DEFAULT_STREAM_DATA.len());
|
||||||
|
@ -703,14 +703,14 @@ fn stream_data_blocked_generates_max_stream_data() {
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
let sdb_before = client.stats().frame_rx.stream_data_blocked;
|
let sdb_before = client.stats().frame_rx.stream_data_blocked;
|
||||||
let dgram = client.process(dgram.as_ref(), now).dgram();
|
let dgram = client.process(dgram, now).dgram();
|
||||||
assert_eq!(client.stats().frame_rx.stream_data_blocked, sdb_before + 1);
|
assert_eq!(client.stats().frame_rx.stream_data_blocked, sdb_before + 1);
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
// Client should have sent a MAX_STREAM_DATA frame with just a small increase
|
// Client should have sent a MAX_STREAM_DATA frame with just a small increase
|
||||||
// on the default window size.
|
// on the default window size.
|
||||||
let msd_before = server.stats().frame_rx.max_stream_data;
|
let msd_before = server.stats().frame_rx.max_stream_data;
|
||||||
server.process_input(&dgram.unwrap(), now);
|
server.process_input(dgram.unwrap(), now);
|
||||||
assert_eq!(server.stats().frame_rx.max_stream_data, msd_before + 1);
|
assert_eq!(server.stats().frame_rx.max_stream_data, msd_before + 1);
|
||||||
|
|
||||||
// Test that the entirety of the receive buffer is available now.
|
// Test that the entirety of the receive buffer is available now.
|
||||||
|
@ -742,22 +742,22 @@ fn max_streams_after_bidi_closed() {
|
||||||
// Write on the one stream and send that out.
|
// Write on the one stream and send that out.
|
||||||
_ = client.stream_send(stream_id, REQUEST).unwrap();
|
_ = client.stream_send(stream_id, REQUEST).unwrap();
|
||||||
client.stream_close_send(stream_id).unwrap();
|
client.stream_close_send(stream_id).unwrap();
|
||||||
let dgram = client.process(None, now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
|
|
||||||
// Now handle the stream and send an incomplete response.
|
// Now handle the stream and send an incomplete response.
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
server.stream_send(stream_id, RESPONSE).unwrap();
|
server.stream_send(stream_id, RESPONSE).unwrap();
|
||||||
let dgram = server.process_output(now()).dgram();
|
let dgram = server.process_output(now()).dgram();
|
||||||
|
|
||||||
// The server shouldn't have released more stream credit.
|
// The server shouldn't have released more stream credit.
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
let e = client.stream_create(StreamType::BiDi).unwrap_err();
|
let e = client.stream_create(StreamType::BiDi).unwrap_err();
|
||||||
assert!(matches!(e, Error::StreamLimitError));
|
assert!(matches!(e, Error::StreamLimitError));
|
||||||
|
|
||||||
// Closing the stream isn't enough.
|
// Closing the stream isn't enough.
|
||||||
server.stream_close_send(stream_id).unwrap();
|
server.stream_close_send(stream_id).unwrap();
|
||||||
let dgram = server.process_output(now()).dgram();
|
let dgram = server.process_output(now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert!(client.stream_create(StreamType::BiDi).is_err());
|
assert!(client.stream_create(StreamType::BiDi).is_err());
|
||||||
|
|
||||||
// The server needs to see an acknowledgment from the client for its
|
// The server needs to see an acknowledgment from the client for its
|
||||||
|
@ -771,12 +771,12 @@ fn max_streams_after_bidi_closed() {
|
||||||
// We need an ACK from the client now, but that isn't guaranteed,
|
// We need an ACK from the client now, but that isn't guaranteed,
|
||||||
// so give the client one more packet just in case.
|
// so give the client one more packet just in case.
|
||||||
let dgram = send_something(&mut server, now());
|
let dgram = send_something(&mut server, now());
|
||||||
client.process_input(&dgram, now());
|
client.process_input(dgram, now());
|
||||||
|
|
||||||
// Now get the client to send the ACK and have the server handle that.
|
// Now get the client to send the ACK and have the server handle that.
|
||||||
let dgram = send_something(&mut client, now());
|
let dgram = send_something(&mut client, now());
|
||||||
let dgram = server.process(Some(&dgram), now()).dgram();
|
let dgram = server.process(Some(dgram), now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert!(client.stream_create(StreamType::BiDi).is_ok());
|
assert!(client.stream_create(StreamType::BiDi).is_ok());
|
||||||
assert!(client.stream_create(StreamType::BiDi).is_err());
|
assert!(client.stream_create(StreamType::BiDi).is_err());
|
||||||
}
|
}
|
||||||
|
@ -790,8 +790,8 @@ fn no_dupdata_readable_events() {
|
||||||
// create a stream
|
// create a stream
|
||||||
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(server.process(out.dgram(), now()));
|
||||||
|
|
||||||
// We have a data_readable event.
|
// We have a data_readable event.
|
||||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
||||||
|
@ -800,16 +800,16 @@ fn no_dupdata_readable_events() {
|
||||||
// Send one more data frame from client. The previous stream data has not been read yet,
|
// Send one more data frame from client. The previous stream data has not been read yet,
|
||||||
// therefore there should not be a new DataReadable event.
|
// therefore there should not be a new DataReadable event.
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
let out_second_data_frame = client.process(None, now());
|
let out_second_data_frame = client.process_output(now());
|
||||||
mem::drop(server.process(out_second_data_frame.as_dgram_ref(), now()));
|
mem::drop(server.process(out_second_data_frame.dgram(), now()));
|
||||||
assert!(!server.events().any(stream_readable));
|
assert!(!server.events().any(stream_readable));
|
||||||
|
|
||||||
// One more frame with a fin will not produce a new DataReadable event, because the
|
// One more frame with a fin will not produce a new DataReadable event, because the
|
||||||
// previous stream data has not been read yet.
|
// previous stream data has not been read yet.
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
client.stream_close_send(stream_id).unwrap();
|
client.stream_close_send(stream_id).unwrap();
|
||||||
let out_third_data_frame = client.process(None, now());
|
let out_third_data_frame = client.process_output(now());
|
||||||
mem::drop(server.process(out_third_data_frame.as_dgram_ref(), now()));
|
mem::drop(server.process(out_third_data_frame.dgram(), now()));
|
||||||
assert!(!server.events().any(stream_readable));
|
assert!(!server.events().any(stream_readable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,8 +822,8 @@ fn no_dupdata_readable_events_empty_last_frame() {
|
||||||
// create a stream
|
// create a stream
|
||||||
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
client.stream_send(stream_id, &[0x00]).unwrap();
|
client.stream_send(stream_id, &[0x00]).unwrap();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(server.process(out.dgram(), now()));
|
||||||
|
|
||||||
// We have a data_readable event.
|
// We have a data_readable event.
|
||||||
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
|
||||||
|
@ -832,8 +832,8 @@ fn no_dupdata_readable_events_empty_last_frame() {
|
||||||
// An empty frame with a fin will not produce a new DataReadable event, because
|
// An empty frame with a fin will not produce a new DataReadable event, because
|
||||||
// the previous stream data has not been read yet.
|
// the previous stream data has not been read yet.
|
||||||
client.stream_close_send(stream_id).unwrap();
|
client.stream_close_send(stream_id).unwrap();
|
||||||
let out_second_data_frame = client.process(None, now());
|
let out_second_data_frame = client.process_output(now());
|
||||||
mem::drop(server.process(out_second_data_frame.as_dgram_ref(), now()));
|
mem::drop(server.process(out_second_data_frame.dgram(), now()));
|
||||||
assert!(!server.events().any(stream_readable));
|
assert!(!server.events().any(stream_readable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,15 +854,15 @@ fn change_flow_control(stream_type: StreamType, new_fc: u64) {
|
||||||
assert_eq!(u64::try_from(written1).unwrap(), RECV_BUFFER_START);
|
assert_eq!(u64::try_from(written1).unwrap(), RECV_BUFFER_START);
|
||||||
|
|
||||||
// Send the stream to the client.
|
// Send the stream to the client.
|
||||||
let out = server.process(None, now());
|
let out = server.process_output(now());
|
||||||
mem::drop(client.process(out.as_dgram_ref(), now()));
|
mem::drop(client.process(out.dgram(), now()));
|
||||||
|
|
||||||
// change max_stream_data for stream_id.
|
// change max_stream_data for stream_id.
|
||||||
client.set_stream_max_data(stream_id, new_fc).unwrap();
|
client.set_stream_max_data(stream_id, new_fc).unwrap();
|
||||||
|
|
||||||
// server should receive a MAX_SREAM_DATA frame if the flow control window is updated.
|
// server should receive a MAX_SREAM_DATA frame if the flow control window is updated.
|
||||||
let out2 = client.process(None, now());
|
let out2 = client.process_output(now());
|
||||||
let out3 = server.process(out2.as_dgram_ref(), now());
|
let out3 = server.process(out2.dgram(), now());
|
||||||
let expected = usize::from(RECV_BUFFER_START < new_fc);
|
let expected = usize::from(RECV_BUFFER_START < new_fc);
|
||||||
assert_eq!(server.stats().frame_rx.max_stream_data, expected);
|
assert_eq!(server.stats().frame_rx.max_stream_data, expected);
|
||||||
|
|
||||||
|
@ -875,17 +875,17 @@ fn change_flow_control(stream_type: StreamType, new_fc: u64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exchange packets so that client gets all data.
|
// Exchange packets so that client gets all data.
|
||||||
let out4 = client.process(out3.as_dgram_ref(), now());
|
let out4 = client.process(out3.dgram(), now());
|
||||||
let out5 = server.process(out4.as_dgram_ref(), now());
|
let out5 = server.process(out4.dgram(), now());
|
||||||
mem::drop(client.process(out5.as_dgram_ref(), now()));
|
mem::drop(client.process(out5.dgram(), now()));
|
||||||
|
|
||||||
// read all data by client
|
// read all data by client
|
||||||
let mut buf = [0x0; 10000];
|
let mut buf = [0x0; 10000];
|
||||||
let (read, _) = client.stream_recv(stream_id, &mut buf).unwrap();
|
let (read, _) = client.stream_recv(stream_id, &mut buf).unwrap();
|
||||||
assert_eq!(u64::try_from(read).unwrap(), max(RECV_BUFFER_START, new_fc));
|
assert_eq!(u64::try_from(read).unwrap(), max(RECV_BUFFER_START, new_fc));
|
||||||
|
|
||||||
let out4 = client.process(None, now());
|
let out4 = client.process_output(now());
|
||||||
mem::drop(server.process(out4.as_dgram_ref(), now()));
|
mem::drop(server.process(out4.dgram(), now()));
|
||||||
|
|
||||||
let written3 = server.stream_send(stream_id, &[0x0; 10000]).unwrap();
|
let written3 = server.stream_send(stream_id, &[0x0; 10000]).unwrap();
|
||||||
assert_eq!(u64::try_from(written3).unwrap(), new_fc);
|
assert_eq!(u64::try_from(written3).unwrap(), new_fc);
|
||||||
|
@ -939,13 +939,13 @@ fn session_flow_control_stop_sending_state_recv() {
|
||||||
// In this case the final size is only known after RESET frame is received.
|
// In this case the final size is only known after RESET frame is received.
|
||||||
// The server sends STOP_SENDING -> the client sends RESET -> the server
|
// The server sends STOP_SENDING -> the client sends RESET -> the server
|
||||||
// sends MAX_DATA.
|
// sends MAX_DATA.
|
||||||
let out = server.process(None, now()).dgram();
|
let out = server.process_output(now()).dgram();
|
||||||
let out = client.process(out.as_ref(), now()).dgram();
|
let out = client.process(out, now()).dgram();
|
||||||
// the client is still limited.
|
// the client is still limited.
|
||||||
let stream_id2 = client.stream_create(StreamType::UniDi).unwrap();
|
let stream_id2 = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
assert_eq!(client.stream_avail_send_space(stream_id2).unwrap(), 0);
|
assert_eq!(client.stream_avail_send_space(stream_id2).unwrap(), 0);
|
||||||
let out = server.process(out.as_ref(), now()).dgram();
|
let out = server.process(out, now()).dgram();
|
||||||
client.process_input(&out.unwrap(), now());
|
client.process_input(out.unwrap(), now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client.stream_avail_send_space(stream_id2).unwrap(),
|
client.stream_avail_send_space(stream_id2).unwrap(),
|
||||||
SMALL_MAX_DATA
|
SMALL_MAX_DATA
|
||||||
|
@ -977,12 +977,12 @@ fn session_flow_control_stop_sending_state_size_known() {
|
||||||
SMALL_MAX_DATA
|
SMALL_MAX_DATA
|
||||||
);
|
);
|
||||||
|
|
||||||
let out1 = client.process(None, now()).dgram();
|
let out1 = client.process_output(now()).dgram();
|
||||||
// Delay this packet and let the server receive fin first (it will enter SizeKnown state).
|
// Delay this packet and let the server receive fin first (it will enter SizeKnown state).
|
||||||
client.stream_close_send(stream_id).unwrap();
|
client.stream_close_send(stream_id).unwrap();
|
||||||
let out2 = client.process(None, now()).dgram();
|
let out2 = client.process_output(now()).dgram();
|
||||||
|
|
||||||
server.process_input(&out2.unwrap(), now());
|
server.process_input(out2.unwrap(), now());
|
||||||
|
|
||||||
server
|
server
|
||||||
.stream_stop_sending(stream_id, Error::NoError.code())
|
.stream_stop_sending(stream_id, Error::NoError.code())
|
||||||
|
@ -991,8 +991,8 @@ fn session_flow_control_stop_sending_state_size_known() {
|
||||||
// In this case the final size is known when stream_stop_sending is called
|
// In this case the final size is known when stream_stop_sending is called
|
||||||
// and the server releases flow control immediately and sends STOP_SENDING and
|
// and the server releases flow control immediately and sends STOP_SENDING and
|
||||||
// MAX_DATA in the same packet.
|
// MAX_DATA in the same packet.
|
||||||
let out = server.process(out1.as_ref(), now()).dgram();
|
let out = server.process(out1, now()).dgram();
|
||||||
client.process_input(&out.unwrap(), now());
|
client.process_input(out.unwrap(), now());
|
||||||
|
|
||||||
// The flow control should have been updated and the client can again send
|
// The flow control should have been updated and the client can again send
|
||||||
// SMALL_MAX_DATA.
|
// SMALL_MAX_DATA.
|
||||||
|
@ -1108,16 +1108,16 @@ fn session_flow_control_affects_all_streams() {
|
||||||
|
|
||||||
fn connect_w_different_limit(bidi_limit: u64, unidi_limit: u64) {
|
fn connect_w_different_limit(bidi_limit: u64, unidi_limit: u64) {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
let mut server = new_server(
|
let mut server = new_server(
|
||||||
ConnectionParameters::default()
|
ConnectionParameters::default()
|
||||||
.max_streams(StreamType::BiDi, bidi_limit)
|
.max_streams(StreamType::BiDi, bidi_limit)
|
||||||
.max_streams(StreamType::UniDi, unidi_limit),
|
.max_streams(StreamType::UniDi, unidi_limit),
|
||||||
);
|
);
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
|
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(server.process(out.dgram(), now()));
|
||||||
|
|
||||||
assert!(maybe_authenticate(&mut client));
|
assert!(maybe_authenticate(&mut client));
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ const INITIAL_PTO: Duration = Duration::from_millis(300);
|
||||||
fn unknown_version() {
|
fn unknown_version() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
mem::drop(client.process(None, now()).dgram());
|
mem::drop(client.process_output(now()).dgram());
|
||||||
|
|
||||||
let mut unknown_version_packet = vec![0x80, 0x1a, 0x1a, 0x1a, 0x1a];
|
let mut unknown_version_packet = vec![0x80, 0x1a, 0x1a, 0x1a, 0x1a];
|
||||||
unknown_version_packet.resize(MIN_INITIAL_PACKET_SIZE, 0x0);
|
unknown_version_packet.resize(MIN_INITIAL_PACKET_SIZE, 0x0);
|
||||||
mem::drop(client.process(Some(&datagram(unknown_version_packet)), now()));
|
mem::drop(client.process(Some(datagram(unknown_version_packet)), now()));
|
||||||
assert_eq!(1, client.stats().dropped_rx);
|
assert_eq!(1, client.stats().dropped_rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ fn server_receive_unknown_first_packet() {
|
||||||
unknown_version_packet.resize(MIN_INITIAL_PACKET_SIZE, 0x0);
|
unknown_version_packet.resize(MIN_INITIAL_PACKET_SIZE, 0x0);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
server.process(Some(&datagram(unknown_version_packet)), now()),
|
server.process(Some(datagram(unknown_version_packet)), now()),
|
||||||
Output::None
|
Output::None
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ fn version_negotiation_current_version() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let initial_pkt = client
|
let initial_pkt = client
|
||||||
.process(None, now())
|
.process_output(now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.expect("a datagram")
|
.expect("a datagram")
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
@ -83,7 +83,7 @@ fn version_negotiation_current_version() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let dgram = datagram(vn);
|
let dgram = datagram(vn);
|
||||||
let delay = client.process(Some(&dgram), now()).callback();
|
let delay = client.process(Some(dgram), now()).callback();
|
||||||
assert_eq!(delay, INITIAL_PTO);
|
assert_eq!(delay, INITIAL_PTO);
|
||||||
assert_eq!(*client.state(), State::WaitInitial);
|
assert_eq!(*client.state(), State::WaitInitial);
|
||||||
assert_eq!(1, client.stats().dropped_rx);
|
assert_eq!(1, client.stats().dropped_rx);
|
||||||
|
@ -94,7 +94,7 @@ fn version_negotiation_version0() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let initial_pkt = client
|
let initial_pkt = client
|
||||||
.process(None, now())
|
.process_output(now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.expect("a datagram")
|
.expect("a datagram")
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
@ -102,7 +102,7 @@ fn version_negotiation_version0() {
|
||||||
let vn = create_vn(&initial_pkt, &[0, 0x1a1a_1a1a]);
|
let vn = create_vn(&initial_pkt, &[0, 0x1a1a_1a1a]);
|
||||||
|
|
||||||
let dgram = datagram(vn);
|
let dgram = datagram(vn);
|
||||||
let delay = client.process(Some(&dgram), now()).callback();
|
let delay = client.process(Some(dgram), now()).callback();
|
||||||
assert_eq!(delay, INITIAL_PTO);
|
assert_eq!(delay, INITIAL_PTO);
|
||||||
assert_eq!(*client.state(), State::WaitInitial);
|
assert_eq!(*client.state(), State::WaitInitial);
|
||||||
assert_eq!(1, client.stats().dropped_rx);
|
assert_eq!(1, client.stats().dropped_rx);
|
||||||
|
@ -113,7 +113,7 @@ fn version_negotiation_only_reserved() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let initial_pkt = client
|
let initial_pkt = client
|
||||||
.process(None, now())
|
.process_output(now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.expect("a datagram")
|
.expect("a datagram")
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
@ -121,7 +121,7 @@ fn version_negotiation_only_reserved() {
|
||||||
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]);
|
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]);
|
||||||
|
|
||||||
let dgram = datagram(vn);
|
let dgram = datagram(vn);
|
||||||
assert_eq!(client.process(Some(&dgram), now()), Output::None);
|
assert_eq!(client.process(Some(dgram), now()), Output::None);
|
||||||
match client.state() {
|
match client.state() {
|
||||||
State::Closed(err) => {
|
State::Closed(err) => {
|
||||||
assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation));
|
assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation));
|
||||||
|
@ -135,7 +135,7 @@ fn version_negotiation_corrupted() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let initial_pkt = client
|
let initial_pkt = client
|
||||||
.process(None, now())
|
.process_output(now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.expect("a datagram")
|
.expect("a datagram")
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
@ -143,7 +143,7 @@ fn version_negotiation_corrupted() {
|
||||||
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]);
|
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]);
|
||||||
|
|
||||||
let dgram = datagram(vn[..vn.len() - 1].to_vec());
|
let dgram = datagram(vn[..vn.len() - 1].to_vec());
|
||||||
let delay = client.process(Some(&dgram), now()).callback();
|
let delay = client.process(Some(dgram), now()).callback();
|
||||||
assert_eq!(delay, INITIAL_PTO);
|
assert_eq!(delay, INITIAL_PTO);
|
||||||
assert_eq!(*client.state(), State::WaitInitial);
|
assert_eq!(*client.state(), State::WaitInitial);
|
||||||
assert_eq!(1, client.stats().dropped_rx);
|
assert_eq!(1, client.stats().dropped_rx);
|
||||||
|
@ -154,7 +154,7 @@ fn version_negotiation_empty() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let initial_pkt = client
|
let initial_pkt = client
|
||||||
.process(None, now())
|
.process_output(now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.expect("a datagram")
|
.expect("a datagram")
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
@ -162,7 +162,7 @@ fn version_negotiation_empty() {
|
||||||
let vn = create_vn(&initial_pkt, &[]);
|
let vn = create_vn(&initial_pkt, &[]);
|
||||||
|
|
||||||
let dgram = datagram(vn);
|
let dgram = datagram(vn);
|
||||||
let delay = client.process(Some(&dgram), now()).callback();
|
let delay = client.process(Some(dgram), now()).callback();
|
||||||
assert_eq!(delay, INITIAL_PTO);
|
assert_eq!(delay, INITIAL_PTO);
|
||||||
assert_eq!(*client.state(), State::WaitInitial);
|
assert_eq!(*client.state(), State::WaitInitial);
|
||||||
assert_eq!(1, client.stats().dropped_rx);
|
assert_eq!(1, client.stats().dropped_rx);
|
||||||
|
@ -173,14 +173,14 @@ fn version_negotiation_not_supported() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let initial_pkt = client
|
let initial_pkt = client
|
||||||
.process(None, now())
|
.process_output(now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.expect("a datagram")
|
.expect("a datagram")
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
|
||||||
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
|
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
|
||||||
let dgram = datagram(vn);
|
let dgram = datagram(vn);
|
||||||
assert_eq!(client.process(Some(&dgram), now()), Output::None);
|
assert_eq!(client.process(Some(dgram), now()), Output::None);
|
||||||
match client.state() {
|
match client.state() {
|
||||||
State::Closed(err) => {
|
State::Closed(err) => {
|
||||||
assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation));
|
assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation));
|
||||||
|
@ -194,7 +194,7 @@ fn version_negotiation_bad_cid() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
// Start the handshake.
|
// Start the handshake.
|
||||||
let mut initial_pkt = client
|
let mut initial_pkt = client
|
||||||
.process(None, now())
|
.process_output(now())
|
||||||
.dgram()
|
.dgram()
|
||||||
.expect("a datagram")
|
.expect("a datagram")
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
@ -203,7 +203,7 @@ fn version_negotiation_bad_cid() {
|
||||||
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
|
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
|
||||||
|
|
||||||
let dgram = datagram(vn);
|
let dgram = datagram(vn);
|
||||||
let delay = client.process(Some(&dgram), now()).callback();
|
let delay = client.process(Some(dgram), now()).callback();
|
||||||
assert_eq!(delay, INITIAL_PTO);
|
assert_eq!(delay, INITIAL_PTO);
|
||||||
assert_eq!(*client.state(), State::WaitInitial);
|
assert_eq!(*client.state(), State::WaitInitial);
|
||||||
assert_eq!(1, client.stats().dropped_rx);
|
assert_eq!(1, client.stats().dropped_rx);
|
||||||
|
@ -240,11 +240,11 @@ fn compatible_upgrade_large_initial() {
|
||||||
// Each should elicit a Version 1 ACK from the server.
|
// Each should elicit a Version 1 ACK from the server.
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
// The following uses the Version from *outside* this crate.
|
// The following uses the Version from *outside* this crate.
|
||||||
assertions::assert_version(dgram.as_ref().unwrap(), Version::Version1.wire_version());
|
assertions::assert_version(dgram.as_ref().unwrap(), Version::Version1.wire_version());
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
connect(&mut client, &mut server);
|
connect(&mut client, &mut server);
|
||||||
assert_eq!(client.version(), Version::Version2);
|
assert_eq!(client.version(), Version::Version2);
|
||||||
|
@ -308,7 +308,7 @@ fn version_negotiation_downgrade() {
|
||||||
let initial = client.process_output(now()).dgram().unwrap();
|
let initial = client.process_output(now()).dgram().unwrap();
|
||||||
let vn = create_vn(&initial, &[DOWNGRADE.wire_version()]);
|
let vn = create_vn(&initial, &[DOWNGRADE.wire_version()]);
|
||||||
let dgram = datagram(vn);
|
let dgram = datagram(vn);
|
||||||
client.process_input(&dgram, now());
|
client.process_input(dgram, now());
|
||||||
|
|
||||||
connect_fail(
|
connect_fail(
|
||||||
&mut client,
|
&mut client,
|
||||||
|
@ -328,7 +328,7 @@ fn invalid_server_version() {
|
||||||
new_server(ConnectionParameters::default().versions(Version::Version2, Version::all()));
|
new_server(ConnectionParameters::default().versions(Version::Version2, Version::all()));
|
||||||
|
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
server.process_input(&dgram.unwrap(), now());
|
server.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
// One packet received.
|
// One packet received.
|
||||||
assert_eq!(server.stats().packets_rx, 1);
|
assert_eq!(server.stats().packets_rx, 1);
|
||||||
|
@ -459,7 +459,7 @@ fn compatible_upgrade_0rtt_rejected() {
|
||||||
let initial = send_something(&mut client, now());
|
let initial = send_something(&mut client, now());
|
||||||
assertions::assert_version(&initial, Version::Version1.wire_version());
|
assertions::assert_version(&initial, Version::Version1.wire_version());
|
||||||
assertions::assert_coalesced_0rtt(&initial);
|
assertions::assert_coalesced_0rtt(&initial);
|
||||||
server.process_input(&initial, now());
|
server.process_input(initial, now());
|
||||||
assert!(!server
|
assert!(!server
|
||||||
.events()
|
.events()
|
||||||
.any(|e| matches!(e, ConnectionEvent::NewStream { .. })));
|
.any(|e| matches!(e, ConnectionEvent::NewStream { .. })));
|
||||||
|
@ -467,9 +467,9 @@ fn compatible_upgrade_0rtt_rejected() {
|
||||||
// Finalize the connection. Don't use connect() because it uses
|
// Finalize the connection. Don't use connect() because it uses
|
||||||
// maybe_authenticate() too liberally and that eats the events we want to check.
|
// maybe_authenticate() too liberally and that eats the events we want to check.
|
||||||
let dgram = server.process_output(now()).dgram(); // ServerHello flight
|
let dgram = server.process_output(now()).dgram(); // ServerHello flight
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram(); // Client Finished (note: no authentication)
|
let dgram = client.process(dgram, now()).dgram(); // Client Finished (note: no authentication)
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // HANDSHAKE_DONE
|
let dgram = server.process(dgram, now()).dgram(); // HANDSHAKE_DONE
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
assert!(matches!(client.state(), State::Confirmed));
|
assert!(matches!(client.state(), State::Confirmed));
|
||||||
assert!(matches!(server.state(), State::Confirmed));
|
assert!(matches!(server.state(), State::Confirmed));
|
||||||
|
|
|
@ -52,24 +52,24 @@ fn zero_rtt_send_recv() {
|
||||||
let mut server = resumed_server(&client);
|
let mut server = resumed_server(&client);
|
||||||
|
|
||||||
// Send ClientHello.
|
// Send ClientHello.
|
||||||
let client_hs = client.process(None, now());
|
let client_hs = client.process_output(now());
|
||||||
assert!(client_hs.as_dgram_ref().is_some());
|
assert!(client_hs.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// Now send a 0-RTT packet.
|
// Now send a 0-RTT packet.
|
||||||
let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
|
client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
|
||||||
let client_0rtt = client.process(None, now());
|
let client_0rtt = client.process_output(now());
|
||||||
assert!(client_0rtt.as_dgram_ref().is_some());
|
assert!(client_0rtt.as_dgram_ref().is_some());
|
||||||
// 0-RTT packets on their own shouldn't be padded to MIN_INITIAL_PACKET_SIZE.
|
// 0-RTT packets on their own shouldn't be padded to MIN_INITIAL_PACKET_SIZE.
|
||||||
assert!(client_0rtt.as_dgram_ref().unwrap().len() < MIN_INITIAL_PACKET_SIZE);
|
assert!(client_0rtt.as_dgram_ref().unwrap().len() < MIN_INITIAL_PACKET_SIZE);
|
||||||
|
|
||||||
let server_hs = server.process(client_hs.as_dgram_ref(), now());
|
let server_hs = server.process(client_hs.dgram(), now());
|
||||||
assert!(server_hs.as_dgram_ref().is_some()); // ServerHello, etc...
|
assert!(server_hs.as_dgram_ref().is_some()); // ServerHello, etc...
|
||||||
|
|
||||||
let all_frames = server.stats().frame_tx.all();
|
let all_frames = server.stats().frame_tx.all();
|
||||||
let ack_frames = server.stats().frame_tx.ack;
|
let ack_frames = server.stats().frame_tx.ack;
|
||||||
let server_process_0rtt = server.process(client_0rtt.as_dgram_ref(), now());
|
let server_process_0rtt = server.process(client_0rtt.dgram(), now());
|
||||||
assert!(server_process_0rtt.as_dgram_ref().is_some());
|
assert!(server_process_0rtt.dgram().is_some());
|
||||||
assert_eq!(server.stats().frame_tx.all(), all_frames + 1);
|
assert_eq!(server.stats().frame_tx.all(), all_frames + 1);
|
||||||
assert_eq!(server.stats().frame_tx.ack, ack_frames + 1);
|
assert_eq!(server.stats().frame_tx.ack, ack_frames + 1);
|
||||||
|
|
||||||
|
@ -100,12 +100,12 @@ fn zero_rtt_send_coalesce() {
|
||||||
// This should result in a datagram that coalesces Initial and 0-RTT.
|
// This should result in a datagram that coalesces Initial and 0-RTT.
|
||||||
let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
let client_stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
|
client.stream_send(client_stream_id, &[1, 2, 3]).unwrap();
|
||||||
let client_0rtt = client.process(None, now());
|
let client_0rtt = client.process_output(now());
|
||||||
assert!(client_0rtt.as_dgram_ref().is_some());
|
assert!(client_0rtt.as_dgram_ref().is_some());
|
||||||
|
|
||||||
assertions::assert_coalesced_0rtt(&client_0rtt.as_dgram_ref().unwrap()[..]);
|
assertions::assert_coalesced_0rtt(&client_0rtt.as_dgram_ref().unwrap()[..]);
|
||||||
|
|
||||||
let server_hs = server.process(client_0rtt.as_dgram_ref(), now());
|
let server_hs = server.process(client_0rtt.dgram(), now());
|
||||||
assert!(server_hs.as_dgram_ref().is_some()); // Should produce ServerHello etc...
|
assert!(server_hs.as_dgram_ref().is_some()); // Should produce ServerHello etc...
|
||||||
|
|
||||||
let server_stream_id = server
|
let server_stream_id = server
|
||||||
|
@ -153,18 +153,18 @@ fn zero_rtt_send_reject() {
|
||||||
.expect("enable 0-RTT");
|
.expect("enable 0-RTT");
|
||||||
|
|
||||||
// Send ClientHello.
|
// Send ClientHello.
|
||||||
let client_hs = client.process(None, now());
|
let client_hs = client.process_output(now());
|
||||||
assert!(client_hs.as_dgram_ref().is_some());
|
assert!(client_hs.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// Write some data on the client.
|
// Write some data on the client.
|
||||||
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_send(stream_id, MESSAGE).unwrap();
|
client.stream_send(stream_id, MESSAGE).unwrap();
|
||||||
let client_0rtt = client.process(None, now());
|
let client_0rtt = client.process_output(now());
|
||||||
assert!(client_0rtt.as_dgram_ref().is_some());
|
assert!(client_0rtt.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let server_hs = server.process(client_hs.as_dgram_ref(), now());
|
let server_hs = server.process(client_hs.dgram(), now());
|
||||||
assert!(server_hs.as_dgram_ref().is_some()); // Should produce ServerHello etc...
|
assert!(server_hs.as_dgram_ref().is_some()); // Should produce ServerHello etc...
|
||||||
let server_ignored = server.process(client_0rtt.as_dgram_ref(), now());
|
let server_ignored = server.process(client_0rtt.dgram(), now());
|
||||||
assert!(server_ignored.as_dgram_ref().is_none());
|
assert!(server_ignored.as_dgram_ref().is_none());
|
||||||
|
|
||||||
// The server shouldn't receive that 0-RTT data.
|
// The server shouldn't receive that 0-RTT data.
|
||||||
|
@ -172,14 +172,14 @@ fn zero_rtt_send_reject() {
|
||||||
assert!(!server.events().any(recvd_stream_evt));
|
assert!(!server.events().any(recvd_stream_evt));
|
||||||
|
|
||||||
// Client should get a rejection.
|
// Client should get a rejection.
|
||||||
let client_fin = client.process(server_hs.as_dgram_ref(), now());
|
let client_fin = client.process(server_hs.dgram(), now());
|
||||||
let recvd_0rtt_reject = |e| e == ConnectionEvent::ZeroRttRejected;
|
let recvd_0rtt_reject = |e| e == ConnectionEvent::ZeroRttRejected;
|
||||||
assert!(client.events().any(recvd_0rtt_reject));
|
assert!(client.events().any(recvd_0rtt_reject));
|
||||||
|
|
||||||
// Server consume client_fin
|
// Server consume client_fin
|
||||||
let server_ack = server.process(client_fin.as_dgram_ref(), now());
|
let server_ack = server.process(client_fin.dgram(), now());
|
||||||
assert!(server_ack.as_dgram_ref().is_some());
|
assert!(server_ack.as_dgram_ref().is_some());
|
||||||
let client_out = client.process(server_ack.as_dgram_ref(), now());
|
let client_out = client.process(server_ack.dgram(), now());
|
||||||
assert!(client_out.as_dgram_ref().is_none());
|
assert!(client_out.as_dgram_ref().is_none());
|
||||||
|
|
||||||
// ...and the client stream should be gone.
|
// ...and the client stream should be gone.
|
||||||
|
@ -191,11 +191,11 @@ fn zero_rtt_send_reject() {
|
||||||
let stream_id_after_reject = client.stream_create(StreamType::UniDi).unwrap();
|
let stream_id_after_reject = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
assert_eq!(stream_id, stream_id_after_reject);
|
assert_eq!(stream_id, stream_id_after_reject);
|
||||||
client.stream_send(stream_id_after_reject, MESSAGE).unwrap();
|
client.stream_send(stream_id_after_reject, MESSAGE).unwrap();
|
||||||
let client_after_reject = client.process(None, now()).dgram();
|
let client_after_reject = client.process_output(now()).dgram();
|
||||||
assert!(client_after_reject.is_some());
|
assert!(client_after_reject.is_some());
|
||||||
|
|
||||||
// The server should receive new stream
|
// The server should receive new stream
|
||||||
server.process_input(&client_after_reject.unwrap(), now());
|
server.process_input(client_after_reject.unwrap(), now());
|
||||||
assert!(server.events().any(recvd_stream_evt));
|
assert!(server.events().any(recvd_stream_evt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,15 +227,15 @@ fn zero_rtt_update_flow_control() {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Stream limits should be low for 0-RTT.
|
// Stream limits should be low for 0-RTT.
|
||||||
let client_hs = client.process(None, now()).dgram();
|
let client_hs = client.process_output(now()).dgram();
|
||||||
let uni_stream = client.stream_create(StreamType::UniDi).unwrap();
|
let uni_stream = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
assert!(!client.stream_send_atomic(uni_stream, MESSAGE).unwrap());
|
assert!(!client.stream_send_atomic(uni_stream, MESSAGE).unwrap());
|
||||||
let bidi_stream = client.stream_create(StreamType::BiDi).unwrap();
|
let bidi_stream = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
assert!(!client.stream_send_atomic(bidi_stream, MESSAGE).unwrap());
|
assert!(!client.stream_send_atomic(bidi_stream, MESSAGE).unwrap());
|
||||||
|
|
||||||
// Now get the server transport parameters.
|
// Now get the server transport parameters.
|
||||||
let server_hs = server.process(client_hs.as_ref(), now()).dgram();
|
let server_hs = server.process(client_hs, now()).dgram();
|
||||||
client.process_input(&server_hs.unwrap(), now());
|
client.process_input(server_hs.unwrap(), now());
|
||||||
|
|
||||||
// The streams should report a writeable event.
|
// The streams should report a writeable event.
|
||||||
let mut uni_stream_event = false;
|
let mut uni_stream_event = false;
|
||||||
|
@ -299,7 +299,7 @@ fn zero_rtt_loss_accepted() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process CI/0-RTT
|
// Process CI/0-RTT
|
||||||
let si = server.process(ci.as_dgram_ref(), now);
|
let si = server.process(ci.dgram(), now);
|
||||||
assert!(si.as_dgram_ref().is_some());
|
assert!(si.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let server_stream_id = server
|
let server_stream_id = server
|
||||||
|
@ -312,7 +312,7 @@ fn zero_rtt_loss_accepted() {
|
||||||
assert_eq!(client_stream_id, server_stream_id.as_u64());
|
assert_eq!(client_stream_id, server_stream_id.as_u64());
|
||||||
|
|
||||||
// 0-RTT should be accepted
|
// 0-RTT should be accepted
|
||||||
client.process_input(si.as_dgram_ref().unwrap(), now);
|
client.process_input(si.dgram().unwrap(), now);
|
||||||
let recvd_0rtt_reject = |e| e == ConnectionEvent::ZeroRttRejected;
|
let recvd_0rtt_reject = |e| e == ConnectionEvent::ZeroRttRejected;
|
||||||
assert!(
|
assert!(
|
||||||
!client.events().any(recvd_0rtt_reject),
|
!client.events().any(recvd_0rtt_reject),
|
||||||
|
|
|
@ -107,7 +107,6 @@ pub enum Error {
|
||||||
DecodingFrame,
|
DecodingFrame,
|
||||||
DecryptError,
|
DecryptError,
|
||||||
DisabledVersion,
|
DisabledVersion,
|
||||||
HandshakeFailed,
|
|
||||||
IdleTimeout,
|
IdleTimeout,
|
||||||
IntegerOverflow,
|
IntegerOverflow,
|
||||||
InvalidInput,
|
InvalidInput,
|
||||||
|
|
|
@ -718,7 +718,7 @@ impl Path {
|
||||||
// with the current value.
|
// with the current value.
|
||||||
let tos = self.tos();
|
let tos = self.tos();
|
||||||
self.ecn_info.on_packet_sent(stats);
|
self.ecn_info.on_packet_sent(stats);
|
||||||
Datagram::new(self.local, self.remote, tos, payload)
|
Datagram::new(self.local, self.remote, tos, payload.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get local address as `SocketAddr`
|
/// Get local address as `SocketAddr`
|
||||||
|
|
|
@ -195,7 +195,7 @@ impl Server {
|
||||||
fn handle_initial(
|
fn handle_initial(
|
||||||
&mut self,
|
&mut self,
|
||||||
initial: InitialDetails,
|
initial: InitialDetails,
|
||||||
dgram: &Datagram,
|
dgram: Datagram<impl AsRef<[u8]>>,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
) -> Output {
|
) -> Output {
|
||||||
qdebug!([self], "Handle initial");
|
qdebug!([self], "Handle initial");
|
||||||
|
@ -297,7 +297,7 @@ impl Server {
|
||||||
fn accept_connection(
|
fn accept_connection(
|
||||||
&mut self,
|
&mut self,
|
||||||
initial: InitialDetails,
|
initial: InitialDetails,
|
||||||
dgram: &Datagram,
|
dgram: Datagram<impl AsRef<[u8]>>,
|
||||||
orig_dcid: Option<ConnectionId>,
|
orig_dcid: Option<ConnectionId>,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
) -> Output {
|
) -> Output {
|
||||||
|
@ -339,7 +339,7 @@ impl Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_input(&mut self, dgram: &Datagram, now: Instant) -> Output {
|
fn process_input(&mut self, dgram: Datagram<impl AsRef<[u8]>>, now: Instant) -> Output {
|
||||||
qtrace!("Process datagram: {}", hex(&dgram[..]));
|
qtrace!("Process datagram: {}", hex(&dgram[..]));
|
||||||
|
|
||||||
// This is only looking at the first packet header in the datagram.
|
// This is only looking at the first packet header in the datagram.
|
||||||
|
@ -430,7 +430,7 @@ impl Server {
|
||||||
let mut callback = None;
|
let mut callback = None;
|
||||||
|
|
||||||
for connection in &mut self.connections {
|
for connection in &mut self.connections {
|
||||||
match connection.borrow_mut().process(None, now) {
|
match connection.borrow_mut().process_output(now) {
|
||||||
Output::None => {}
|
Output::None => {}
|
||||||
d @ Output::Datagram(_) => return d,
|
d @ Output::Datagram(_) => return d,
|
||||||
Output::Callback(next) => match callback {
|
Output::Callback(next) => match callback {
|
||||||
|
@ -443,8 +443,14 @@ impl Server {
|
||||||
callback.map_or(Output::None, Output::Callback)
|
callback.map_or(Output::None, Output::Callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Short-hand for [`Server::process`] without an input datagram.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn process(&mut self, dgram: Option<&Datagram>, now: Instant) -> Output {
|
pub fn process_output(&mut self, now: Instant) -> Output {
|
||||||
|
self.process(None::<Datagram>, now)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn process(&mut self, dgram: Option<Datagram<impl AsRef<[u8]>>>, now: Instant) -> Output {
|
||||||
let out = dgram
|
let out = dgram
|
||||||
.map_or(Output::None, |d| self.process_input(d, now))
|
.map_or(Output::None, |d| self.process_input(d, now))
|
||||||
.or_else(|| self.process_next_output(now));
|
.or_else(|| self.process_next_output(now));
|
||||||
|
|
|
@ -58,27 +58,27 @@ pub fn connect(client: &mut Connection, server: &mut Server) -> ConnectionRef {
|
||||||
server.set_validation(ValidateAddress::Never);
|
server.set_validation(ValidateAddress::Never);
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Init);
|
assert_eq!(*client.state(), State::Init);
|
||||||
let out = client.process(None, now()); // ClientHello
|
let out = client.process_output(now()); // ClientHello
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
let out = server.process(out.as_dgram_ref(), now()); // ServerHello...
|
let out = server.process(out.dgram(), now()); // ServerHello...
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// Ingest the server Certificate.
|
// Ingest the server Certificate.
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some()); // This should just be an ACK.
|
assert!(out.as_dgram_ref().is_some()); // This should just be an ACK.
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none()); // So the server should have nothing to say.
|
assert!(out.as_dgram_ref().is_none()); // So the server should have nothing to say.
|
||||||
|
|
||||||
// Now mark the server as authenticated.
|
// Now mark the server as authenticated.
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some()); // ACK + HANDSHAKE_DONE + NST
|
assert!(out.as_dgram_ref().is_some()); // ACK + HANDSHAKE_DONE + NST
|
||||||
|
|
||||||
// Have the client process the HANDSHAKE_DONE.
|
// Have the client process the HANDSHAKE_DONE.
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_none());
|
assert!(out.as_dgram_ref().is_none());
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
|
|
||||||
|
@ -105,14 +105,14 @@ pub fn generate_ticket(server: &mut Server) -> ResumptionToken {
|
||||||
let mut server_conn = connect(&mut client, server);
|
let mut server_conn = connect(&mut client, server);
|
||||||
|
|
||||||
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
|
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
|
||||||
let out = server.process(None, now());
|
let out = server.process_output(now());
|
||||||
client.process_input(out.as_dgram_ref().unwrap(), now()); // Consume ticket, ignore output.
|
client.process_input(out.dgram().unwrap(), now()); // Consume ticket, ignore output.
|
||||||
let ticket = find_ticket(&mut client);
|
let ticket = find_ticket(&mut client);
|
||||||
|
|
||||||
// Have the client close the connection and then let the server clean up.
|
// Have the client close the connection and then let the server clean up.
|
||||||
client.close(now(), 0, "got a ticket");
|
client.close(now(), 0, "got a ticket");
|
||||||
let out = client.process_output(now());
|
let out = client.process_output(now());
|
||||||
mem::drop(server.process(out.as_dgram_ref(), now()));
|
mem::drop(server.process(out.dgram(), now()));
|
||||||
// Calling active_connections clears the set of active connections.
|
// Calling active_connections clears the set of active connections.
|
||||||
assert_eq!(server.active_connections().len(), 1);
|
assert_eq!(server.active_connections().len(), 1);
|
||||||
ticket
|
ticket
|
||||||
|
|
|
@ -265,7 +265,7 @@ fn process_client_initial(v: Version, packet: &[u8]) {
|
||||||
|
|
||||||
let dgram = datagram(packet.to_vec());
|
let dgram = datagram(packet.to_vec());
|
||||||
assert_eq!(*server.state(), State::Init);
|
assert_eq!(*server.state(), State::Init);
|
||||||
let out = server.process(Some(&dgram), now());
|
let out = server.process(Some(dgram), now());
|
||||||
assert_eq!(*server.state(), State::Handshaking);
|
assert_eq!(*server.state(), State::Handshaking);
|
||||||
assert!(out.dgram().is_some());
|
assert!(out.dgram().is_some());
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@ fn truncate_long_packet() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// This will truncate the Handshake packet from the server.
|
// This will truncate the Handshake packet from the server.
|
||||||
|
@ -44,18 +44,18 @@ fn truncate_long_packet() {
|
||||||
dupe.tos(),
|
dupe.tos(),
|
||||||
&dupe[..(dupe.len() - tail)],
|
&dupe[..(dupe.len() - tail)],
|
||||||
);
|
);
|
||||||
let hs_probe = client.process(Some(&truncated), now()).dgram();
|
let hs_probe = client.process(Some(truncated), now()).dgram();
|
||||||
assert!(hs_probe.is_some());
|
assert!(hs_probe.is_some());
|
||||||
|
|
||||||
// Now feed in the untruncated packet.
|
// Now feed in the untruncated packet.
|
||||||
let out = client.process(out.as_dgram_ref(), now());
|
let out = client.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some()); // Throw this ACK away.
|
assert!(out.as_dgram_ref().is_some()); // Throw this ACK away.
|
||||||
assert!(test_fixture::maybe_authenticate(&mut client));
|
assert!(test_fixture::maybe_authenticate(&mut client));
|
||||||
let out = client.process(None, now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
|
|
||||||
assert!(client.state().connected());
|
assert!(client.state().connected());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert!(server.state().connected());
|
assert!(server.state().connected());
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ fn reorder_server_initial() {
|
||||||
decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap();
|
decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap();
|
||||||
let client_dcid = client_dcid.to_owned();
|
let client_dcid = client_dcid.to_owned();
|
||||||
|
|
||||||
let server_packet = server.process(client_initial.as_dgram_ref(), now()).dgram();
|
let server_packet = server.process(client_initial.dgram(), now()).dgram();
|
||||||
let (server_initial, server_hs) = split_datagram(server_packet.as_ref().unwrap());
|
let (server_initial, server_hs) = split_datagram(server_packet.as_ref().unwrap());
|
||||||
let (protected_header, _, _, payload) =
|
let (protected_header, _, _, payload) =
|
||||||
decode_initial_header(&server_initial, Role::Server).unwrap();
|
decode_initial_header(&server_initial, Role::Server).unwrap();
|
||||||
|
@ -119,16 +119,16 @@ fn reorder_server_initial() {
|
||||||
// Now a connection can be made successfully.
|
// Now a connection can be made successfully.
|
||||||
// Though we modified the server's Initial packet, we get away with it.
|
// Though we modified the server's Initial packet, we get away with it.
|
||||||
// TLS only authenticates the content of the CRYPTO frame, which was untouched.
|
// TLS only authenticates the content of the CRYPTO frame, which was untouched.
|
||||||
client.process_input(&reordered, now());
|
client.process_input(reordered, now());
|
||||||
client.process_input(&server_hs.unwrap(), now());
|
client.process_input(server_hs.unwrap(), now());
|
||||||
assert!(test_fixture::maybe_authenticate(&mut client));
|
assert!(test_fixture::maybe_authenticate(&mut client));
|
||||||
let finished = client.process_output(now());
|
let finished = client.process_output(now());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
|
|
||||||
let done = server.process(finished.as_dgram_ref(), now());
|
let done = server.process(finished.dgram(), now());
|
||||||
assert_eq!(*server.state(), State::Confirmed);
|
assert_eq!(*server.state(), State::Confirmed);
|
||||||
|
|
||||||
client.process_input(done.as_dgram_ref().unwrap(), now());
|
client.process_input(done.dgram().unwrap(), now());
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,12 +171,13 @@ fn packet_without_frames() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let client_initial = client.process_output(now());
|
let client_initial = client.process_output(now());
|
||||||
|
let client_initial_clone = client_initial.as_dgram_ref().unwrap().clone();
|
||||||
let (_, client_dcid, _, _) =
|
let (_, client_dcid, _, _) =
|
||||||
decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap();
|
decode_initial_header(&client_initial_clone, Role::Client).unwrap();
|
||||||
|
|
||||||
let server_packet = server.process(client_initial.as_dgram_ref(), now()).dgram();
|
let server_packet = server.process(client_initial.dgram(), now()).dgram();
|
||||||
let modified = set_payload(server_packet.as_ref(), client_dcid, &[]);
|
let modified = set_payload(server_packet.as_ref(), client_dcid, &[]);
|
||||||
client.process_input(&modified, now());
|
client.process_input(modified, now());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client.state(),
|
client.state(),
|
||||||
&State::Closed(CloseReason::Transport(Error::ProtocolViolation))
|
&State::Closed(CloseReason::Transport(Error::ProtocolViolation))
|
||||||
|
@ -192,12 +193,13 @@ fn packet_with_only_padding() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let client_initial = client.process_output(now());
|
let client_initial = client.process_output(now());
|
||||||
|
let client_initial_clone = client_initial.as_dgram_ref().unwrap().clone();
|
||||||
let (_, client_dcid, _, _) =
|
let (_, client_dcid, _, _) =
|
||||||
decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap();
|
decode_initial_header(&client_initial_clone, Role::Client).unwrap();
|
||||||
|
|
||||||
let server_packet = server.process(client_initial.as_dgram_ref(), now()).dgram();
|
let server_packet = server.process(client_initial.dgram(), now()).dgram();
|
||||||
let modified = set_payload(server_packet.as_ref(), client_dcid, &[0]);
|
let modified = set_payload(server_packet.as_ref(), client_dcid, &[0]);
|
||||||
client.process_input(&modified, now());
|
client.process_input(modified, now());
|
||||||
assert_eq!(client.state(), &State::WaitInitial);
|
assert_eq!(client.state(), &State::WaitInitial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +217,7 @@ fn overflow_crypto() {
|
||||||
decode_initial_header(client_initial.as_ref().unwrap(), Role::Client).unwrap();
|
decode_initial_header(client_initial.as_ref().unwrap(), Role::Client).unwrap();
|
||||||
let client_dcid = client_dcid.to_owned();
|
let client_dcid = client_dcid.to_owned();
|
||||||
|
|
||||||
let server_packet = server.process(client_initial.as_ref(), now()).dgram();
|
let server_packet = server.process(client_initial, now()).dgram();
|
||||||
let (server_initial, _) = split_datagram(server_packet.as_ref().unwrap());
|
let (server_initial, _) = split_datagram(server_packet.as_ref().unwrap());
|
||||||
|
|
||||||
// Now decrypt the server packet to get AEAD and HP instances.
|
// Now decrypt the server packet to get AEAD and HP instances.
|
||||||
|
@ -261,7 +263,7 @@ fn overflow_crypto() {
|
||||||
server_initial.tos(),
|
server_initial.tos(),
|
||||||
packet,
|
packet,
|
||||||
);
|
);
|
||||||
client.process_input(&dgram, now());
|
client.process_input(dgram, now());
|
||||||
if let State::Closing { error, .. } = client.state() {
|
if let State::Closing { error, .. } = client.state() {
|
||||||
assert!(
|
assert!(
|
||||||
matches!(error, CloseReason::Transport(Error::CryptoBufferExceeded)),
|
matches!(error, CloseReason::Transport(Error::CryptoBufferExceeded)),
|
||||||
|
|
|
@ -35,23 +35,23 @@ fn retry_basic() {
|
||||||
server.set_validation(ValidateAddress::Always);
|
server.set_validation(ValidateAddress::Always);
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // Initial
|
let dgram = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
|
let dgram = server.process(dgram, now()).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
|
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram(); // Initial w/token
|
let dgram = client.process(dgram, now()).dgram(); // Initial w/token
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Initial, HS
|
let dgram = server.process(dgram, now()).dgram(); // Initial, HS
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
mem::drop(client.process(dgram.as_ref(), now()).dgram()); // Ingest, drop any ACK.
|
mem::drop(client.process(dgram, now()).dgram()); // Ingest, drop any ACK.
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
let dgram = client.process(None, now()).dgram(); // Send Finished
|
let dgram = client.process_output(now()).dgram(); // Send Finished
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // (done)
|
let dgram = server.process(dgram, now()).dgram(); // (done)
|
||||||
assert!(dgram.is_some()); // Note that this packet will be dropped...
|
assert!(dgram.is_some()); // Note that this packet will be dropped...
|
||||||
connected_server(&server);
|
connected_server(&server);
|
||||||
}
|
}
|
||||||
|
@ -66,12 +66,12 @@ fn implicit_rtt_retry() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let dgram = client.process(None, now).dgram();
|
let dgram = client.process_output(now).dgram();
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram();
|
let dgram = server.process(dgram, now).dgram();
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
now += RTT / 2;
|
now += RTT / 2;
|
||||||
client.process_input(&dgram.unwrap(), now);
|
client.process_input(dgram.unwrap(), now);
|
||||||
|
|
||||||
assert_eq!(client.stats().rtt, RTT);
|
assert_eq!(client.stats().rtt, RTT);
|
||||||
}
|
}
|
||||||
|
@ -83,18 +83,18 @@ fn retry_expired() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let dgram = client.process(None, now).dgram(); // Initial
|
let dgram = client.process_output(now).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram(); // Retry
|
let dgram = server.process(dgram, now).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
|
|
||||||
let dgram = client.process(dgram.as_ref(), now).dgram(); // Initial w/token
|
let dgram = client.process(dgram, now).dgram(); // Initial w/token
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
now += Duration::from_secs(60); // Too long for Retry.
|
now += Duration::from_secs(60); // Too long for Retry.
|
||||||
let dgram = server.process(dgram.as_ref(), now).dgram(); // Initial, HS
|
let dgram = server.process(dgram, now).dgram(); // Initial, HS
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,26 +111,26 @@ fn retry_0rtt() {
|
||||||
let client_stream = client.stream_create(StreamType::UniDi).unwrap();
|
let client_stream = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_send(client_stream, &[1, 2, 3]).unwrap();
|
client.stream_send(client_stream, &[1, 2, 3]).unwrap();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // Initial w/0-RTT
|
let dgram = client.process_output(now()).dgram(); // Initial w/0-RTT
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_coalesced_0rtt(dgram.as_ref().unwrap());
|
assertions::assert_coalesced_0rtt(dgram.as_ref().unwrap());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
|
let dgram = server.process(dgram, now()).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
|
|
||||||
// After retry, there should be a token and still coalesced 0-RTT.
|
// After retry, there should be a token and still coalesced 0-RTT.
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram();
|
let dgram = client.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_coalesced_0rtt(dgram.as_ref().unwrap());
|
assertions::assert_coalesced_0rtt(dgram.as_ref().unwrap());
|
||||||
|
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Initial, HS
|
let dgram = server.process(dgram, now()).dgram(); // Initial, HS
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram();
|
let dgram = client.process(dgram, now()).dgram();
|
||||||
// Note: the client doesn't need to authenticate the server here
|
// Note: the client doesn't need to authenticate the server here
|
||||||
// as there is no certificate; authentication is based on the ticket.
|
// as there is no certificate; authentication is based on the ticket.
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // (done)
|
let dgram = server.process(dgram, now()).dgram(); // (done)
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
connected_server(&server);
|
connected_server(&server);
|
||||||
assert!(client.tls_info().unwrap().resumed());
|
assert!(client.tls_info().unwrap().resumed());
|
||||||
|
@ -142,14 +142,14 @@ fn retry_different_ip() {
|
||||||
server.set_validation(ValidateAddress::Always);
|
server.set_validation(ValidateAddress::Always);
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let dgram = client.process(None.as_ref(), now()).dgram(); // Initial
|
let dgram = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
|
let dgram = server.process(dgram, now()).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
|
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram(); // Initial w/token
|
let dgram = client.process(dgram, now()).dgram(); // Initial w/token
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
// Change the source IP on the address from the client.
|
// Change the source IP on the address from the client.
|
||||||
|
@ -157,7 +157,7 @@ fn retry_different_ip() {
|
||||||
let other_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2));
|
let other_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2));
|
||||||
let other_addr = SocketAddr::new(other_v4, 443);
|
let other_addr = SocketAddr::new(other_v4, 443);
|
||||||
let from_other = Datagram::new(other_addr, dgram.destination(), dgram.tos(), &dgram[..]);
|
let from_other = Datagram::new(other_addr, dgram.destination(), dgram.tos(), &dgram[..]);
|
||||||
let dgram = server.process(Some(&from_other), now()).dgram();
|
let dgram = server.process(Some(from_other), now()).dgram();
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ fn new_token_different_ip() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
client.enable_resumption(now(), &token).unwrap();
|
client.enable_resumption(now(), &token).unwrap();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // Initial
|
let dgram = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ fn new_token_different_ip() {
|
||||||
let d = dgram.unwrap();
|
let d = dgram.unwrap();
|
||||||
let src = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), d.source().port());
|
let src = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), d.source().port());
|
||||||
let dgram = Some(Datagram::new(src, d.destination(), d.tos(), &d[..]));
|
let dgram = Some(Datagram::new(src, d.destination(), d.tos(), &d[..]));
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
|
let dgram = server.process(dgram, now()).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ fn new_token_expired() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
client.enable_resumption(now(), &token).unwrap();
|
client.enable_resumption(now(), &token).unwrap();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // Initial
|
let dgram = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ fn new_token_expired() {
|
||||||
let d = dgram.unwrap();
|
let d = dgram.unwrap();
|
||||||
let src = SocketAddr::new(d.source().ip(), d.source().port() + 1);
|
let src = SocketAddr::new(d.source().ip(), d.source().port() + 1);
|
||||||
let dgram = Some(Datagram::new(src, d.destination(), d.tos(), &d[..]));
|
let dgram = Some(Datagram::new(src, d.destination(), d.tos(), &d[..]));
|
||||||
let dgram = server.process(dgram.as_ref(), the_future).dgram(); // Retry
|
let dgram = server.process(dgram, the_future).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
}
|
}
|
||||||
|
@ -215,34 +215,34 @@ fn retry_after_initial() {
|
||||||
retry_server.set_validation(ValidateAddress::Always);
|
retry_server.set_validation(ValidateAddress::Always);
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let cinit = client.process(None, now()).dgram(); // Initial
|
let cinit = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(cinit.is_some());
|
assert!(cinit.is_some());
|
||||||
let server_flight = server.process(cinit.as_ref(), now()).dgram(); // Initial
|
let server_flight = server.process(cinit.clone(), now()).dgram(); // Initial
|
||||||
assert!(server_flight.is_some());
|
assert!(server_flight.is_some());
|
||||||
|
|
||||||
// We need to have the client just process the Initial.
|
// We need to have the client just process the Initial.
|
||||||
let (server_initial, _other) = split_datagram(server_flight.as_ref().unwrap());
|
let (server_initial, _other) = split_datagram(server_flight.as_ref().unwrap());
|
||||||
let dgram = client.process(Some(&server_initial), now()).dgram();
|
let dgram = client.process(Some(server_initial), now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assert!(*client.state() != State::Connected);
|
assert!(*client.state() != State::Connected);
|
||||||
|
|
||||||
let retry = retry_server.process(cinit.as_ref(), now()).dgram(); // Retry!
|
let retry = retry_server.process(cinit, now()).dgram(); // Retry!
|
||||||
assert!(retry.is_some());
|
assert!(retry.is_some());
|
||||||
assertions::assert_retry(retry.as_ref().unwrap());
|
assertions::assert_retry(retry.as_ref().unwrap());
|
||||||
|
|
||||||
// The client should ignore the retry.
|
// The client should ignore the retry.
|
||||||
let junk = client.process(retry.as_ref(), now()).dgram();
|
let junk = client.process(retry, now()).dgram();
|
||||||
assert!(junk.is_none());
|
assert!(junk.is_none());
|
||||||
|
|
||||||
// Either way, the client should still be able to process the server flight and connect.
|
// Either way, the client should still be able to process the server flight and connect.
|
||||||
let dgram = client.process(server_flight.as_ref(), now()).dgram();
|
let dgram = client.process(server_flight, now()).dgram();
|
||||||
assert!(dgram.is_some()); // Drop this one.
|
assert!(dgram.is_some()); // Drop this one.
|
||||||
assert!(test_fixture::maybe_authenticate(&mut client));
|
assert!(test_fixture::maybe_authenticate(&mut client));
|
||||||
let dgram = client.process(None, now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // (done)
|
let dgram = server.process(dgram, now()).dgram(); // (done)
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
connected_server(&server);
|
connected_server(&server);
|
||||||
}
|
}
|
||||||
|
@ -253,9 +253,9 @@ fn retry_bad_integrity() {
|
||||||
server.set_validation(ValidateAddress::Always);
|
server.set_validation(ValidateAddress::Always);
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // Initial
|
let dgram = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
|
let dgram = server.process(dgram, now()).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
let retry = &dgram.as_ref().unwrap();
|
let retry = &dgram.as_ref().unwrap();
|
||||||
|
@ -266,7 +266,7 @@ fn retry_bad_integrity() {
|
||||||
let tweaked_packet = Datagram::new(retry.source(), retry.destination(), retry.tos(), tweaked);
|
let tweaked_packet = Datagram::new(retry.source(), retry.destination(), retry.tos(), tweaked);
|
||||||
|
|
||||||
// The client should ignore this packet.
|
// The client should ignore this packet.
|
||||||
let dgram = client.process(Some(&tweaked_packet), now()).dgram();
|
let dgram = client.process(Some(tweaked_packet), now()).dgram();
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,16 +278,14 @@ fn retry_bad_token() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
// Send a retry to one server, then replay it to the other.
|
// Send a retry to one server, then replay it to the other.
|
||||||
let client_initial1 = client.process(None, now()).dgram();
|
let client_initial1 = client.process_output(now()).dgram();
|
||||||
assert!(client_initial1.is_some());
|
assert!(client_initial1.is_some());
|
||||||
let retry = retry_server
|
let retry = retry_server.process(client_initial1, now()).dgram();
|
||||||
.process(client_initial1.as_ref(), now())
|
|
||||||
.dgram();
|
|
||||||
assert!(retry.is_some());
|
assert!(retry.is_some());
|
||||||
let client_initial2 = client.process(retry.as_ref(), now()).dgram();
|
let client_initial2 = client.process(retry, now()).dgram();
|
||||||
assert!(client_initial2.is_some());
|
assert!(client_initial2.is_some());
|
||||||
|
|
||||||
let dgram = server.process(client_initial2.as_ref(), now()).dgram();
|
let dgram = server.process(client_initial2, now()).dgram();
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,20 +301,20 @@ fn retry_after_pto() {
|
||||||
server.set_validation(ValidateAddress::Always);
|
server.set_validation(ValidateAddress::Always);
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
|
|
||||||
let ci = client.process(None, now).dgram();
|
let ci = client.process_output(now).dgram();
|
||||||
assert!(ci.is_some()); // sit on this for a bit.RefCell
|
assert!(ci.is_some()); // sit on this for a bit.RefCell
|
||||||
|
|
||||||
// Let PTO fire on the client and then let it exhaust its PTO packets.
|
// Let PTO fire on the client and then let it exhaust its PTO packets.
|
||||||
now += Duration::from_secs(1);
|
now += Duration::from_secs(1);
|
||||||
let pto = client.process(None, now).dgram();
|
let pto = client.process_output(now).dgram();
|
||||||
assert!(pto.unwrap().len() >= MIN_INITIAL_PACKET_SIZE);
|
assert!(pto.unwrap().len() >= MIN_INITIAL_PACKET_SIZE);
|
||||||
let cb = client.process(None, now).callback();
|
let cb = client.process_output(now).callback();
|
||||||
assert_ne!(cb, Duration::new(0, 0));
|
assert_ne!(cb, Duration::new(0, 0));
|
||||||
|
|
||||||
let retry = server.process(ci.as_ref(), now).dgram();
|
let retry = server.process(ci, now).dgram();
|
||||||
assertions::assert_retry(retry.as_ref().unwrap());
|
assertions::assert_retry(retry.as_ref().unwrap());
|
||||||
|
|
||||||
let ci2 = client.process(retry.as_ref(), now).dgram();
|
let ci2 = client.process(retry, now).dgram();
|
||||||
assert!(ci2.unwrap().len() >= MIN_INITIAL_PACKET_SIZE);
|
assert!(ci2.unwrap().len() >= MIN_INITIAL_PACKET_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,14 +324,14 @@ fn vn_after_retry() {
|
||||||
server.set_validation(ValidateAddress::Always);
|
server.set_validation(ValidateAddress::Always);
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // Initial
|
let dgram = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
|
let dgram = server.process(dgram, now()).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
assertions::assert_retry(dgram.as_ref().unwrap());
|
assertions::assert_retry(dgram.as_ref().unwrap());
|
||||||
|
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram(); // Initial w/token
|
let dgram = client.process(dgram, now()).dgram(); // Initial w/token
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
let mut encoder = Encoder::default();
|
let mut encoder = Encoder::default();
|
||||||
|
@ -345,7 +343,7 @@ fn vn_after_retry() {
|
||||||
let vn = datagram(encoder.into());
|
let vn = datagram(encoder.into());
|
||||||
|
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
client.process(Some(&vn), now()).callback(),
|
client.process(Some(vn), now()).callback(),
|
||||||
Duration::from_secs(0)
|
Duration::from_secs(0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -368,13 +366,11 @@ fn mitm_retry() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
// Trigger initial and a second client Initial.
|
// Trigger initial and a second client Initial.
|
||||||
let client_initial1 = client.process(None, now()).dgram();
|
let client_initial1 = client.process_output(now()).dgram();
|
||||||
assert!(client_initial1.is_some());
|
assert!(client_initial1.is_some());
|
||||||
let retry = retry_server
|
let retry = retry_server.process(client_initial1, now()).dgram();
|
||||||
.process(client_initial1.as_ref(), now())
|
|
||||||
.dgram();
|
|
||||||
assert!(retry.is_some());
|
assert!(retry.is_some());
|
||||||
let client_initial2 = client.process(retry.as_ref(), now()).dgram();
|
let client_initial2 = client.process(retry, now()).dgram();
|
||||||
assert!(client_initial2.is_some());
|
assert!(client_initial2.is_some());
|
||||||
|
|
||||||
// Now to start the epic process of decrypting the packet,
|
// Now to start the epic process of decrypting the packet,
|
||||||
|
@ -432,15 +428,15 @@ fn mitm_retry() {
|
||||||
notoken_packet,
|
notoken_packet,
|
||||||
);
|
);
|
||||||
qdebug!("passing modified Initial to the main server");
|
qdebug!("passing modified Initial to the main server");
|
||||||
let dgram = server.process(Some(&new_datagram), now()).dgram();
|
let dgram = server.process(Some(new_datagram), now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
|
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram(); // Generate an ACK.
|
let dgram = client.process(dgram, now()).dgram(); // Generate an ACK.
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
assert!(test_fixture::maybe_authenticate(&mut client));
|
assert!(test_fixture::maybe_authenticate(&mut client));
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram();
|
let dgram = client.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_some()); // Client sending CLOSE_CONNECTIONs
|
assert!(dgram.is_some()); // Client sending CLOSE_CONNECTIONs
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*client.state(),
|
*client.state(),
|
||||||
|
|
|
@ -47,8 +47,8 @@ pub fn complete_connection(
|
||||||
};
|
};
|
||||||
while !is_done(client) {
|
while !is_done(client) {
|
||||||
_ = test_fixture::maybe_authenticate(client);
|
_ = test_fixture::maybe_authenticate(client);
|
||||||
let out = client.process(datagram.as_ref(), now());
|
let out = client.process(datagram, now());
|
||||||
let out = server.process(out.as_dgram_ref(), now());
|
let out = server.process(out.dgram(), now());
|
||||||
datagram = out.dgram();
|
datagram = out.dgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,9 +111,9 @@ fn connect_single_version_server() {
|
||||||
// Run the version negotiation exchange if necessary.
|
// Run the version negotiation exchange if necessary.
|
||||||
let out = client.process_output(now());
|
let out = client.process_output(now());
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
let dgram = server.process(out.as_dgram_ref(), now()).dgram();
|
let dgram = server.process(out.dgram(), now()).dgram();
|
||||||
assertions::assert_vn(dgram.as_ref().unwrap());
|
assertions::assert_vn(dgram.as_ref().unwrap());
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_conn = connect(&mut client, &mut server);
|
let server_conn = connect(&mut client, &mut server);
|
||||||
|
@ -133,14 +133,16 @@ fn duplicate_initial() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Init);
|
assert_eq!(*client.state(), State::Init);
|
||||||
let initial = client.process(None, now());
|
let initial = client.process_output(now());
|
||||||
assert!(initial.as_dgram_ref().is_some());
|
assert!(initial.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// The server should ignore a packets with the same remote address and
|
// The server should ignore a packets with the same remote address and
|
||||||
// destination connection ID as an existing connection attempt.
|
// destination connection ID as an existing connection attempt.
|
||||||
let server_initial = server.process(initial.as_dgram_ref(), now()).dgram();
|
let server_initial = server
|
||||||
|
.process(initial.as_dgram_ref().cloned(), now())
|
||||||
|
.dgram();
|
||||||
assert!(server_initial.is_some());
|
assert!(server_initial.is_some());
|
||||||
let dgram = server.process(initial.as_dgram_ref(), now()).dgram();
|
let dgram = server.process(initial.dgram(), now()).dgram();
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
|
|
||||||
assert_eq!(server.active_connections().len(), 1);
|
assert_eq!(server.active_connections().len(), 1);
|
||||||
|
@ -153,7 +155,7 @@ fn duplicate_initial_new_path() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
assert_eq!(*client.state(), State::Init);
|
assert_eq!(*client.state(), State::Init);
|
||||||
let initial = client.process(None, now()).dgram().unwrap();
|
let initial = client.process_output(now()).dgram().unwrap();
|
||||||
let other = Datagram::new(
|
let other = Datagram::new(
|
||||||
SocketAddr::new(initial.source().ip(), initial.source().port() ^ 23),
|
SocketAddr::new(initial.source().ip(), initial.source().port() ^ 23),
|
||||||
initial.destination(),
|
initial.destination(),
|
||||||
|
@ -161,11 +163,11 @@ fn duplicate_initial_new_path() {
|
||||||
&initial[..],
|
&initial[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
let server_initial = server.process(Some(&initial), now()).dgram();
|
let server_initial = server.process(Some(initial), now()).dgram();
|
||||||
assert!(server_initial.is_some());
|
assert!(server_initial.is_some());
|
||||||
|
|
||||||
// The server should ignore a packet with the same destination connection ID.
|
// The server should ignore a packet with the same destination connection ID.
|
||||||
let dgram = server.process(Some(&other), now()).dgram();
|
let dgram = server.process(Some(other), now()).dgram();
|
||||||
assert!(dgram.is_none());
|
assert!(dgram.is_none());
|
||||||
|
|
||||||
assert_eq!(server.active_connections().len(), 1);
|
assert_eq!(server.active_connections().len(), 1);
|
||||||
|
@ -178,20 +180,16 @@ fn different_initials_same_path() {
|
||||||
let mut client1 = default_client();
|
let mut client1 = default_client();
|
||||||
let mut client2 = default_client();
|
let mut client2 = default_client();
|
||||||
|
|
||||||
let client_initial1 = client1.process(None, now());
|
let client_initial1 = client1.process_output(now());
|
||||||
assert!(client_initial1.as_dgram_ref().is_some());
|
assert!(client_initial1.as_dgram_ref().is_some());
|
||||||
let client_initial2 = client2.process(None, now());
|
let client_initial2 = client2.process_output(now());
|
||||||
assert!(client_initial2.as_dgram_ref().is_some());
|
assert!(client_initial2.as_dgram_ref().is_some());
|
||||||
|
|
||||||
// The server should respond to both as these came from different addresses.
|
// The server should respond to both as these came from different addresses.
|
||||||
let server_initial1 = server
|
let server_initial1 = server.process(client_initial1.dgram(), now()).dgram();
|
||||||
.process(client_initial1.as_dgram_ref(), now())
|
|
||||||
.dgram();
|
|
||||||
assert!(server_initial1.is_some());
|
assert!(server_initial1.is_some());
|
||||||
|
|
||||||
let server_initial2 = server
|
let server_initial2 = server.process(client_initial2.dgram(), now()).dgram();
|
||||||
.process(client_initial2.as_dgram_ref(), now())
|
|
||||||
.dgram();
|
|
||||||
assert!(server_initial2.is_some());
|
assert!(server_initial2.is_some());
|
||||||
|
|
||||||
assert_eq!(server.active_connections().len(), 2);
|
assert_eq!(server.active_connections().len(), 2);
|
||||||
|
@ -204,17 +202,19 @@ fn same_initial_after_connected() {
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
let client_initial = client.process(None, now());
|
let client_initial = client.process_output(now());
|
||||||
assert!(client_initial.as_dgram_ref().is_some());
|
assert!(client_initial.as_dgram_ref().is_some());
|
||||||
|
|
||||||
let server_initial = server.process(client_initial.as_dgram_ref(), now()).dgram();
|
let server_initial = server
|
||||||
|
.process(client_initial.as_dgram_ref().cloned(), now())
|
||||||
|
.dgram();
|
||||||
assert!(server_initial.is_some());
|
assert!(server_initial.is_some());
|
||||||
complete_connection(&mut client, &mut server, server_initial);
|
complete_connection(&mut client, &mut server, server_initial);
|
||||||
assert_eq!(server.active_connections().len(), 1);
|
assert_eq!(server.active_connections().len(), 1);
|
||||||
|
|
||||||
// Now make a new connection using the exact same initial as before.
|
// Now make a new connection using the exact same initial as before.
|
||||||
// The server should respond to an attempt to connect with the same Initial.
|
// The server should respond to an attempt to connect with the same Initial.
|
||||||
let dgram = server.process(client_initial.as_dgram_ref(), now()).dgram();
|
let dgram = server.process(client_initial.dgram(), now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
// The server should make a new connection object.
|
// The server should make a new connection object.
|
||||||
assert_eq!(server.active_connections().len(), 2);
|
assert_eq!(server.active_connections().len(), 2);
|
||||||
|
@ -236,7 +236,7 @@ fn drop_non_initial() {
|
||||||
bogus_data.resize(MIN_INITIAL_PACKET_SIZE, 66);
|
bogus_data.resize(MIN_INITIAL_PACKET_SIZE, 66);
|
||||||
|
|
||||||
let bogus = datagram(bogus_data);
|
let bogus = datagram(bogus_data);
|
||||||
assert!(server.process(Some(&bogus), now()).dgram().is_none());
|
assert!(server.process(Some(bogus), now()).dgram().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -255,7 +255,7 @@ fn drop_short_initial() {
|
||||||
bogus_data.resize(1199, 66);
|
bogus_data.resize(1199, 66);
|
||||||
|
|
||||||
let bogus = datagram(bogus_data);
|
let bogus = datagram(bogus_data);
|
||||||
assert!(server.process(Some(&bogus), now()).dgram().is_none());
|
assert!(server.process(Some(bogus), now()).dgram().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -272,7 +272,7 @@ fn drop_short_header_packet_for_unknown_connection() {
|
||||||
bogus_data.resize(MIN_INITIAL_PACKET_SIZE, 66);
|
bogus_data.resize(MIN_INITIAL_PACKET_SIZE, 66);
|
||||||
|
|
||||||
let bogus = datagram(bogus_data);
|
let bogus = datagram(bogus_data);
|
||||||
assert!(server.process(Some(&bogus), now()).dgram().is_none());
|
assert!(server.process(Some(bogus), now()).dgram().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify that the server can read 0-RTT properly. A more robust server would buffer
|
/// Verify that the server can read 0-RTT properly. A more robust server would buffer
|
||||||
|
@ -286,9 +286,9 @@ fn zero_rtt() {
|
||||||
|
|
||||||
// Discharge the old connection so that we don't have to worry about it.
|
// Discharge the old connection so that we don't have to worry about it.
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
let t = server.process(None, now).callback();
|
let t = server.process_output(now).callback();
|
||||||
now += t;
|
now += t;
|
||||||
assert_eq!(server.process(None, now), Output::None);
|
assert_eq!(server.process_output(now), Output::None);
|
||||||
assert_eq!(server.active_connections().len(), 0);
|
assert_eq!(server.active_connections().len(), 0);
|
||||||
|
|
||||||
let start_time = now;
|
let start_time = now;
|
||||||
|
@ -298,12 +298,12 @@ fn zero_rtt() {
|
||||||
let mut client_send = || {
|
let mut client_send = || {
|
||||||
let client_stream = client.stream_create(StreamType::UniDi).unwrap();
|
let client_stream = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_send(client_stream, &[1, 2, 3]).unwrap();
|
client.stream_send(client_stream, &[1, 2, 3]).unwrap();
|
||||||
match client.process(None, now) {
|
match client.process_output(now) {
|
||||||
Output::Datagram(d) => d,
|
Output::Datagram(d) => d,
|
||||||
Output::Callback(t) => {
|
Output::Callback(t) => {
|
||||||
// Pacing...
|
// Pacing...
|
||||||
now += t;
|
now += t;
|
||||||
client.process(None, now).dgram().unwrap()
|
client.process_output(now).dgram().unwrap()
|
||||||
}
|
}
|
||||||
Output::None => panic!(),
|
Output::None => panic!(),
|
||||||
}
|
}
|
||||||
|
@ -317,12 +317,12 @@ fn zero_rtt() {
|
||||||
let c4 = client_send();
|
let c4 = client_send();
|
||||||
|
|
||||||
// 0-RTT packets that arrive before the handshake get dropped.
|
// 0-RTT packets that arrive before the handshake get dropped.
|
||||||
mem::drop(server.process(Some(&c2), now));
|
mem::drop(server.process(Some(c2), now));
|
||||||
assert!(server.active_connections().is_empty());
|
assert!(server.active_connections().is_empty());
|
||||||
|
|
||||||
// Now handshake and let another 0-RTT packet in.
|
// Now handshake and let another 0-RTT packet in.
|
||||||
let shs = server.process(Some(&c1), now);
|
let shs = server.process(Some(c1), now);
|
||||||
mem::drop(server.process(Some(&c3), now));
|
mem::drop(server.process(Some(c3), now));
|
||||||
// The server will have received two STREAM frames now if it processed both packets.
|
// The server will have received two STREAM frames now if it processed both packets.
|
||||||
// `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable types.
|
// `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable types.
|
||||||
#[allow(clippy::mutable_key_type)]
|
#[allow(clippy::mutable_key_type)]
|
||||||
|
@ -343,11 +343,11 @@ fn zero_rtt() {
|
||||||
// Complete the handshake. As the client was pacing 0-RTT packets, extend the time
|
// Complete the handshake. As the client was pacing 0-RTT packets, extend the time
|
||||||
// a little so that the pacer doesn't prevent the Finished from being sent.
|
// a little so that the pacer doesn't prevent the Finished from being sent.
|
||||||
now += now - start_time;
|
now += now - start_time;
|
||||||
let cfin = client.process(shs.as_dgram_ref(), now);
|
let cfin = client.process(shs.dgram(), now);
|
||||||
mem::drop(server.process(cfin.as_dgram_ref(), now));
|
mem::drop(server.process(cfin.dgram(), now));
|
||||||
|
|
||||||
// The server will drop this last 0-RTT packet.
|
// The server will drop this last 0-RTT packet.
|
||||||
mem::drop(server.process(Some(&c4), now));
|
mem::drop(server.process(Some(c4), now));
|
||||||
// `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable types.
|
// `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable types.
|
||||||
#[allow(clippy::mutable_key_type)]
|
#[allow(clippy::mutable_key_type)]
|
||||||
let active = server.active_connections();
|
let active = server.active_connections();
|
||||||
|
@ -377,20 +377,20 @@ fn new_token_0rtt() {
|
||||||
let client_stream = client.stream_create(StreamType::UniDi).unwrap();
|
let client_stream = client.stream_create(StreamType::UniDi).unwrap();
|
||||||
client.stream_send(client_stream, &[1, 2, 3]).unwrap();
|
client.stream_send(client_stream, &[1, 2, 3]).unwrap();
|
||||||
|
|
||||||
let out = client.process(None, now()); // Initial w/0-RTT
|
let out = client.process_output(now()); // Initial w/0-RTT
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assertions::assert_initial(out.as_dgram_ref().unwrap(), true);
|
assertions::assert_initial(out.as_dgram_ref().unwrap(), true);
|
||||||
assertions::assert_coalesced_0rtt(out.as_dgram_ref().unwrap());
|
assertions::assert_coalesced_0rtt(out.as_dgram_ref().unwrap());
|
||||||
let out = server.process(out.as_dgram_ref(), now()); // Initial
|
let out = server.process(out.dgram(), now()); // Initial
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assertions::assert_initial(out.as_dgram_ref().unwrap(), false);
|
assertions::assert_initial(out.as_dgram_ref().unwrap(), false);
|
||||||
|
|
||||||
let dgram = client.process(out.as_dgram_ref(), now());
|
let dgram = client.process(out.as_dgram_ref().cloned(), now());
|
||||||
// Note: the client doesn't need to authenticate the server here
|
// Note: the client doesn't need to authenticate the server here
|
||||||
// as there is no certificate; authentication is based on the ticket.
|
// as there is no certificate; authentication is based on the ticket.
|
||||||
assert!(out.as_dgram_ref().is_some());
|
assert!(out.as_dgram_ref().is_some());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
let dgram = server.process(dgram.as_dgram_ref(), now()); // (done)
|
let dgram = server.process(dgram.dgram(), now()); // (done)
|
||||||
assert!(dgram.as_dgram_ref().is_some());
|
assert!(dgram.as_dgram_ref().is_some());
|
||||||
connected_server(&server);
|
connected_server(&server);
|
||||||
assert!(client.tls_info().unwrap().resumed());
|
assert!(client.tls_info().unwrap().resumed());
|
||||||
|
@ -405,7 +405,7 @@ fn new_token_different_port() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
client.enable_resumption(now(), &token).unwrap();
|
client.enable_resumption(now(), &token).unwrap();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // Initial
|
let dgram = client.process_output(now()).dgram(); // Initial
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
assertions::assert_initial(dgram.as_ref().unwrap(), true);
|
||||||
|
|
||||||
|
@ -413,7 +413,7 @@ fn new_token_different_port() {
|
||||||
let d = dgram.unwrap();
|
let d = dgram.unwrap();
|
||||||
let src = SocketAddr::new(d.source().ip(), d.source().port() + 1);
|
let src = SocketAddr::new(d.source().ip(), d.source().port() + 1);
|
||||||
let dgram = Some(Datagram::new(src, d.destination(), d.tos(), &d[..]));
|
let dgram = Some(Datagram::new(src, d.destination(), d.tos(), &d[..]));
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
|
let dgram = server.process(dgram, now()).dgram(); // Retry
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_initial(dgram.as_ref().unwrap(), false);
|
assertions::assert_initial(dgram.as_ref().unwrap(), false);
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ fn bad_client_initial() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram().expect("a datagram");
|
let dgram = client.process_output(now()).dgram().expect("a datagram");
|
||||||
let (header, d_cid, s_cid, payload) = decode_initial_header(&dgram, Role::Client).unwrap();
|
let (header, d_cid, s_cid, payload) = decode_initial_header(&dgram, Role::Client).unwrap();
|
||||||
let (aead, hp) = initial_aead_and_hp(d_cid, Role::Client);
|
let (aead, hp) = initial_aead_and_hp(d_cid, Role::Client);
|
||||||
let (fixed_header, pn) = remove_header_protection(&hp, header, payload);
|
let (fixed_header, pn) = remove_header_protection(&hp, header, payload);
|
||||||
|
@ -470,7 +470,7 @@ fn bad_client_initial() {
|
||||||
let bad_dgram = Datagram::new(dgram.source(), dgram.destination(), dgram.tos(), ciphertext);
|
let bad_dgram = Datagram::new(dgram.source(), dgram.destination(), dgram.tos(), ciphertext);
|
||||||
|
|
||||||
// The server should reject this.
|
// The server should reject this.
|
||||||
let response = server.process(Some(&bad_dgram), now());
|
let response = server.process(Some(bad_dgram), now());
|
||||||
let close_dgram = response.dgram().unwrap();
|
let close_dgram = response.dgram().unwrap();
|
||||||
// The resulting datagram might contain multiple packets, but each is small.
|
// The resulting datagram might contain multiple packets, but each is small.
|
||||||
let (initial_close, rest) = split_datagram(&close_dgram);
|
let (initial_close, rest) = split_datagram(&close_dgram);
|
||||||
|
@ -484,10 +484,10 @@ fn bad_client_initial() {
|
||||||
|
|
||||||
// The client should accept this new and stop trying to connect.
|
// The client should accept this new and stop trying to connect.
|
||||||
// It will generate a CONNECTION_CLOSE first though.
|
// It will generate a CONNECTION_CLOSE first though.
|
||||||
let response = client.process(Some(&close_dgram), now()).dgram();
|
let response = client.process(Some(close_dgram), now()).dgram();
|
||||||
assert!(response.is_some());
|
assert!(response.is_some());
|
||||||
// The client will now wait out its closing period.
|
// The client will now wait out its closing period.
|
||||||
let delay = client.process(None, now()).callback();
|
let delay = client.process_output(now()).callback();
|
||||||
assert_ne!(delay, Duration::from_secs(0));
|
assert_ne!(delay, Duration::from_secs(0));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*client.state(),
|
*client.state(),
|
||||||
|
@ -502,7 +502,7 @@ fn bad_client_initial() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// After sending the CONNECTION_CLOSE, the server goes idle.
|
// After sending the CONNECTION_CLOSE, the server goes idle.
|
||||||
let res = server.process(None, now());
|
let res = server.process_output(now());
|
||||||
assert_eq!(res, Output::None);
|
assert_eq!(res, Output::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,7 +511,7 @@ fn bad_client_initial_connection_close() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
let mut server = default_server();
|
let mut server = default_server();
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram().expect("a datagram");
|
let dgram = client.process_output(now()).dgram().expect("a datagram");
|
||||||
let (header, d_cid, s_cid, payload) = decode_initial_header(&dgram, Role::Client).unwrap();
|
let (header, d_cid, s_cid, payload) = decode_initial_header(&dgram, Role::Client).unwrap();
|
||||||
let (aead, hp) = initial_aead_and_hp(d_cid, Role::Client);
|
let (aead, hp) = initial_aead_and_hp(d_cid, Role::Client);
|
||||||
let (_, pn) = remove_header_protection(&hp, header, payload);
|
let (_, pn) = remove_header_protection(&hp, header, payload);
|
||||||
|
@ -553,9 +553,9 @@ fn bad_client_initial_connection_close() {
|
||||||
|
|
||||||
// The server should ignore this and go to Draining.
|
// The server should ignore this and go to Draining.
|
||||||
let mut now = now();
|
let mut now = now();
|
||||||
let response = server.process(Some(&bad_dgram), now);
|
let response = server.process(Some(bad_dgram), now);
|
||||||
now += response.callback();
|
now += response.callback();
|
||||||
let response = server.process(None, now);
|
let response = server.process_output(now);
|
||||||
assert_eq!(response, Output::None);
|
assert_eq!(response, Output::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +565,7 @@ fn version_negotiation_ignored() {
|
||||||
let mut client = default_client();
|
let mut client = default_client();
|
||||||
|
|
||||||
// Any packet will do, but let's make something that looks real.
|
// Any packet will do, but let's make something that looks real.
|
||||||
let dgram = client.process(None, now()).dgram().expect("a datagram");
|
let dgram = client.process_output(now()).dgram().expect("a datagram");
|
||||||
let mut input = dgram.to_vec();
|
let mut input = dgram.to_vec();
|
||||||
input[1] ^= 0x12;
|
input[1] ^= 0x12;
|
||||||
let damaged = Datagram::new(
|
let damaged = Datagram::new(
|
||||||
|
@ -574,7 +574,7 @@ fn version_negotiation_ignored() {
|
||||||
dgram.tos(),
|
dgram.tos(),
|
||||||
input.clone(),
|
input.clone(),
|
||||||
);
|
);
|
||||||
let vn = server.process(Some(&damaged), now()).dgram();
|
let vn = server.process(Some(damaged), now()).dgram();
|
||||||
|
|
||||||
let mut dec = Decoder::from(&input[5..]); // Skip past version.
|
let mut dec = Decoder::from(&input[5..]); // Skip past version.
|
||||||
let d_cid = dec.decode_vec(1).expect("client DCID").to_vec();
|
let d_cid = dec.decode_vec(1).expect("client DCID").to_vec();
|
||||||
|
@ -595,7 +595,7 @@ fn version_negotiation_ignored() {
|
||||||
assert!(found, "valid version not found");
|
assert!(found, "valid version not found");
|
||||||
|
|
||||||
// Client ignores VN packet that contain negotiated version.
|
// Client ignores VN packet that contain negotiated version.
|
||||||
let res = client.process(Some(&vn), now());
|
let res = client.process(Some(vn), now());
|
||||||
assert!(res.callback() > Duration::new(0, 120));
|
assert!(res.callback() > Duration::new(0, 120));
|
||||||
assert_eq!(client.state(), &State::WaitInitial);
|
assert_eq!(client.state(), &State::WaitInitial);
|
||||||
}
|
}
|
||||||
|
@ -615,9 +615,9 @@ fn version_negotiation() {
|
||||||
// `connect()` runs a fixed exchange, so manually run the Version Negotiation.
|
// `connect()` runs a fixed exchange, so manually run the Version Negotiation.
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assertions::assert_vn(dgram.as_ref().unwrap());
|
assertions::assert_vn(dgram.as_ref().unwrap());
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
let sconn = connect(&mut client, &mut server);
|
let sconn = connect(&mut client, &mut server);
|
||||||
assert_eq!(client.version(), VN_VERSION);
|
assert_eq!(client.version(), VN_VERSION);
|
||||||
|
@ -651,22 +651,22 @@ fn version_negotiation_and_compatible() {
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_version(dgram.as_ref().unwrap(), ORIG_VERSION.wire_version());
|
assertions::assert_version(dgram.as_ref().unwrap(), ORIG_VERSION.wire_version());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assertions::assert_vn(dgram.as_ref().unwrap());
|
assertions::assert_vn(dgram.as_ref().unwrap());
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
let dgram = client.process(None, now()).dgram(); // ClientHello
|
let dgram = client.process_output(now()).dgram(); // ClientHello
|
||||||
assertions::assert_version(dgram.as_ref().unwrap(), VN_VERSION.wire_version());
|
assertions::assert_version(dgram.as_ref().unwrap(), VN_VERSION.wire_version());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // ServerHello...
|
let dgram = server.process(dgram, now()).dgram(); // ServerHello...
|
||||||
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
|
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
client.authenticated(AuthenticationStatus::Ok, now());
|
client.authenticated(AuthenticationStatus::Ok, now());
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
|
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
|
||||||
assert_eq!(*client.state(), State::Connected);
|
assert_eq!(*client.state(), State::Connected);
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram(); // ACK + HANDSHAKE_DONE + NST
|
let dgram = server.process(dgram, now()).dgram(); // ACK + HANDSHAKE_DONE + NST
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
assert_eq!(*client.state(), State::Confirmed);
|
assert_eq!(*client.state(), State::Confirmed);
|
||||||
|
|
||||||
let sconn = connected_server(&server);
|
let sconn = connected_server(&server);
|
||||||
|
@ -698,8 +698,8 @@ fn compatible_upgrade_resumption_and_vn() {
|
||||||
assert_eq!(server_conn.borrow().version(), COMPAT_VERSION);
|
assert_eq!(server_conn.borrow().version(), COMPAT_VERSION);
|
||||||
|
|
||||||
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
|
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
|
||||||
let dgram = server.process(None, now()).dgram();
|
let dgram = server.process_output(now()).dgram();
|
||||||
client.process_input(&dgram.unwrap(), now()); // Consume ticket, ignore output.
|
client.process_input(dgram.unwrap(), now()); // Consume ticket, ignore output.
|
||||||
let ticket = find_ticket(&mut client);
|
let ticket = find_ticket(&mut client);
|
||||||
|
|
||||||
// This new server will reject the ticket, but it will also generate a VN packet.
|
// This new server will reject the ticket, but it will also generate a VN packet.
|
||||||
|
@ -713,9 +713,9 @@ fn compatible_upgrade_resumption_and_vn() {
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
assert!(dgram.is_some());
|
assert!(dgram.is_some());
|
||||||
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
|
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
assertions::assert_vn(dgram.as_ref().unwrap());
|
assertions::assert_vn(dgram.as_ref().unwrap());
|
||||||
client.process_input(&dgram.unwrap(), now());
|
client.process_input(dgram.unwrap(), now());
|
||||||
|
|
||||||
let server_conn = connect(&mut client, &mut server);
|
let server_conn = connect(&mut client, &mut server);
|
||||||
assert_eq!(client.version(), RESUMPTION_VERSION);
|
assert_eq!(client.version(), RESUMPTION_VERSION);
|
||||||
|
@ -730,14 +730,14 @@ fn closed() {
|
||||||
connect(&mut client, &mut server);
|
connect(&mut client, &mut server);
|
||||||
|
|
||||||
// The server will have sent a few things, so it will be on PTO.
|
// The server will have sent a few things, so it will be on PTO.
|
||||||
let res = server.process(None, now());
|
let res = server.process_output(now());
|
||||||
assert!(res.callback() > Duration::new(0, 0));
|
assert!(res.callback() > Duration::new(0, 0));
|
||||||
// The client will be on the delayed ACK timer.
|
// The client will be on the delayed ACK timer.
|
||||||
let res = client.process(None, now());
|
let res = client.process_output(now());
|
||||||
assert!(res.callback() > Duration::new(0, 0));
|
assert!(res.callback() > Duration::new(0, 0));
|
||||||
|
|
||||||
qtrace!("60s later");
|
qtrace!("60s later");
|
||||||
let res = server.process(None, now() + Duration::from_secs(60));
|
let res = server.process_output(now() + Duration::from_secs(60));
|
||||||
assert_eq!(res, Output::None);
|
assert_eq!(res, Output::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,8 +825,8 @@ fn max_streams_after_0rtt_rejection() {
|
||||||
client.enable_resumption(now(), &token).unwrap();
|
client.enable_resumption(now(), &token).unwrap();
|
||||||
_ = client.stream_create(StreamType::BiDi).unwrap();
|
_ = client.stream_create(StreamType::BiDi).unwrap();
|
||||||
let dgram = client.process_output(now()).dgram();
|
let dgram = client.process_output(now()).dgram();
|
||||||
let dgram = server.process(dgram.as_ref(), now()).dgram();
|
let dgram = server.process(dgram, now()).dgram();
|
||||||
let dgram = client.process(dgram.as_ref(), now()).dgram();
|
let dgram = client.process(dgram, now()).dgram();
|
||||||
assert!(dgram.is_some()); // We're far enough along to complete the test now.
|
assert!(dgram.is_some()); // We're far enough along to complete the test now.
|
||||||
|
|
||||||
// Make sure that we can create MAX_STREAMS uni- and bidirectional streams.
|
// Make sure that we can create MAX_STREAMS uni- and bidirectional streams.
|
||||||
|
@ -863,8 +863,8 @@ fn has_active_connections() {
|
||||||
|
|
||||||
assert!(!server.has_active_connections());
|
assert!(!server.has_active_connections());
|
||||||
|
|
||||||
let initial = client.process(None, now());
|
let initial = client.process_output(now());
|
||||||
_ = server.process(initial.as_dgram_ref(), now()).dgram();
|
_ = server.process(initial.dgram(), now()).dgram();
|
||||||
|
|
||||||
assert!(server.has_active_connections());
|
assert!(server.has_active_connections());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"f115cdd60c3993b4b7b5611ee8ccffe2a92e6b4180cca93fed8c198805543ace","src/lib.rs":"bf3bc79b1d799a42b73e64d2b203ce688cc0859d7afa6c66eec429ec36199ba6"},"package":null}
|
{"files":{"Cargo.toml":"9dfe3aad758bbe584ac465f6cb35a9a7d3e32d859cb3878a23390fcff3f4f828","src/lib.rs":"d175cfb8f2ed2cc1a0e552c910fdee0e780a38a582d570554db32ff417115e55"},"package":null}
|
|
@ -13,7 +13,7 @@
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
name = "neqo-udp"
|
name = "neqo-udp"
|
||||||
version = "0.9.2"
|
version = "0.10.0"
|
||||||
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
authors = ["The Neqo Authors <necko@mozilla.com>"]
|
||||||
build = false
|
build = false
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
|
@ -7,10 +7,9 @@
|
||||||
#![allow(clippy::missing_errors_doc)] // Functions simply delegate to tokio and quinn-udp.
|
#![allow(clippy::missing_errors_doc)] // Functions simply delegate to tokio and quinn-udp.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
|
||||||
io::{self, IoSliceMut},
|
io::{self, IoSliceMut},
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
slice,
|
slice::{self, Chunks},
|
||||||
};
|
};
|
||||||
|
|
||||||
use neqo_common::{qdebug, qtrace, Datagram, IpTos};
|
use neqo_common::{qdebug, qtrace, Datagram, IpTos};
|
||||||
|
@ -21,11 +20,7 @@ use quinn_udp::{EcnCodepoint, RecvMeta, Transmit, UdpSocketState};
|
||||||
/// Allows reading multiple datagrams in a single [`Socket::recv`] call.
|
/// Allows reading multiple datagrams in a single [`Socket::recv`] call.
|
||||||
//
|
//
|
||||||
// TODO: Experiment with different values across platforms.
|
// TODO: Experiment with different values across platforms.
|
||||||
const RECV_BUF_SIZE: usize = u16::MAX as usize;
|
pub const RECV_BUF_SIZE: usize = u16::MAX as usize;
|
||||||
|
|
||||||
std::thread_local! {
|
|
||||||
static RECV_BUF: RefCell<Vec<u8>> = RefCell::new(vec![0; RECV_BUF_SIZE]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_inner(
|
pub fn send_inner(
|
||||||
state: &UdpSocketState,
|
state: &UdpSocketState,
|
||||||
|
@ -57,63 +52,89 @@ use std::os::fd::AsFd as SocketRef;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::os::windows::io::AsSocket as SocketRef;
|
use std::os::windows::io::AsSocket as SocketRef;
|
||||||
|
|
||||||
pub fn recv_inner(
|
pub fn recv_inner<'a>(
|
||||||
local_address: &SocketAddr,
|
local_address: SocketAddr,
|
||||||
state: &UdpSocketState,
|
state: &UdpSocketState,
|
||||||
socket: impl SocketRef,
|
socket: impl SocketRef,
|
||||||
) -> Result<Vec<Datagram>, io::Error> {
|
recv_buf: &'a mut [u8],
|
||||||
let dgrams = RECV_BUF.with_borrow_mut(|recv_buf| -> Result<Vec<Datagram>, io::Error> {
|
) -> Result<DatagramIter<'a>, io::Error> {
|
||||||
let mut meta;
|
let mut meta;
|
||||||
|
|
||||||
loop {
|
let data = loop {
|
||||||
meta = RecvMeta::default();
|
meta = RecvMeta::default();
|
||||||
|
|
||||||
state.recv(
|
state.recv(
|
||||||
(&socket).into(),
|
(&socket).into(),
|
||||||
&mut [IoSliceMut::new(recv_buf)],
|
&mut [IoSliceMut::new(recv_buf)],
|
||||||
slice::from_mut(&mut meta),
|
slice::from_mut(&mut meta),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if meta.len == 0 || meta.stride == 0 {
|
if meta.len == 0 || meta.stride == 0 {
|
||||||
qdebug!(
|
qdebug!(
|
||||||
"ignoring datagram from {} to {} len {} stride {}",
|
"ignoring datagram from {} to {} len {} stride {}",
|
||||||
meta.addr,
|
meta.addr,
|
||||||
local_address,
|
local_address,
|
||||||
meta.len,
|
meta.len,
|
||||||
meta.stride
|
meta.stride
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(recv_buf[0..meta.len]
|
break &recv_buf[..meta.len];
|
||||||
.chunks(meta.stride)
|
};
|
||||||
.map(|d| {
|
|
||||||
qtrace!(
|
|
||||||
"received {} bytes from {} to {}",
|
|
||||||
d.len(),
|
|
||||||
meta.addr,
|
|
||||||
local_address,
|
|
||||||
);
|
|
||||||
Datagram::new(
|
|
||||||
meta.addr,
|
|
||||||
*local_address,
|
|
||||||
meta.ecn.map(|n| IpTos::from(n as u8)).unwrap_or_default(),
|
|
||||||
d,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
qtrace!(
|
qtrace!(
|
||||||
"received {} datagrams ({:?})",
|
"received {} bytes from {} to {} in {} segments",
|
||||||
dgrams.len(),
|
data.len(),
|
||||||
dgrams.iter().map(|d| d.len()).collect::<Vec<_>>(),
|
meta.addr,
|
||||||
|
local_address,
|
||||||
|
data.len().div_ceil(meta.stride),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(dgrams)
|
Ok(DatagramIter {
|
||||||
|
meta,
|
||||||
|
datagrams: data.chunks(meta.stride),
|
||||||
|
local_address,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DatagramIter<'a> {
|
||||||
|
meta: RecvMeta,
|
||||||
|
datagrams: Chunks<'a, u8>,
|
||||||
|
local_address: SocketAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for DatagramIter<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("DatagramIter")
|
||||||
|
.field("meta", &self.meta)
|
||||||
|
.field("local_address", &self.local_address)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for DatagramIter<'a> {
|
||||||
|
type Item = Datagram<&'a [u8]>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.datagrams.next().map(|d| {
|
||||||
|
Datagram::from_slice(
|
||||||
|
self.meta.addr,
|
||||||
|
self.local_address,
|
||||||
|
self.meta
|
||||||
|
.ecn
|
||||||
|
.map(|n| IpTos::from(n as u8))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
d,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExactSizeIterator for DatagramIter<'_> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.datagrams.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around a UDP socket, sending and receiving [`Datagram`]s.
|
/// A wrapper around a UDP socket, sending and receiving [`Datagram`]s.
|
||||||
|
@ -138,8 +159,12 @@ impl<S: SocketRef> Socket<S> {
|
||||||
|
|
||||||
/// Receive a batch of [`Datagram`]s on the given [`Socket`], each
|
/// Receive a batch of [`Datagram`]s on the given [`Socket`], each
|
||||||
/// set with the provided local address.
|
/// set with the provided local address.
|
||||||
pub fn recv(&self, local_address: &SocketAddr) -> Result<Vec<Datagram>, io::Error> {
|
pub fn recv<'a>(
|
||||||
recv_inner(local_address, &self.state, &self.inner)
|
&self,
|
||||||
|
local_address: SocketAddr,
|
||||||
|
recv_buf: &'a mut [u8],
|
||||||
|
) -> Result<DatagramIter<'a>, io::Error> {
|
||||||
|
recv_inner(local_address, &self.state, &self.inner, recv_buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +195,8 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
sender.send(&datagram)?;
|
sender.send(&datagram)?;
|
||||||
let res = receiver.recv(&receiver_addr);
|
let mut recv_buf = vec![0; RECV_BUF_SIZE];
|
||||||
|
let res = receiver.recv(receiver_addr, &mut recv_buf);
|
||||||
assert_eq!(res.unwrap_err().kind(), std::io::ErrorKind::WouldBlock);
|
assert_eq!(res.unwrap_err().kind(), std::io::ErrorKind::WouldBlock);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -191,17 +217,15 @@ mod tests {
|
||||||
|
|
||||||
sender.send(&datagram)?;
|
sender.send(&datagram)?;
|
||||||
|
|
||||||
let received_datagram = receiver
|
let mut recv_buf = vec![0; RECV_BUF_SIZE];
|
||||||
.recv(&receiver_addr)
|
let mut received_datagrams = receiver
|
||||||
.expect("receive to succeed")
|
.recv(receiver_addr, &mut recv_buf)
|
||||||
.into_iter()
|
.expect("receive to succeed");
|
||||||
.next()
|
|
||||||
.expect("receive to yield datagram");
|
|
||||||
|
|
||||||
// Assert that the ECN is correct.
|
// Assert that the ECN is correct.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
IpTosEcn::from(datagram.tos()),
|
IpTosEcn::from(datagram.tos()),
|
||||||
IpTosEcn::from(received_datagram.tos())
|
IpTosEcn::from(received_datagrams.next().unwrap().tos())
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -236,11 +260,11 @@ mod tests {
|
||||||
|
|
||||||
// Allow for one GSO sendmmsg to result in multiple GRO recvmmsg.
|
// Allow for one GSO sendmmsg to result in multiple GRO recvmmsg.
|
||||||
let mut num_received = 0;
|
let mut num_received = 0;
|
||||||
|
let mut recv_buf = vec![0; RECV_BUF_SIZE];
|
||||||
while num_received < max_gso_segments {
|
while num_received < max_gso_segments {
|
||||||
receiver
|
receiver
|
||||||
.recv(&receiver_addr)
|
.recv(receiver_addr, &mut recv_buf)
|
||||||
.expect("receive to succeed")
|
.expect("receive to succeed")
|
||||||
.into_iter()
|
|
||||||
.for_each(|d| {
|
.for_each(|d| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SEGMENT_SIZE,
|
SEGMENT_SIZE,
|
||||||
|
@ -253,4 +277,20 @@ mod tests {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmt_datagram_iter() {
|
||||||
|
let dgrams = [];
|
||||||
|
|
||||||
|
let i = DatagramIter {
|
||||||
|
meta: RecvMeta::default(),
|
||||||
|
datagrams: dgrams.chunks(1),
|
||||||
|
local_address: "[::]:0".parse().unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
&format!("{i:?}"),
|
||||||
|
"DatagramIter { meta: RecvMeta { addr: [::]:0, len: 0, stride: 0, ecn: None, dst_ip: None }, local_address: [::]:0 }"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче