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:
Max Inden 2024-11-01 06:38:43 +00:00
parent fda5d36893
commit 4264815cfc
73 changed files with 1820 additions and 1586 deletions

View File

@ -90,9 +90,9 @@ git = "https://github.com/mozilla/mp4parse-rust"
rev = "a138e40ec1c603615873e524b5b22e11c0ec4820"
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"
tag = "v0.9.2"
tag = "v0.10.0"
replace-with = "vendored-sources"
[source."git+https://github.com/servo/unicode-bidi?rev=ca612daf1c08c53abe07327cb3e6ef6e0a760f0c"]

28
Cargo.lock generated
View File

@ -4245,8 +4245,8 @@ dependencies = [
[[package]]
name = "neqo-bin"
version = "0.9.2"
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
version = "0.10.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
dependencies = [
"clap",
"clap-verbosity-flag",
@ -4267,8 +4267,8 @@ dependencies = [
[[package]]
name = "neqo-common"
version = "0.9.2"
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
version = "0.10.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
dependencies = [
"enum-map",
"env_logger",
@ -4279,8 +4279,8 @@ dependencies = [
[[package]]
name = "neqo-crypto"
version = "0.9.2"
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
version = "0.10.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
dependencies = [
"bindgen 0.69.4",
"log",
@ -4294,8 +4294,8 @@ dependencies = [
[[package]]
name = "neqo-http3"
version = "0.9.2"
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
version = "0.10.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
dependencies = [
"enumset",
"log",
@ -4310,8 +4310,8 @@ dependencies = [
[[package]]
name = "neqo-qpack"
version = "0.9.2"
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
version = "0.10.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
dependencies = [
"log",
"neqo-common",
@ -4322,8 +4322,8 @@ dependencies = [
[[package]]
name = "neqo-transport"
version = "0.9.2"
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
version = "0.10.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
dependencies = [
"enum-map",
"indexmap 2.2.6",
@ -4337,8 +4337,8 @@ dependencies = [
[[package]]
name = "neqo-udp"
version = "0.9.2"
source = "git+https://github.com/mozilla/neqo?tag=v0.9.2#aca20d3890c0a8af2658c95d2634cab2b5badf08"
version = "0.10.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.10.0#214ad48e0dbb8cc35c7148b225fbc6f58eb85f36"
dependencies = [
"log",
"neqo-common",

View File

@ -10,11 +10,11 @@ name = "neqo_glue"
[dependencies]
firefox-on-glean = { path = "../../../toolkit/components/glean/api" }
neqo-udp = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { 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.10.0", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
xpcom = { path = "../../../xpcom/rust/xpcom" }
@ -29,7 +29,7 @@ uuid = { version = "1.0", features = ["v4"] }
winapi = {version = "0.3", features = ["ws2def"] }
[dependencies.neqo-crypto]
tag = "v0.9.2"
tag = "v0.10.0"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

View File

@ -41,6 +41,10 @@ use uuid::Uuid;
use winapi::shared::ws2def::{AF_INET, AF_INET6};
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)]
pub struct NeqoHttp3Conn {
conn: Http3Client,
@ -517,10 +521,10 @@ pub unsafe extern "C" fn neqo_http3conn_process_input_use_nspr_for_io(
remote,
conn.local_addr,
IpTos::default(),
(*packet).to_vec(),
(*packet).as_slice(),
);
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;
}
@ -538,52 +542,61 @@ pub unsafe extern "C" fn neqo_http3conn_process_input(
) -> ProcessInputResult {
let mut bytes_read = 0;
loop {
let mut dgrams = match conn
.socket
.as_mut()
.expect("non NSPR IO")
.recv(&conn.local_addr)
{
Ok(dgrams) => dgrams,
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
RECV_BUF.with_borrow_mut(|recv_buf| {
loop {
let dgrams = match conn
.socket
.as_mut()
.expect("non NSPR IO")
.recv(conn.local_addr, recv_buf)
{
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;
}
Err(e) => {
qwarn!("failed to receive datagrams: {}", e);
return ProcessInputResult {
result: NS_ERROR_FAILURE,
bytes_read: 0,
};
}
// Attach metric instrumentation to `dgrams` iterator.
let mut sum = 0;
conn.datagram_segments_received
.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]
@ -1001,7 +1014,6 @@ impl From<TransportError> for CloseError {
TransportError::ConnectionState => CloseError::TransportInternalErrorOther(3),
TransportError::DecodingFrame => CloseError::TransportInternalErrorOther(4),
TransportError::DecryptError => CloseError::TransportInternalErrorOther(5),
TransportError::HandshakeFailed => CloseError::TransportInternalErrorOther(6),
TransportError::IntegerOverflow => CloseError::TransportInternalErrorOther(7),
TransportError::InvalidInput => CloseError::TransportInternalErrorOther(8),
TransportError::InvalidMigration => CloseError::TransportInternalErrorOther(9),

View File

@ -6,11 +6,11 @@ edition = "2018"
license = "MPL-2.0"
[dependencies]
neqo-bin = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.9.2", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { 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.10.0", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.10.0", git = "https://github.com/mozilla/neqo" }
log = "0.4.0"
base64 = "0.21"
cfg-if = "1.0"
@ -20,7 +20,7 @@ tokio = { version = "1", features = ["rt-multi-thread"] }
mozilla-central-workspace-hack = { version = "0.1", features = ["http3server"], optional = true }
[dependencies.neqo-crypto]
tag = "v0.9.2"
tag = "v0.10.0"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

View File

@ -179,7 +179,7 @@ impl 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 = if self.sessions_to_close.is_empty() {
@ -637,7 +637,7 @@ impl ::std::fmt::Display 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)
}
@ -882,7 +882,7 @@ impl 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);
#[cfg(not(target_os = "android"))]
@ -1015,7 +1015,7 @@ impl ::std::fmt::Display 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
}
@ -1227,7 +1227,7 @@ extern "C" fn __tsan_default_suppressions() -> *const std::os::raw::c_char {
}
// 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" {}
#[cfg_attr(target_os = "windows", link(name="propsys"))]
#[cfg_attr(target_os = "windows", link(name = "propsys"))]
extern "C" {}

View File

@ -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}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76.0"
name = "neqo-bin"
version = "0.9.2"
version = "0.10.0"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = false
autobins = false

View File

@ -4,7 +4,7 @@
// option. This file may not be copied, modified, or distributed
// 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 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();
let done_sender = spawn_server();
let mtu = env::var("MTU").map_or_else(|_| String::new(), |mtu| format!("/mtu-{mtu}"));
for Benchmark { name, requests } in [
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],
},
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],
},
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],
},
] {

View File

@ -26,7 +26,7 @@ use neqo_transport::{
use url::Url;
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> {
streams: HashMap<StreamId, Option<BufWriter<File>>>,
@ -37,6 +37,7 @@ pub struct Handler<'a> {
token: Option<ResumptionToken>,
needs_key_update: bool,
read_buffer: Vec<u8>,
migration: Option<&'a (u16, SocketAddr)>,
}
impl Handler<'_> {
@ -85,6 +86,26 @@ impl super::Handler for Handler<'_> {
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(
State::WaitInitial | State::Handshaking | State::Connected,
) => {
@ -181,10 +202,11 @@ impl super::Client for Connection {
self.process_output(now)
}
fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
where
I: IntoIterator<Item = &'a Datagram>,
{
fn process_multiple_input<'a>(
&mut self,
dgrams: impl IntoIterator<Item = Datagram<&'a [u8]>>,
now: Instant,
) {
self.process_multiple_input(dgrams, now);
}
@ -211,7 +233,11 @@ impl super::Client for Connection {
}
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 {
streams: HashMap::new(),
url_queue,
@ -221,6 +247,7 @@ impl<'b> Handler<'b> {
token: None,
needs_key_update: args.key_update,
read_buffer: vec![0; STREAM_IO_BUFFER_SIZE],
migration,
}
}

View File

@ -132,10 +132,11 @@ impl super::Client for Http3Client {
self.process_output(now)
}
fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
where
I: IntoIterator<Item = &'a Datagram>,
{
fn process_multiple_input<'a>(
&mut self,
dgrams: impl IntoIterator<Item = Datagram<&'a [u8]>>,
now: Instant,
) {
self.process_multiple_input(dgrams, now);
}

View File

@ -31,7 +31,7 @@ use neqo_crypto::{
use neqo_http3::Output;
use neqo_transport::{AppError, CloseReason, ConnectionId, Version};
use tokio::time::Sleep;
use url::{Origin, Url};
use url::{Host, Origin, Url};
use crate::SharedArgs;
@ -231,8 +231,11 @@ impl Args {
// Only use v1 for most QNS tests.
self.shared.quic_parameters.quic_version = vec![Version::Version1];
// This is the default for all tests except http3.
self.shared.use_old_http = true;
match testcase.as_str() {
"http3" => {
self.shared.use_old_http = false;
if let Some(testcase) = &self.test {
if testcase.as_str() != "upload" {
qerror!("Unsupported test case: {testcase}");
@ -242,15 +245,18 @@ impl Args {
self.method = String::from("POST");
}
}
"handshake" | "transfer" | "retry" | "ecn" => {
self.shared.use_old_http = true;
}
"handshake"
| "transfer"
| "retry"
| "ecn"
| "rebind-port"
| "rebind-addr"
| "connectionmigration" => {}
"resumption" => {
if self.urls.len() < 2 {
qerror!("Warning: resumption test won't work without >1 URL");
exit(127);
}
self.shared.use_old_http = true;
self.resume = true;
}
"zerortt" => {
@ -258,7 +264,6 @@ impl Args {
qerror!("Warning: zerortt test won't work without >1 URL");
exit(127);
}
self.shared.use_old_http = true;
self.resume = true;
// PMTUD probes inflate what we sent in 1-RTT, causing QNS to fail the test.
self.shared.quic_parameters.no_pmtud = true;
@ -267,22 +272,18 @@ impl Args {
self.shared.quic_parameters.no_pacing = true;
}
"multiconnect" => {
self.shared.use_old_http = true;
self.download_in_series = true;
}
"chacha20" => {
self.shared.use_old_http = true;
self.shared.ciphers.clear();
self.shared
.ciphers
.extend_from_slice(&[String::from("TLS_CHACHA20_POLY1305_SHA256")]);
}
"keyupdate" => {
self.shared.use_old_http = true;
self.key_update = true;
}
"v2" => {
self.shared.use_old_http = true;
// Use default version set for this test (which allows compatible vneg.)
self.shared.quic_parameters.quic_version.clear();
}
@ -373,9 +374,11 @@ enum CloseState {
/// Network client, e.g. [`neqo_transport::Connection`] or [`neqo_http3::Http3Client`].
trait Client {
fn process_output(&mut self, now: Instant) -> Output;
fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
where
I: IntoIterator<Item = &'a Datagram>;
fn process_multiple_input<'a>(
&mut self,
dgrams: impl IntoIterator<Item = Datagram<&'a [u8]>>,
now: Instant,
);
fn has_events(&self) -> bool;
fn close<S>(&mut self, now: Instant, app_error: AppError, msg: S)
where
@ -391,9 +394,28 @@ struct Runner<'a, H: Handler> {
handler: H,
timeout: Option<Pin<Box<Sleep>>>,
args: &'a Args,
recv_buf: Vec<u8>,
}
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>> {
loop {
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<()> {
loop {
let dgrams = self.socket.recv(&self.local_addr)?;
if dgrams.is_empty() {
let Some(dgrams) = self.socket.recv(self.local_addr, &mut self.recv_buf)? else {
break;
};
if dgrams.len() == 0 {
break;
}
self.client
.process_multiple_input(dgrams.iter(), Instant::now());
self.client.process_multiple_input(dgrams, Instant::now());
self.process_output().await?;
}
@ -492,6 +515,29 @@ fn qlog_new(args: &Args, hostname: &str, cid: &ConnectionId) -> Res<NeqoQlog> {
.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<()> {
neqo_common::log::init(
args.shared
@ -505,46 +551,24 @@ pub async fn client(mut args: Args) -> Res<()> {
init()?;
let urls_by_origin = args
.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 {
for ((host, port), mut urls) in urls_by_origin(&args.urls) {
if args.resume && urls.len() < 2 {
qerror!("Resumption to {host} cannot work without at least 2 URLs.");
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!(
(addr, args.ipv4_only, args.ipv6_only),
(SocketAddr::V4(..), false, true) | (SocketAddr::V6(..), true, false)
)
});
let remote_addr = remote_addrs.next();
let Some(remote_addr) = remote_addr else {
qerror!("No compatible address found for: {host}");
exit(1);
};
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 mut socket = crate::udp::Socket::bind(local_addr_for(&remote_addr, 0))?;
let real_local = socket.local_addr().unwrap();
qinfo!(
"{} Client connecting: {:?} -> {:?}",
@ -553,6 +577,18 @@ pub async fn client(mut args: Args) -> Res<()> {
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 mut token: Option<ResumptionToken> = None;
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)
.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 {
args: &args,
client,
handler,
local_addr: real_local,
socket: &mut socket,
timeout: None,
}
.run()
.await?
Runner::new(real_local, &mut socket, client, handler, &args)
.run()
.await?
} else {
let client = http3::create_client(&args, real_local, remote_addr, &hostname, token)
.expect("failed to create client");
let handler = http3::Handler::new(to_request, &args);
Runner {
args: &args,
client,
handler,
local_addr: real_local,
socket: &mut socket,
timeout: None,
}
.run()
.await?
Runner::new(real_local, &mut socket, client, handler, &args)
.run()
.await?
};
}
}

View File

@ -185,7 +185,7 @@ impl 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)
}

View File

@ -79,7 +79,7 @@ impl Display 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)
}

View File

@ -194,7 +194,7 @@ fn qns_read_response(filename: &str) -> Result<Vec<u8>, io::Error> {
#[allow(clippy::module_name_repetitions)]
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 has_events(&self) -> bool;
}
@ -205,6 +205,7 @@ pub struct ServerRunner {
server: Box<dyn HttpServer>,
timeout: Option<Pin<Box<Sleep>>>,
sockets: Vec<(SocketAddr, crate::udp::Socket)>,
recv_buf: Vec<u8>,
}
impl ServerRunner {
@ -219,6 +220,7 @@ impl ServerRunner {
server,
timeout: None,
sockets,
recv_buf: vec![0; neqo_udp::RECV_BUF_SIZE],
}
}
@ -236,7 +238,7 @@ impl ServerRunner {
.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 {
match self.server.process(dgram.take(), (self.now)()) {
Output::Datagram(dgram) => {
@ -289,12 +291,15 @@ impl ServerRunner {
match self.ready().await? {
Ready::Socket(inx) => loop {
let (host, socket) = self.sockets.get_mut(inx).unwrap();
let dgrams = socket.recv(host)?;
if dgrams.is_empty() {
let Some(dgrams) = socket.recv(*host, &mut self.recv_buf)? else {
break;
};
if dgrams.len() == 0 {
break;
}
let dgrams: Vec<Datagram> = dgrams.map(|d| d.to_owned()).collect();
for dgram in dgrams {
self.process(Some(&dgram)).await?;
self.process(Some(dgram)).await?;
}
},
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.");
}
// This is the default for all tests except http3.
args.shared.use_old_http = true;
// TODO: More options to deduplicate with client?
match testcase.as_str() {
"http3" => (),
"http3" => args.shared.use_old_http = false,
"zerortt" => {
args.shared.use_old_http = true;
args.shared.alpn = String::from(HQ_INTEROP);
args.shared.quic_parameters.max_streams_bidi = 100;
}
"handshake" | "transfer" | "resumption" | "multiconnect" | "v2" | "ecn" => {
args.shared.use_old_http = true;
"handshake"
| "transfer"
| "resumption"
| "multiconnect"
| "v2"
| "ecn"
| "rebind-port"
| "rebind-addr"
| "connectionmigration" => {
args.shared.alpn = String::from(HQ_INTEROP);
}
"chacha20" => {
args.shared.use_old_http = true;
args.shared.alpn = String::from(HQ_INTEROP);
args.shared.ciphers.clear();
args.shared
@ -357,7 +369,6 @@ pub async fn server(mut args: Args) -> Res<()> {
.extend_from_slice(&[String::from("TLS_CHACHA20_POLY1305_SHA256")]);
}
"retry" => {
args.shared.use_old_http = true;
args.shared.alpn = String::from(HQ_INTEROP);
args.retry = true;
}

View File

@ -7,6 +7,7 @@
use std::{io, net::SocketAddr};
use neqo_common::Datagram;
use neqo_udp::DatagramIter;
/// 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
/// 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
.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| {
if e.kind() == io::ErrorKind::WouldBlock {
Ok(vec![])
Ok(None)
} else {
Err(e)
}

View File

@ -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}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76.0"
name = "neqo-common"
version = "0.9.2"
version = "0.10.0"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = "build.rs"
autobins = false

View File

@ -9,23 +9,14 @@ use std::{net::SocketAddr, ops::Deref};
use crate::{hex_with_len, IpTos};
#[derive(Clone, PartialEq, Eq)]
pub struct Datagram {
pub struct Datagram<D = Vec<u8>> {
src: SocketAddr,
dst: SocketAddr,
tos: IpTos,
d: Vec<u8>,
d: D,
}
impl Datagram {
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> Datagram<D> {
#[must_use]
pub const fn source(&self) -> SocketAddr {
self.src
@ -46,15 +37,43 @@ impl Datagram {
}
}
impl Deref for Datagram {
type Target = Vec<u8>;
#[must_use]
fn deref(&self) -> &Self::Target {
&self.d
impl<D: AsRef<[u8]>> Datagram<D> {
pub fn len(&self) -> usize {
self.d.as_ref().len()
}
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 {
write!(
f,
@ -67,14 +86,46 @@ impl std::fmt::Debug for Datagram {
}
}
#[cfg(test)]
use test_fixture::datagram;
impl<'a> Datagram<&'a [u8]> {
#[must_use]
pub const fn from_slice(src: SocketAddr, dst: SocketAddr, tos: IpTos, d: &'a [u8]) -> Self {
Self { src, dst, tos, d }
}
#[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"
);
#[must_use]
pub fn to_owned(&self) -> Datagram {
Datagram {
src: self.src,
dst: self.dst,
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());
}
}

View File

@ -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}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76.0"
name = "neqo-crypto"
version = "0.9.2"
version = "0.10.0"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = "build.rs"
autobins = false

View File

@ -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}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76.0"
name = "neqo-http3"
version = "0.9.2"
version = "0.10.0"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = false
autobins = false

File diff suppressed because it is too large Load Diff

View File

@ -68,7 +68,7 @@ pub(crate) enum ExtendedConnectType {
impl ExtendedConnectType {
#[must_use]
#[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"
}

View File

@ -63,8 +63,8 @@ pub fn default_http3_server(server_params: Http3Parameters) -> Http3Server {
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
let mut out = None;
loop {
out = client.process(out.as_ref(), now()).dgram();
out = server.process(out.as_ref(), now()).dgram();
out = client.process(out, now()).dgram();
out = server.process(out, now()).dgram();
if out.is_none() {
break;
}
@ -74,31 +74,31 @@ fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
// Perform only Quic transport handshake.
fn connect_with(client: &mut Http3Client, server: &mut Http3Server) {
assert_eq!(client.state(), Http3State::Initializing);
let out = client.process(None, now());
let out = client.process_output(now());
assert_eq!(client.state(), Http3State::Initializing);
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(out.as_dgram_ref(), now());
let out = server.process(out.as_dgram_ref(), now());
let out = server.process(out.dgram(), now());
let out = client.process(out.dgram(), now());
let out = server.process(out.dgram(), now());
assert!(out.as_dgram_ref().is_none());
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(client.events().any(authentication_needed));
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));
assert!(client.events().any(connected));
assert_eq!(client.state(), Http3State::Connected);
// Exchange H3 setttings
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(out.as_dgram_ref(), now());
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(out.as_dgram_ref(), now());
let out = server.process(out.as_dgram_ref(), now());
std::mem::drop(client.process(out.as_dgram_ref(), now()));
let out = server.process(out.dgram(), now());
let out = client.process(out.dgram(), now());
let out = server.process(out.dgram(), now());
let out = client.process(out.dgram(), now());
let out = server.process(out.dgram(), now());
std::mem::drop(client.process(out.dgram(), now()));
}
fn connect(
@ -200,10 +200,10 @@ impl WtTest {
let mut now = now();
loop {
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();
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() {
break;
}

View File

@ -86,9 +86,9 @@ fn zero_rtt(
assert_eq!(client.webtransport_enabled(), client_org && server_org);
// 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.
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);
let token = client
.events()
@ -233,8 +233,8 @@ fn zero_rtt_wt_settings() {
fn exchange_packets2(client: &mut Http3Client, server: &mut Connection) {
let mut out = None;
loop {
out = client.process(out.as_ref(), now()).dgram();
out = server.process(out.as_ref(), now()).dgram();
out = client.process(out, now()).dgram();
out = server.process(out, now()).dgram();
if out.is_none() {
break;
}

View File

@ -425,18 +425,18 @@ fn wt_close_session_cannot_be_sent_at_once() {
Err(Error::InvalidStreamId)
);
let out = wt.server.process(None, now());
let out = wt.client.process(out.as_dgram_ref(), now());
let out = wt.server.process_output(now());
let out = wt.client.process(out.dgram(), now());
// 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 out = wt.server.process(out.as_dgram_ref(), now());
let out = wt.client.process(out.as_dgram_ref(), now());
let out = wt.server.process(out.as_dgram_ref(), now());
let out = wt.client.process(out.as_dgram_ref(), now());
let out = wt.server.process(out.as_dgram_ref(), now());
let _out = wt.client.process(out.as_dgram_ref(), now());
let out = wt.server.process(out.dgram(), now());
let out = wt.client.process(out.dgram(), now());
let out = wt.server.process(out.dgram(), now());
let out = wt.client.process(out.dgram(), now());
let out = wt.server.process(out.dgram(), now());
let _out = wt.client.process(out.dgram(), now());
wt.check_events_after_closing_session_client(
&[],

View File

@ -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_s = default_server();
let out = conn_c.process(None, now());
let out = conn_s.process(out.as_dgram_ref(), now());
let out = conn_c.process(out.as_dgram_ref(), now());
mem::drop(conn_s.process(out.as_dgram_ref(), now()));
let out = conn_c.process_output(now());
let out = conn_s.process(out.dgram(), now());
let out = conn_c.process(out.dgram(), now());
mem::drop(conn_s.process(out.dgram(), now()));
conn_c.authenticated(AuthenticationStatus::Ok, now());
let out = conn_c.process(None, now());
mem::drop(conn_s.process(out.as_dgram_ref(), now()));
let out = conn_c.process_output(now());
mem::drop(conn_s.process(out.dgram(), now()));
// create a stream
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
let buf = Encoder::from_hex(st);
conn_s.stream_send(stream_id, buf.as_ref()).unwrap();
let out = conn_s.process(None, now());
mem::drop(conn_c.process(out.as_dgram_ref(), now()));
let out = conn_s.process_output(now());
mem::drop(conn_c.process(out.dgram(), now()));
let (frame, fin) = fr
.receive::<T>(&mut StreamReaderConnectionWrapper::new(

View File

@ -39,8 +39,8 @@ impl FrameReaderTest {
fn process<T: FrameDecoder<T>>(&mut self, v: &[u8]) -> Option<T> {
self.conn_s.stream_send(self.stream_id, v).unwrap();
let out = self.conn_s.process(None, now());
mem::drop(self.conn_c.process(out.as_dgram_ref(), now()));
let out = self.conn_s.process_output(now());
mem::drop(self.conn_c.process(out.dgram(), now()));
let (frame, fin) = self
.fr
.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();
}
let out = fr.conn_s.process(None, now());
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
let out = fr.conn_s.process_output(now());
mem::drop(fr.conn_c.process(out.dgram(), now()));
if matches!(test_to_send, FrameReadingTestSend::DataThenFin) {
fr.conn_s.stream_close_send(fr.stream_id).unwrap();
let out = fr.conn_s.process(None, now());
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
let out = fr.conn_s.process_output(now());
mem::drop(fr.conn_c.process(out.dgram(), now()));
}
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();
fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap();
let out = fr.conn_s.process(None, now());
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
let out = fr.conn_s.process_output(now());
mem::drop(fr.conn_c.process(out.dgram(), now()));
assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id));
let out = fr.conn_c.process(None, now());
mem::drop(fr.conn_s.process(out.as_dgram_ref(), now()));
let out = fr.conn_c.process_output(now());
mem::drop(fr.conn_s.process(out.dgram(), now()));
assert_eq!(
Ok((None, true)),
fr.fr
@ -501,12 +501,12 @@ fn wt_frame_reading_when_stream_is_closed_before_sending_data() {
let mut fr = FrameReaderTest::new();
fr.conn_s.stream_send(fr.stream_id, &[0x00]).unwrap();
let out = fr.conn_s.process(None, now());
mem::drop(fr.conn_c.process(out.as_dgram_ref(), now()));
let out = fr.conn_s.process_output(now());
mem::drop(fr.conn_c.process(out.dgram(), now()));
assert_eq!(Ok(()), fr.conn_c.stream_close_send(fr.stream_id));
let out = fr.conn_c.process(None, now());
mem::drop(fr.conn_s.process(out.as_dgram_ref(), now()));
let out = fr.conn_c.process_output(now());
mem::drop(fr.conn_s.process(out.dgram(), now()));
assert_eq!(
Ok((None, true)),
fr.fr

View File

@ -364,7 +364,7 @@ impl PushController {
}
Some(PushState::Active { stream_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(
conn,
*stream_id,

View File

@ -113,7 +113,12 @@ impl Http3Server {
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.");
let out = self.server.process(dgram, now);
self.process_http3(now);
@ -123,7 +128,7 @@ impl Http3Server {
qtrace!([self], "Send packet: {:?}", 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);
fn connect_transport(server: &mut Http3Server, client: &mut Connection, resume: bool) {
let c1 = client.process(None, now());
let s1 = server.process(c1.as_dgram_ref(), now());
let c2 = client.process(s1.as_dgram_ref(), now());
let c1 = client.process_output(now());
let s1 = server.process(c1.dgram(), now());
let c2 = client.process(s1.dgram(), now());
let needs_auth = client
.events()
.any(|e| e == ConnectionEvent::AuthenticationNeeded);
let c2 = if needs_auth {
assert!(!resume);
// c2 should just be an ACK, so absorb that.
let s_ack = server.process(c2.as_dgram_ref(), now());
assert!(s_ack.as_dgram_ref().is_none());
let s_ack = server.process(c2.dgram(), now());
assert!(s_ack.dgram().is_none());
client.authenticated(AuthenticationStatus::Ok, now());
client.process(None, now())
client.process_output(now())
} else {
assert!(resume);
c2
};
assert!(client.state().connected());
let s2 = server.process(c2.as_dgram_ref(), now());
let s2 = server.process(c2.dgram(), now());
assert_connected(server);
let c3 = client.process(s2.as_dgram_ref(), now());
assert!(c3.as_dgram_ref().is_none());
let c3 = client.process(s2.dgram(), now());
assert!(c3.dgram().is_none());
}
// 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();
sent = neqo_trans_conn.stream_send(decoder_stream, &[0x3]);
assert_eq!(sent, Ok(1));
let out1 = neqo_trans_conn.process(None, now());
let out2 = server.process(out1.as_dgram_ref(), now());
mem::drop(neqo_trans_conn.process(out2.as_dgram_ref(), now()));
let out1 = neqo_trans_conn.process_output(now());
let out2 = server.process(out1.dgram(), now());
mem::drop(neqo_trans_conn.process(out2.dgram(), now()));
// assert no error occured.
assert_not_closed(server);
@ -584,8 +589,8 @@ mod tests {
let (mut hconn, mut peer_conn) = connect();
let control = peer_conn.control_stream_id;
peer_conn.stream_close_send(control).unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
}
@ -599,8 +604,8 @@ mod tests {
// Send a MAX_PUSH_ID frame instead.
let sent = neqo_trans_conn.stream_send(control_stream, &[0x0, 0xd, 0x1, 0xf]);
assert_eq!(sent, Ok(4));
let out = neqo_trans_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = neqo_trans_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpMissingSettings);
}
@ -611,8 +616,8 @@ mod tests {
let (mut hconn, mut peer_conn) = connect();
// send the second SETTINGS frame.
peer_conn.control_send(&[0x4, 0x6, 0x1, 0x40, 0x64, 0x7, 0x40, 0x64]);
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpFrameUnexpected);
}
@ -626,8 +631,8 @@ mod tests {
let mut e = Encoder::default();
frame.encode(&mut e);
peer_conn.control_send(e.as_ref());
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
// check if the given connection got closed on invalid stream ids
if valid {
assert_not_closed(&hconn);
@ -669,8 +674,8 @@ mod tests {
// receive a frame that is not allowed on the control stream.
peer_conn.control_send(v);
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpFrameUnexpected);
}
@ -703,11 +708,11 @@ mod tests {
_ = peer_conn
.stream_send(new_stream_id, &[0x41, 0x19, 0x4, 0x4, 0x6, 0x0, 0x8, 0x0])
.unwrap();
let out = peer_conn.process(None, now());
let out = hconn.process(out.as_dgram_ref(), now());
mem::drop(peer_conn.process(out.as_dgram_ref(), now()));
let out = hconn.process(None, now());
mem::drop(peer_conn.process(out.as_dgram_ref(), now()));
let out = peer_conn.process_output(now());
let out = hconn.process(out.dgram(), now());
mem::drop(peer_conn.process(out.dgram(), now()));
let out = hconn.process_output(now());
mem::drop(peer_conn.process(out.dgram(), now()));
// check for stop-sending with Error::HttpStreamCreation.
let mut stop_sending_event_found = false;
@ -734,9 +739,9 @@ mod tests {
// create a push stream.
let push_stream_id = peer_conn.stream_create(StreamType::UniDi).unwrap();
_ = peer_conn.stream_send(push_stream_id, &[0x1]).unwrap();
let out = peer_conn.process(None, now());
let out = hconn.process(out.as_dgram_ref(), now());
mem::drop(peer_conn.conn.process(out.as_dgram_ref(), now()));
let out = peer_conn.process_output(now());
let out = hconn.process(out.dgram(), now());
mem::drop(peer_conn.conn.process(out.dgram(), now()));
assert_closed(&hconn, &Error::HttpStreamCreation);
}
@ -751,77 +756,77 @@ mod tests {
// send the stream type
let mut sent = peer_conn.stream_send(control_stream, &[0x0]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
// start sending SETTINGS frame
sent = peer_conn.stream_send(control_stream, &[0x4]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x4]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x6]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x0]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x8]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x0]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_not_closed(&hconn);
// Now test PushPromise
sent = peer_conn.stream_send(control_stream, &[0x5]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x5]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x4]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x61]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x62]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x63]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
sent = peer_conn.stream_send(control_stream, &[0x64]);
assert_eq!(sent, Ok(1));
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
// PUSH_PROMISE on a control stream will cause an error
assert_closed(&hconn, &Error::HttpFrameUnexpected);
@ -836,8 +841,8 @@ mod tests {
peer_conn.stream_send(stream_id, res).unwrap();
peer_conn.stream_close_send(stream_id).unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpFrame);
}
@ -888,8 +893,8 @@ mod tests {
peer_conn.stream_send(stream_id, REQUEST_WITH_BODY).unwrap();
peer_conn.stream_close_send(stream_id).unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
// Check connection event. There should be 1 Header and 2 data events.
let mut headers_frames = 0;
@ -935,8 +940,8 @@ mod tests {
.stream_send(stream_id, &REQUEST_WITH_BODY[..20])
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
// Check connection event. There should be 1 Header and no data events.
let mut headers_frames = 0;
@ -972,7 +977,7 @@ mod tests {
| Http3ServerEvent::WebTransport(_) => {}
}
}
let out = hconn.process(None, now());
let out = hconn.process_output(now());
// Send data.
peer_conn
@ -980,8 +985,8 @@ mod tests {
.unwrap();
peer_conn.stream_close_send(stream_id).unwrap();
let out = peer_conn.process(out.as_dgram_ref(), now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process(out.dgram(), now());
hconn.process(out.dgram(), now());
while let Some(event) = hconn.next_event() {
match event {
@ -1012,8 +1017,8 @@ mod tests {
.stream_send(request_stream_id, &REQUEST_WITH_BODY[..20])
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
// Check connection event. There should be 1 Header and no data events.
// The server will reset the stream.
@ -1043,10 +1048,10 @@ mod tests {
| Http3ServerEvent::WebTransport(_) => {}
}
}
let out = hconn.process(None, now());
let out = hconn.process_output(now());
let out = peer_conn.process(out.as_dgram_ref(), now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process(out.dgram(), now());
hconn.process(out.dgram(), now());
// Check that STOP_SENDING and REET has been received.
let mut reset = 0;
@ -1077,8 +1082,8 @@ mod tests {
peer_conn
.stream_reset_send(CLIENT_SIDE_CONTROL_STREAM_ID, Error::HttpNoError.code())
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
}
@ -1090,8 +1095,8 @@ mod tests {
peer_conn
.stream_reset_send(CLIENT_SIDE_ENCODER_STREAM_ID, Error::HttpNoError.code())
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
}
@ -1103,8 +1108,8 @@ mod tests {
peer_conn
.stream_reset_send(CLIENT_SIDE_DECODER_STREAM_ID, Error::HttpNoError.code())
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
}
@ -1117,8 +1122,8 @@ mod tests {
peer_conn
.stream_stop_sending(SERVER_SIDE_CONTROL_STREAM_ID, Error::HttpNoError.code())
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
}
@ -1130,8 +1135,8 @@ mod tests {
peer_conn
.stream_stop_sending(SERVER_SIDE_ENCODER_STREAM_ID, Error::HttpNoError.code())
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
}
@ -1143,8 +1148,8 @@ mod tests {
peer_conn
.stream_stop_sending(SERVER_SIDE_DECODER_STREAM_ID, Error::HttpNoError.code())
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
assert_closed(&hconn, &Error::HttpClosedCriticalStream);
}
@ -1251,8 +1256,8 @@ mod tests {
.stream_send(request_stream_id_2, REQUEST_WITH_BODY)
.unwrap();
let out = peer_conn.process(None, now());
hconn.process(out.as_dgram_ref(), now());
let out = peer_conn.process_output(now());
hconn.process(out.dgram(), now());
let mut requests = HashMap::new();
while let Some(event) = hconn.next_event() {

View File

@ -268,8 +268,8 @@ mod tests {
let (mut conn_c, mut conn_s) = connect();
// create a stream
let stream_id = conn_s.stream_create(stream_type).unwrap();
let out = conn_s.process(None, now());
mem::drop(conn_c.process(out.as_dgram_ref(), now()));
let out = conn_s.process_output(now());
mem::drop(conn_c.process(out.dgram(), now()));
Self {
conn_c,
@ -291,8 +291,8 @@ mod tests {
self.conn_s
.stream_send(self.stream_id, &enc[i..=i])
.unwrap();
let out = self.conn_s.process(None, now());
mem::drop(self.conn_c.process(out.as_dgram_ref(), now()));
let out = self.conn_s.process_output(now());
mem::drop(self.conn_c.process(out.dgram(), now()));
assert_eq!(
self.decoder.receive(&mut self.conn_c).unwrap(),
(ReceiveOutput::NoOutput, false)
@ -305,8 +305,8 @@ mod tests {
if fin {
self.conn_s.stream_close_send(self.stream_id).unwrap();
}
let out = self.conn_s.process(None, now());
mem::drop(self.conn_c.process(out.dgram().as_ref(), now()));
let out = self.conn_s.process_output(now());
mem::drop(self.conn_c.process(out.dgram(), now()));
assert_eq!(&self.decoder.receive(&mut self.conn_c), outcome);
assert_eq!(self.decoder.done(), done);
}

View File

@ -94,20 +94,20 @@ fn process_client_events(conn: &mut Http3Client) {
fn connect_peers(hconn_c: &mut Http3Client, hconn_s: &mut Http3Server) -> Option<Datagram> {
assert_eq!(hconn_c.state(), Http3State::Initializing);
let out = hconn_c.process(None, now()); // Initial
let out = hconn_s.process(out.as_dgram_ref(), now()); // Initial + Handshake
let out = hconn_c.process(out.as_dgram_ref(), now()); // ACK
mem::drop(hconn_s.process(out.as_dgram_ref(), now())); // consume ACK
let out = hconn_c.process_output(now()); // Initial
let out = hconn_s.process(out.dgram(), now()); // Initial + Handshake
let out = hconn_c.process(out.dgram(), now()); // ACK
mem::drop(hconn_s.process(out.dgram(), now())); // consume ACK
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(hconn_c.events().any(authentication_needed));
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);
let out = hconn_s.process(out.as_dgram_ref(), now()); // Handshake
let out = hconn_c.process(out.as_dgram_ref(), now());
let out = hconn_s.process(out.as_dgram_ref(), now());
let out = hconn_s.process(out.dgram(), now()); // Handshake
let out = hconn_c.process(out.dgram(), now());
let out = hconn_s.process(out.dgram(), now());
// 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);
out.dgram()
@ -121,28 +121,28 @@ fn connect_peers_with_network_propagation_delay(
let net_delay = Duration::from_millis(net_delay);
assert_eq!(hconn_c.state(), Http3State::Initializing);
let mut now = now();
let out = hconn_c.process(None, now); // Initial
let out = hconn_c.process_output(now); // Initial
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;
let out = hconn_c.process(out.as_dgram_ref(), now); // ACK
let out = hconn_c.process(out.dgram(), now); // ACK
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());
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(hconn_c.events().any(authentication_needed));
now += net_delay;
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);
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;
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;
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;
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)
}
@ -157,8 +157,8 @@ fn connect() -> (Http3Client, Http3Server, Option<Datagram>) {
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server, out_ex: Option<Datagram>) {
let mut out = out_ex;
loop {
out = client.process(out.as_ref(), now()).dgram();
out = server.process(out.as_ref(), now()).dgram();
out = client.process(out, now()).dgram();
out = server.process(out, now()).dgram();
if out.is_none() {
break;
}
@ -186,17 +186,17 @@ fn fetch() {
.unwrap();
assert_eq!(req, 0);
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");
let out = hconn_s.process(out.as_dgram_ref(), now());
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
let out = hconn_s.process(out.dgram(), now());
mem::drop(hconn_c.process(out.dgram(), now()));
process_server_events(&hconn_s);
let out = hconn_s.process(None, now());
let out = hconn_s.process(None::<Datagram>, now());
qtrace!("-----client");
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
let out = hconn_s.process(None, now());
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
mem::drop(hconn_c.process(out.dgram(), now()));
let out = hconn_s.process(None::<Datagram>, now());
mem::drop(hconn_c.process(out.dgram(), now()));
process_client_events(&mut hconn_c);
}
@ -215,10 +215,10 @@ fn response_103() {
.unwrap();
assert_eq!(req, 0);
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());
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
let out = hconn_s.process(out.dgram(), now());
mem::drop(hconn_c.process(out.dgram(), now()));
let request = receive_request(&hconn_s).unwrap();
let info_headers = [
Header::new(":status", "103"),
@ -226,9 +226,9 @@ fn response_103() {
];
// Send 103
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| {
matches!(e, Http3ClientEvent::HeaderReady { headers,
@ -238,8 +238,8 @@ fn response_103() {
assert!(hconn_c.events().any(info_headers_event));
set_response(&request);
let out = hconn_s.process(None, now());
mem::drop(hconn_c.process(out.as_dgram_ref(), now()));
let out = hconn_s.process(None::<Datagram>, now());
mem::drop(hconn_c.process(out.dgram(), now()));
process_client_events(&mut hconn_c);
}
@ -448,8 +448,8 @@ fn zerortt() {
.unwrap();
hconn_c.stream_close_send(req).unwrap();
let out = hconn_c.process(dgram.as_ref(), now());
let out = hconn_s.process(out.as_dgram_ref(), now());
let out = hconn_c.process(dgram, now());
let out = hconn_s.process(out.dgram(), now());
let mut request_stream = None;
let mut zerortt_state_change = false;
@ -513,7 +513,7 @@ fn fetch_noresponse_will_idletimeout() {
.unwrap();
assert_eq!(req, 0);
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");
let mut done = false;

View File

@ -16,9 +16,9 @@ use test_fixture::*;
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
let mut out = None;
loop {
out = client.process(out.as_ref(), now()).dgram();
out = client.process(out, now()).dgram();
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 {
break;
}
@ -28,29 +28,29 @@ fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
// Perform only Quic transport handshake.
fn connect_with(client: &mut Http3Client, server: &mut Http3Server) {
assert_eq!(client.state(), Http3State::Initializing);
let out = client.process(None, now());
let out = client.process_output(now());
assert_eq!(client.state(), Http3State::Initializing);
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(out.as_dgram_ref(), now());
let out = server.process(out.as_dgram_ref(), now());
let out = server.process(out.dgram(), now());
let out = client.process(out.dgram(), now());
let out = server.process(out.dgram(), now());
assert!(out.as_dgram_ref().is_none());
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(client.events().any(authentication_needed));
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));
assert!(client.events().any(connected));
assert_eq!(client.state(), Http3State::Connected);
// Exchange H3 setttings
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(out.as_dgram_ref(), now());
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(out.as_dgram_ref(), now());
_ = server.process(out.as_dgram_ref(), now());
let out = server.process(out.dgram(), now());
let out = client.process(out.dgram(), now());
let out = server.process(out.dgram(), now());
let out = client.process(out.dgram(), now());
_ = server.process(out.dgram(), now());
}
fn connect() -> (Http3Client, Http3Server) {

View File

@ -29,8 +29,8 @@ fn response_header_103() -> &'static Vec<Header> {
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
let mut out = None;
loop {
out = client.process(out.as_ref(), now()).dgram();
out = server.process(out.as_ref(), now()).dgram();
out = client.process(out, now()).dgram();
out = server.process(out, now()).dgram();
if out.is_none() {
break;
}

View File

@ -41,19 +41,19 @@ fn connect() -> (Http3Client, Http3Server) {
)
.expect("create a server");
assert_eq!(client.state(), Http3State::Initializing);
let out = client.process(None, now());
let out = client.process_output(now());
assert_eq!(client.state(), Http3State::Initializing);
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(out.as_dgram_ref(), now());
let out = server.process(out.as_dgram_ref(), now());
let out = server.process(out.dgram(), now());
let out = client.process(out.dgram(), now());
let out = server.process(out.dgram(), now());
assert!(out.as_dgram_ref().is_none());
let authentication_needed = |e| matches!(e, Http3ClientEvent::AuthenticationNeeded);
assert!(client.events().any(authentication_needed));
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));
assert!(client.events().any(connected));
@ -61,9 +61,9 @@ fn connect() -> (Http3Client, Http3Server) {
// Exchange H3 setttings
loop {
out = server.process(out.as_ref(), now()).dgram();
out = server.process(out, now()).dgram();
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 {
break;
}
@ -74,8 +74,8 @@ fn connect() -> (Http3Client, Http3Server) {
fn exchange_packets(client: &mut Http3Client, server: &mut Http3Server) {
let mut out = None;
loop {
out = client.process(out.as_ref(), now()).dgram();
out = server.process(out.as_ref(), now()).dgram();
out = client.process(out, now()).dgram();
out = server.process(out, now()).dgram();
if out.is_none() {
break;
}

View File

@ -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}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76.0"
name = "neqo-qpack"
version = "0.9.2"
version = "0.10.0"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = false
autobins = false

View File

@ -333,8 +333,8 @@ mod tests {
.peer_conn
.stream_send(decoder.recv_stream_id, encoder_instruction)
.unwrap();
let out = decoder.peer_conn.process(None, now());
mem::drop(decoder.conn.process(out.as_dgram_ref(), now()));
let out = decoder.peer_conn.process_output(now());
mem::drop(decoder.conn.process(out.dgram(), now()));
assert_eq!(
decoder
.decoder
@ -345,8 +345,8 @@ mod tests {
fn send_instructions_and_check(decoder: &mut TestDecoder, decoder_instruction: &[u8]) {
decoder.decoder.send(&mut decoder.conn).unwrap();
let out = decoder.conn.process(None, now());
mem::drop(decoder.peer_conn.process(out.as_dgram_ref(), now()));
let out = decoder.conn.process_output(now());
mem::drop(decoder.peer_conn.process(out.dgram(), now()));
let mut buf = [0_u8; 100];
let (amount, fin) = decoder
.peer_conn

View File

@ -572,9 +572,9 @@ mod tests {
pub fn send_instructions(&mut self, encoder_instruction: &[u8]) {
self.encoder.send_encoder_updates(&mut self.conn).unwrap();
let out = self.conn.process(None, now());
let out2 = self.peer_conn.process(out.as_dgram_ref(), now());
mem::drop(self.conn.process(out2.as_dgram_ref(), now()));
let out = self.conn.process_output(now());
let out2 = self.peer_conn.process(out.dgram(), now());
mem::drop(self.conn.process(out2.dgram(), now()));
let mut buf = [0_u8; 100];
let (amount, fin) = self
.peer_conn
@ -635,8 +635,8 @@ mod tests {
.peer_conn
.stream_send(encoder.recv_stream_id, decoder_instruction)
.unwrap();
let out = encoder.peer_conn.process(None, now());
mem::drop(encoder.conn.process(out.as_dgram_ref(), now()));
let out = encoder.peer_conn.process_output(now());
mem::drop(encoder.conn.process(out.dgram(), now()));
assert!(encoder
.encoder
.read_instructions(&mut encoder.conn, encoder.recv_stream_id)
@ -1563,8 +1563,8 @@ mod tests {
encoder.send_instructions(ONE_INSTRUCTION_1);
// exchange a flow control update.
let out = encoder.peer_conn.process(None, now());
mem::drop(encoder.conn.process(out.as_dgram_ref(), now()));
let out = encoder.peer_conn.process_output(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,
// because instructions can be sent.
@ -1610,8 +1610,8 @@ mod tests {
.encoder
.send_encoder_updates(&mut encoder.conn)
.unwrap();
let out = encoder.conn.process(None, now());
mem::drop(encoder.peer_conn.process(out.as_dgram_ref(), now()));
let out = encoder.conn.process_output(now());
mem::drop(encoder.peer_conn.process(out.dgram(), now()));
// receive an insert count increment.
recv_instruction(&mut encoder, &[0x01]);

File diff suppressed because one or more lines are too long

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76.0"
name = "neqo-transport"
version = "0.9.2"
version = "0.10.0"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = "build.rs"
autobins = false

View File

@ -13,7 +13,7 @@ use test_fixture::{
sim::{
connection::{ConnectionNode, ReachState, ReceiveData, SendData},
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 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] {
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
@ -52,9 +53,7 @@ fn benchmark_transfer(c: &mut Criterion, label: &str, seed: &Option<impl AsRef<s
}
sim.setup()
},
|sim| {
sim.run();
},
ReadySimulator::run,
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) {
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) {
benchmark_transfer(
c,
"same-seed",
&Some("62df6933ba1f543cece01db8f27fb2025529b27f93df39e19f006e1db3b8c843"),
Some("62df6933ba1f543cece01db8f27fb2025529b27f93df39e19f006e1db3b8c843"),
);
}

View File

@ -1022,15 +1022,16 @@ impl 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);
}
/// Process new input datagrams on the connection.
pub fn process_multiple_input<'a, I>(&mut self, dgrams: I, now: Instant)
where
I: IntoIterator<Item = &'a Datagram>,
{
pub fn process_multiple_input(
&mut self,
dgrams: impl IntoIterator<Item = Datagram<impl AsRef<[u8]>>>,
now: Instant,
) {
let mut dgrams = dgrams.into_iter().peekable();
if dgrams.peek().is_none() {
return;
@ -1161,7 +1162,7 @@ impl Connection {
/// Process input and generate output.
#[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 {
self.input(d, now, 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 connection is connected, then the reset token will be invalid.
if d.len() < 16 || !self.state.connected() {
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))
}
fn check_stateless_reset(
&mut self,
path: &PathRef,
d: &Datagram,
d: &Datagram<impl AsRef<[u8]>>,
first: bool,
now: Instant,
) -> Res<()> {
@ -1280,24 +1281,27 @@ impl Connection {
debug_assert!(self.crypto.states.rx_hp(self.version, cspace).is_some());
for saved in self.saved_datagrams.take_saved() {
qtrace!([self], "input saved @{:?}: {:?}", saved.t, saved.d);
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
/// part that we don't have keys for.
fn save_datagram(&mut self, cspace: CryptoSpace, d: &Datagram, remaining: usize, now: Instant) {
let d = if remaining < d.len() {
Datagram::new(
d.source(),
d.destination(),
d.tos(),
&d[d.len() - remaining..],
)
} else {
d.clone()
};
#[allow(clippy::needless_pass_by_value)] // To consume an owned datagram below.
fn save_datagram(
&mut self,
cspace: CryptoSpace,
d: Datagram<impl AsRef<[u8]>>,
remaining: usize,
now: Instant,
) {
let d = Datagram::new(
d.source(),
d.destination(),
d.tos(),
d[d.len() - remaining..].to_vec(),
);
self.saved_datagrams.save(cspace, d, now);
self.stats.borrow_mut().saved_datagrams += 1;
}
@ -1498,7 +1502,7 @@ impl Connection {
fn postprocess_packet(
&mut self,
path: &PathRef,
d: &Datagram,
d: &Datagram<impl AsRef<[u8]>>,
packet: &PublicPacket,
migrate: bool,
now: Instant,
@ -1530,7 +1534,7 @@ impl Connection {
/// 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.
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.
let path = self.paths.find_path_with_rebinding(
d.destination(),
@ -1544,11 +1548,16 @@ impl Connection {
self.capture_error(Some(path), now, 0, res).ok();
}
fn input_path(&mut self, path: &PathRef, d: &Datagram, now: Instant) -> Res<()> {
let mut slc = &d[..];
fn input_path(
&mut self,
path: &PathRef,
d: Datagram<impl AsRef<[u8]>>,
now: Instant,
) -> Res<()> {
let mut slc = d.as_ref();
let mut dcid = None;
qtrace!([self], "{} input {}", path.borrow(), hex(&**d));
qtrace!([self], "{} input {}", path.borrow(), hex(&d));
let pto = path.borrow().rtt().pto(self.confirmed());
// Handle each packet in the datagram.
@ -1606,7 +1615,7 @@ impl Connection {
} else {
match self.process_packet(path, &payload, now) {
Ok(migrate) => {
self.postprocess_packet(path, d, &packet, migrate, now);
self.postprocess_packet(path, &d, &packet, migrate, now);
}
Err(e) => {
self.ensure_error_path(path, &packet, now);
@ -1648,7 +1657,7 @@ impl Connection {
// Decryption failure, or not having keys is not fatal.
// 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.
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");
qlog::packet_dropped(&self.qlog, &packet);
}
@ -1656,7 +1665,7 @@ impl Connection {
slc = remainder;
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(())
}
@ -1958,7 +1967,13 @@ impl Connection {
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 {
return;
}

View File

@ -13,7 +13,7 @@ use super::{
ack_bytes, connect_rtt_idle, default_client, default_server, fill_cwnd, increase_cwnd,
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
/// `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.
now += DEFAULT_RTT / 2;
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_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.
let d = send_something(&mut client, now);
now += RTT / 2;
let ack = server.process(Some(&d), now).dgram();
let ack = server.process(Some(d), now).dgram();
assert!(ack.is_some());
let d = send_something(&mut client, now);
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!(client.stats().frame_tx.ack_frequency, 1);
@ -144,11 +144,11 @@ fn ack_rate_server_half_rtt() {
now += RTT / 2;
// The client now will acknowledge immediately because it has been more than
// 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());
let d = send_something(&mut server, now);
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!(server.stats().frame_tx.ack_frequency, 1);
@ -169,10 +169,11 @@ fn migrate_ack_delay() {
let client1 = send_something(&mut client, now);
assertions::assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
assert_path_challenge_min_len(&client, &client1, now);
let client2 = send_something(&mut client, now);
assertions::assert_v4_path(&client2, false); // Doesn't. Is dropped.
now += DEFAULT_RTT / 2;
server.process_input(&client1, now);
server.process_input(client1, now);
let stream = client.stream_create(StreamType::UniDi).unwrap();
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.
// It has sent a few before (as we dropped `client2`), so ignore those.
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_eq!(client.stats().frame_tx.ack_frequency, ad_before + 1);
}

View File

@ -47,7 +47,7 @@ fn cc_slow_start_pmtud() {
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
let cwnd = cwnd_avail(&client);
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!(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
now += DEFAULT_RTT / 2;
client.process_input(&s_ack, now);
client.process_input(s_ack, now);
assert_eq!(
client.stats().frame_rx.largest_acknowledged,
flight1_largest
@ -117,7 +117,7 @@ fn cc_slow_start_to_cong_avoidance_recovery_period(congestion_signal: Congestion
// Client: Process ack
now += DEFAULT_RTT / 2;
client.process_input(&s_ack, now);
client.process_input(s_ack, now);
assert_eq!(
client.stats().frame_rx.largest_acknowledged,
flight2_largest
@ -160,7 +160,7 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
// Server: Receive and generate ack
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);
@ -168,7 +168,7 @@ fn cc_cong_avoidance_recovery_period_unchanged() {
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
client.process_input(&s_ack, now);
client.process_input(s_ack, now);
// cwnd should not have changed since ACKed packets were sent before
// recovery period expired
@ -198,12 +198,12 @@ fn single_packet_on_recovery() {
// Acknowledge just one packet and cause one packet to be declared lost.
// 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());
// The client should see the loss and enter recovery.
// As there are many outstanding packets, there should be no available cwnd.
client.process_input(&ack.unwrap(), now);
client.process_input(ack.unwrap(), now);
assert_eq!(cwnd_avail(&client), 0);
// 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
now += DEFAULT_RTT / 2;
client.process_input(&s_ack, now);
client.process_input(s_ack, now);
// Should be in CARP now.
now += DEFAULT_RTT / 2;
@ -251,7 +251,7 @@ fn cc_cong_avoidance_recovery_period_to_cong_avoidance() {
for i in 0..5 {
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!(
"client sending {} bytes into cwnd of {}",
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 s_ack = ack_bytes(&mut server, stream_id, c_tx_dgrams.drain(..most), now);
assert_eq!(cwnd(&client), expected_cwnd);
client.process_input(&s_ack, now);
client.process_input(s_ack, now);
// make sure to fill cwnd again.
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
now = next_now;
@ -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);
assert_eq!(cwnd(&client), expected_cwnd);
client.process_input(&s_ack, now);
client.process_input(s_ack, now);
// make sure to fill cwnd again.
let (mut new_pkts, next_now) = fill_cwnd(&mut client, stream_id, now);
now = next_now;
@ -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);
now += Duration::from_millis(100);
client.process_input(&s_ack, now);
client.process_input(s_ack, now);
// send bytes that will be lost
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)
// 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.
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();
assert_eq!(other_stream, 1);
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.
// Now the server sends a packet that will force an ACK,
// because the client will detect a gap.
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());
// The client can ack the server packet even if cc windows is full.
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());
qdebug!([server], "Handle 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);
}

View File

@ -41,7 +41,7 @@ fn connection_close() {
client.close(now, 42, "");
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;
assert_eq!(
stats_after.connection_close,
@ -49,7 +49,7 @@ fn connection_close() {
);
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));
}
@ -65,7 +65,7 @@ fn connection_close_with_long_reason_string() {
client.close(now, 42, long_reason);
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;
assert_eq!(
stats_after.connection_close,
@ -73,7 +73,7 @@ fn connection_close_with_long_reason_string() {
);
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));
}
@ -84,17 +84,17 @@ fn early_application_close() {
let mut server = default_server();
// One flight each.
let dgram = client.process(None, now()).dgram();
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
let dgram = server.process(dgram.as_ref(), now()).dgram();
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_some());
server.close(now(), 77, String::new());
assert!(server.state().closed());
let dgram = server.process(None, now()).dgram();
let dgram = server.process_output(now()).dgram();
assert!(dgram.is_some());
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
assert_draining(&client, &Error::PeerError(ERROR_APPLICATION_CLOSE));
}
@ -109,15 +109,15 @@ fn bad_tls_version() {
.unwrap();
let mut server = default_server();
let dgram = client.process(None, now()).dgram();
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
let dgram = server.process(dgram.as_ref(), now()).dgram();
let dgram = server.process(dgram, now()).dgram();
assert_eq!(
*server.state(),
State::Closed(CloseReason::Transport(Error::ProtocolViolation))
);
assert!(dgram.is_some());
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
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.
let _p1 = 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.
// 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));
now += cb;
// Rather than let the timer pop, close the connection.
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());
// This should now report the end of the closing period, not a
// 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));
}
@ -164,20 +164,20 @@ fn closing_and_draining() {
// Close the connection.
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());
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));
// The client will spit out the same packet in response to anything it receives.
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!(
client_close.as_ref().unwrap().len(),
client_close2.as_ref().unwrap().len()
);
// 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!(
*client.state(),
@ -185,17 +185,17 @@ fn closing_and_draining() {
);
// 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_close.is_some());
// .. 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));
// 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);
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!(
*server.state(),
@ -218,6 +218,6 @@ fn stateless_reset_client() {
.unwrap();
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);
}

View File

@ -93,7 +93,7 @@ fn datagram_enabled_on_client() {
let out = server.process_output(now()).dgram().unwrap();
assert_eq!(server.stats().frame_tx.datagram, dgram_sent + 1);
client.process_input(&out, now());
client.process_input(out, now());
assert!(matches!(
client.next_event().unwrap(),
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();
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
server.process_input(&out, now());
server.process_input(out, now());
assert!(matches!(
server.next_event().unwrap(),
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);
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);
let now = now() + AT_LEAST_PTO;
// Ack should be sent
@ -253,7 +253,7 @@ fn datagram_acked() {
ConnectionEvent::Datagram(data) if data == DATA_SMALLER_THAN_MTU
));
client.process_input(&out.unwrap(), now);
client.process_input(out.unwrap(), now);
assert!(matches!(
client.next_event().unwrap(),
ConnectionEvent::OutgoingDatagramOutcome { id, outcome } if id == 1 && outcome == OutgoingDatagramOutcome::Acked
@ -265,7 +265,7 @@ fn send_packet_and_get_server_event(
server: &mut Connection,
) -> ConnectionEvent {
let out = client.process_output(now()).dgram();
server.process_input(&out.unwrap(), now());
server.process_input(out.unwrap(), now());
let mut events: Vec<_> = server
.events()
.filter_map(|evt| match evt {
@ -404,7 +404,7 @@ fn dgram_no_allowed() {
.test_write_frames(InsertDatagram { data: DATA_MTU }, now())
.dgram()
.unwrap();
client.process_input(&out, now());
client.process_input(out, now());
assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation));
}
@ -420,7 +420,7 @@ fn dgram_too_big() {
.test_write_frames(InsertDatagram { data: DATA_MTU }, now())
.dgram()
.unwrap();
client.process_input(&out, now());
client.process_input(out, now());
assert_error(&client, &CloseReason::Transport(Error::ProtocolViolation));
}
@ -455,7 +455,7 @@ fn outgoing_datagram_queue_full() {
// Send DATA_SMALLER_THAN_MTU_2 datagram
let out = client.process_output(now()).dgram();
assert_eq!(client.stats().frame_tx.datagram, dgram_sent + 1);
server.process_input(&out.unwrap(), now());
server.process_input(out.unwrap(), now());
assert!(matches!(
server.next_event().unwrap(),
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 out = client.process_output(now()).dgram();
assert_eq!(client.stats().frame_tx.datagram, dgram_sent2 + 1);
server.process_input(&out.unwrap(), now());
server.process_input(out.unwrap(), now());
assert!(matches!(
server.next_event().unwrap(),
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);
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);
}
@ -593,7 +593,7 @@ fn multiple_quic_datagrams_in_one_packet() {
let out = client.process_output(now()).dgram();
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(..));
assert_eq!(server.events().filter(datagram).count(), 2);
}

View File

@ -14,9 +14,10 @@ use test_fixture::{
use crate::{
connection::tests::{
connect_force_idle, connect_force_idle_with_modifier, default_client, default_server,
handshake_with_modifier, migration::get_cid, new_client, new_server, send_and_receive,
send_something, send_something_with_modifier, send_with_modifier_and_receive, DEFAULT_RTT,
assert_path_challenge_min_len, connect_force_idle, connect_force_idle_with_modifier,
default_client, default_server, handshake_with_modifier, migration::get_cid, new_client,
new_server, send_and_receive, send_something, send_something_with_modifier,
send_with_modifier_and_receive, DEFAULT_RTT,
},
ecn::ECN_TEST_COUNT,
path::MAX_PATH_PROBES,
@ -120,6 +121,7 @@ fn migration_delay_to_ecn_blackhole() {
// This should be a PATH_CHALLENGE.
probes += 1;
assert_eq!(client.stats().frame_tx.path_challenge, probes);
assert_path_challenge_min_len(&client, &d, now);
if probes <= MAX_PATH_PROBES {
// The first probes should be sent with ECN.
assert_ecn_enabled(d.tos());
@ -143,12 +145,12 @@ fn stats() {
for _ in 0..ECN_TEST_COUNT {
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 {
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()] {
@ -194,7 +196,7 @@ fn disables_on_remark() {
for _ in 0..ECN_TEST_COUNT {
if let Some(ack) = send_with_modifier_and_receive(&mut client, &mut server, now, remark()) {
client.process_input(&ack, now);
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.
let client_pkt = send_something(&mut client, now);
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.
for _ in 0..burst {
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() {
client.process_input(&ack, now);
client.process_input(ack, now);
}
let client_pkt = send_something(&mut client, now);
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
.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());
if let Some(probe) = probe {
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);
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_eq!(server.stats().frame_tx.path_response, 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.
let client_data = send_something_with_modifier(&mut client, now, orig_path_modifier);
assert_ne!(get_cid(&client_data), probe_cid);
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);
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.
client.process_input(&resp, now);
client.process_input(resp, now);
assert_eq!(client.stats().frame_rx.path_challenge, 1);
migrated = true;
@ -276,7 +280,7 @@ pub fn migration_with_modifiers(
// 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
// 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;
@ -287,6 +291,10 @@ pub fn migration_with_modifiers(
server.stats().frame_tx.path_challenge,
if migrated { 2 } else { 0 }
);
if migrated {
assert_path_challenge_min_len(&server, &probe_old_server, now);
}
assert_eq!(
server.stats().frame_tx.stream,
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);
// The client receives these checks and responds to the probe, but uses the new path.
client.process_input(&migrate_server, now);
client.process_input(&probe_old_server, now);
client.process_input(migrate_server, now);
client.process_input(probe_old_server, now);
let old_probe_resp = send_something_with_modifier(&mut client, now, new_path_modifier);
assert_v6_path(&old_probe_resp, true);
let client_confirmation = client.process_output(now).dgram().unwrap();
@ -315,17 +323,17 @@ pub fn migration_with_modifiers(
let server_confirmation =
send_something_with_modifier(&mut server, now + server_pacing, new_path_modifier);
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.
for _ in 0..burst {
now += client.process_output(now).callback();
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() {
client.process_input(&ack, now);
client.process_input(ack, now);
}
}

View File

@ -48,37 +48,37 @@ const ECH_PUBLIC_NAME: &str = "public.example";
fn full_handshake(pmtud: bool) {
qdebug!("---- client: generate CH");
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_eq!(out.as_dgram_ref().unwrap().len(), client.plpmtu());
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
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_eq!(out.as_dgram_ref().unwrap().len(), server.plpmtu());
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());
let out = server.process(out.as_dgram_ref(), now());
let out = server.process(out.dgram(), now());
assert!(out.as_dgram_ref().is_none());
assert!(maybe_authenticate(&mut client));
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_eq!(*client.state(), State::Connected);
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_eq!(*server.state(), State::Confirmed);
qdebug!("---- client: ACKS -> 0");
let out = client.process(out.as_dgram_ref(), now());
let out = client.process(out.dgram(), now());
if pmtud {
// PMTUD causes a PING probe to be sent here
let pkt = out.dgram().unwrap();
@ -103,19 +103,19 @@ fn handshake_pmtud() {
fn handshake_failed_authentication() {
qdebug!("---- client: generate CH");
let mut client = default_client();
let out = client.process(None, now());
let out = client.process_output(now());
assert!(out.as_dgram_ref().is_some());
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
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());
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());
let out = server.process(out.as_dgram_ref(), now());
let out = server.process(out.dgram(), now());
assert!(out.as_dgram_ref().is_none());
let authentication_needed = |e| matches!(e, ConnectionEvent::AuthenticationNeeded);
@ -124,11 +124,11 @@ fn handshake_failed_authentication() {
client.authenticated(AuthenticationStatus::CertRevoked, now());
qdebug!("---- client: -> Alert(certificate_revoked)");
let out = client.process(None, now());
let out = client.process_output(now());
assert!(out.as_dgram_ref().is_some());
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_error(&client, &CloseReason::Transport(Error::CryptoAlert(44)));
assert_error(&server, &CloseReason::Transport(Error::PeerError(300)));
@ -160,29 +160,29 @@ fn no_alpn() {
fn dup_server_flight1() {
qdebug!("---- client: generate CH");
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_eq!(out.as_dgram_ref().unwrap().len(), client.plpmtu());
qdebug!("Output={:0x?}", out.as_dgram_ref());
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
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());
qdebug!("Output={:0x?}", out_to_rep.as_dgram_ref());
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());
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!(maybe_authenticate(&mut client));
qdebug!("---- client: SH..FIN -> FIN");
let out = client.process(None, now());
let out = client.process_output(now());
assert!(out.as_dgram_ref().is_some());
qdebug!("Output={:0x?}", out.as_dgram_ref());
@ -191,7 +191,7 @@ fn dup_server_flight1() {
assert_eq!(1, client.stats().dropped_rx);
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());
qdebug!("Output={:0x?}", out.as_dgram_ref());
@ -216,17 +216,17 @@ fn crypto_frame_split() {
)
.expect("create a server");
let client1 = client.process(None, now());
let client1 = client.process_output(now());
assert!(client1.as_dgram_ref().is_some());
// The entire server flight doesn't fit in a single packet because the
// certificate is large, therefore the server will produce 2 packets.
let server1 = server.process(client1.as_dgram_ref(), now());
let server1 = server.process(client1.dgram(), now());
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());
let client2 = client.process(server1.as_dgram_ref(), now());
let client2 = client.process(server1.dgram(), now());
// This is an ack.
assert!(client2.as_dgram_ref().is_some());
// 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);
// 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());
// 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.
let auth2 = maybe_authenticate(&mut client);
@ -247,13 +247,13 @@ fn crypto_frame_split() {
// Now client has all data to finish handshake.
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
// after the first or second server packet.
assert!(client3.as_dgram_ref().is_some() ^ client4.as_dgram_ref().is_some());
mem::drop(server.process(client3.as_dgram_ref(), now()));
mem::drop(server.process(client4.as_dgram_ref(), now()));
mem::drop(server.process(client3.dgram(), now()));
mem::drop(server.process(client4.dgram(), now()));
assert_eq!(*client.state(), State::Connected);
assert_eq!(*server.state(), State::Confirmed);
@ -283,21 +283,21 @@ fn send_05rtt() {
let mut client = default_client();
let mut server = default_server();
let c1 = client.process(None, now()).dgram();
let c1 = client.process_output(now()).dgram();
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());
// The server should accept writes at this point.
let s2 = send_something(&mut server, now());
// Complete the handshake at the client.
client.process_input(&s1, now());
client.process_input(s1, now());
maybe_authenticate(&mut client);
assert_eq!(*client.state(), State::Connected);
// 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 stream_id = client
.events()
@ -320,21 +320,21 @@ fn reorder_05rtt() {
let mut client = default_client();
let mut server = default_server();
let c1 = client.process(None, now()).dgram();
let c1 = client.process_output(now()).dgram();
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.
let s2 = send_something(&mut server, now());
// We can't use the standard facility to complete the handshake, so
// drive it as aggressively as possible.
client.process_input(&s2, now());
client.process_input(s2, now());
assert_eq!(client.stats().saved_datagrams, 1);
// After processing the first packet, the client should go back and
// 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.
client.authenticated(AuthenticationStatus::Ok, now());
assert_eq!(*client.state(), State::Connected);
@ -372,7 +372,7 @@ fn reorder_05rtt_with_0rtt() {
server.send_ticket(now, &[]).unwrap();
let ticket = server.process_output(now).dgram().unwrap();
now += RTT / 2;
client.process_input(&ticket, now);
client.process_input(ticket, now);
let token = get_tokens(&mut client).pop().unwrap();
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.
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.
server.process_input(&c2, now);
server.process_input(c2, now);
let s2 = send_something(&mut server, now);
// Save the 0.5 RTT.
now += RTT / 2;
client.process_input(&s2, now);
client.process_input(s2, now);
assert_eq!(client.stats().saved_datagrams, 1);
// Now PTO at the client and cause the server to re-send handshake packets.
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());
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.
// This should contain an ACK, so we are processing an ACK from the past.
now += RTT / 2;
client.process_input(&s3, now);
client.process_input(s3, now);
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.paths.rtt(), RTT);
now += RTT / 2;
server.process_input(&c4.unwrap(), now);
server.process_input(c4.unwrap(), now);
assert_eq!(*server.state(), State::Confirmed);
// Don't check server RTT as it will be massively inflated by a
// 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.
// 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());
now += RTT / 2;
let s1 = server.process(c1.as_ref(), now).dgram();
let s1 = server.process(c1, now).dgram();
assert!(s1.is_some());
// Drop the server flight. Then send some data.
@ -450,10 +450,10 @@ fn coalesce_05rtt() {
// The server should then send its entire flight again,
// including the application data, which it sends in a 1-RTT packet.
now += AT_LEAST_PTO;
let c2 = client.process(None, now).dgram();
let c2 = client.process_output(now).dgram();
assert!(c2.is_some());
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
// flight should be padded to full size.
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.
now += RTT / 2;
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.
assert_eq!(client.stats().dropped_rx, 0);
assert_eq!(client.stats().packets_rx, 3);
@ -470,7 +470,7 @@ fn coalesce_05rtt() {
// After (successful) authentication, the packet is processed.
maybe_authenticate(&mut client);
let c3 = client.process(None, now).dgram();
let c3 = client.process_output(now).dgram();
assert!(c3.is_some());
assert_eq!(client.stats().dropped_rx, 0); // No Initial padding.
assert_eq!(client.stats().packets_rx, 4);
@ -479,11 +479,11 @@ fn coalesce_05rtt() {
// Allow the handshake to complete.
now += RTT / 2;
let s3 = server.process(c3.as_ref(), now).dgram();
let s3 = server.process(c3, now).dgram();
assert!(s3.is_some());
assert_eq!(*server.state(), State::Confirmed);
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.stats().dropped_rx, 0); // No dropped packets.
@ -496,11 +496,11 @@ fn reorder_handshake() {
let mut server = default_server();
let mut now = now();
let c1 = client.process(None, now).dgram();
let c1 = client.process_output(now).dgram();
assert!(c1.is_some());
now += RTT / 2;
let s1 = server.process(c1.as_ref(), now).dgram();
let s1 = server.process(c1, now).dgram();
assert!(s1.is_some());
// 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.
// It can only send another Initial packet.
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);
assert_eq!(client.stats().saved_datagrams, 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
// a second client Initial packet to cause it to send again.
now += AT_LEAST_PTO;
let c2 = client.process(None, now).dgram();
let c2 = client.process_output(now).dgram();
now += RTT / 2;
let s2 = server.process(c2.as_ref(), now).dgram();
let s2 = server.process(c2, now).dgram();
assert!(s2.is_some());
let (s_init, s_hs) = split_datagram(&s2.unwrap());
@ -529,28 +529,28 @@ fn reorder_handshake() {
// Processing the Handshake packet first should save it.
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().packets_rx, 2);
client.process_input(&s_init, now);
client.process_input(s_init, now);
// Each saved packet should now be "received" again.
assert_eq!(client.stats().packets_rx, 7);
maybe_authenticate(&mut client);
let c3 = client.process(None, now).dgram();
let c3 = client.process_output(now).dgram();
assert!(c3.is_some());
// Note that though packets were saved and processed very late,
// they don't cause the RTT to change.
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);
// Don't check server RTT estimate as it will be inflated due to
// it making a guess based on retransmissions when it dropped
// the Initial packet number space.
now += RTT / 2;
client.process_input(&s3.unwrap(), now);
client.process_input(s3.unwrap(), now);
assert_eq!(*client.state(), State::Confirmed);
assert_eq!(client.paths.rtt(), RTT);
}
@ -563,24 +563,24 @@ fn reorder_1rtt() {
let mut server = default_server();
let mut now = now();
let c1 = client.process(None, now).dgram();
let c1 = client.process_output(now).dgram();
assert!(c1.is_some());
now += RTT / 2;
let s1 = server.process(c1.as_ref(), now).dgram();
let s1 = server.process(c1, now).dgram();
assert!(s1.is_some());
now += RTT / 2;
client.process_input(&s1.unwrap(), now);
client.process_input(s1.unwrap(), now);
maybe_authenticate(&mut client);
let c2 = client.process(None, now).dgram();
let c2 = client.process_output(now).dgram();
assert!(c2.is_some());
// Now get a bunch of packets from the client.
// Give them to the server before giving it `c2`.
for _ in 0..PACKETS {
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 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);
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 two additional are a Handshake and a 1-RTT (w/ NEW_CONNECTION_ID).
assert_eq!(server.stats().packets_rx, PACKETS * 2 + 4);
@ -599,7 +599,7 @@ fn reorder_1rtt() {
assert_eq!(server.paths.rtt(), RTT);
now += RTT / 2;
client.process_input(&s2.unwrap(), now);
client.process_input(s2.unwrap(), now);
assert_eq!(client.paths.rtt(), RTT);
// All the stream data that was sent should now be available.
@ -627,7 +627,7 @@ fn reorder_1rtt() {
fn corrupted_initial() {
let mut client = default_client();
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[..]);
// Find the last non-zero value and corrupt that.
let (idx, _) = corrupted
@ -638,7 +638,7 @@ fn corrupted_initial() {
.unwrap();
corrupted[idx] ^= 0x76;
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 first should be dropped, the second saved.
assert_eq!(server.stats().packets_rx, 2);
@ -655,14 +655,14 @@ fn verify_pkt_honors_mtu() {
let now = now();
let res = client.process(None, now);
let res = client.process_output(now);
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
assert_eq!(res, Output::Callback(idle_timeout));
// Try to send a large stream and verify first packet is correctly sized
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
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_eq!(pkt0.as_dgram_ref().unwrap().len(), client.plpmtu());
}
@ -673,10 +673,10 @@ fn extra_initial_hs() {
let mut server = default_server();
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());
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());
now += DEFAULT_RTT / 2;
@ -688,28 +688,28 @@ fn extra_initial_hs() {
// Do that EXTRA_INITIALS times and each time the client will emit
// another Initial packet.
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);
now += DEFAULT_RTT / 10;
}
// 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());
// Until PTO, where another Initial can be used to complete the handshake.
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);
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;
client.process_input(&s_init.unwrap(), now);
client.process_input(s_init.unwrap(), now);
maybe_authenticate(&mut client);
let c_fin = client.process_output(now).dgram();
assert_eq!(*client.state(), State::Connected);
now += DEFAULT_RTT / 2;
server.process_input(&c_fin.unwrap(), now);
server.process_input(c_fin.unwrap(), now);
assert_eq!(*server.state(), State::Confirmed);
}
@ -719,10 +719,10 @@ fn extra_initial_invalid_cid() {
let mut server = default_server();
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());
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());
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.
copy[6] ^= 0xc4;
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());
}
@ -783,7 +783,7 @@ fn anti_amplification() {
let c_init = client.process_output(now).dgram();
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());
let s_init2 = server.process_output(now).dgram().unwrap();
assert_eq!(s_init2.len(), server.plpmtu());
@ -795,11 +795,11 @@ fn anti_amplification() {
assert_eq!(cb, server.conn_params.get_idle_timeout());
now += DEFAULT_RTT / 2;
client.process_input(&s_init1, now);
client.process_input(&s_init2, now);
client.process_input(s_init1, now);
client.process_input(s_init2, now);
let ack_count = client.stats().frame_tx.ack;
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.
// 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).
now += DEFAULT_RTT / 2;
let remainder = server.process(Some(&ack), now).dgram();
let remainder = server.process(Some(ack), now).dgram();
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.
let fin = client.process_output(now).dgram();
assert_eq!(*client.state(), State::Connected);
now += DEFAULT_RTT / 2;
server.process_input(&fin.unwrap(), now);
server.process_input(fin.unwrap(), now);
assert_eq!(*server.state(), State::Confirmed);
}
@ -833,17 +833,17 @@ fn garbage_initial() {
corrupted.push(initial[initial.len() - 1] ^ 0xb7);
corrupted.extend_from_slice(rest.as_ref().map_or(&[], |r| &r[..]));
let garbage = datagram(corrupted);
assert_eq!(Output::None, server.process(Some(&garbage), now()));
assert_eq!(Output::None, server.process(Some(garbage), now()));
}
#[test]
fn drop_initial_packet_from_wrong_address() {
let mut client = default_client();
let out = client.process(None, now());
let out = client.process_output(now());
assert!(out.as_dgram_ref().is_some());
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());
let p = out.dgram().unwrap();
@ -854,24 +854,24 @@ fn drop_initial_packet_from_wrong_address() {
&p[..],
);
let out = client.process(Some(&dgram), now());
let out = client.process(Some(dgram), now());
assert!(out.as_dgram_ref().is_none());
}
#[test]
fn drop_handshake_packet_from_wrong_address() {
let mut client = default_client();
let out = client.process(None, now());
let out = client.process_output(now());
assert!(out.as_dgram_ref().is_some());
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());
let (s_in, s_hs) = split_datagram(&out.dgram().unwrap());
// 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 dgram = Datagram::new(
@ -881,7 +881,7 @@ fn drop_handshake_packet_from_wrong_address() {
&p[..],
);
let out = client.process(Some(&dgram), now());
let out = client.process(Some(dgram), now());
assert!(out.as_dgram_ref().is_none());
}
@ -930,8 +930,8 @@ fn ech_retry() {
.unwrap();
let dgram = client.process_output(now()).dgram();
let dgram = server.process(dgram.as_ref(), now()).dgram();
client.process_input(&dgram.unwrap(), now());
let dgram = server.process(dgram, now()).dgram();
client.process_input(dgram.unwrap(), now());
let auth_event = ConnectionEvent::EchFallbackAuthenticationNeeded {
public_name: String::from(ECH_PUBLIC_NAME),
};
@ -941,7 +941,7 @@ fn ech_retry() {
// Tell the server about the error.
let dgram = client.process_output(now()).dgram();
server.process_input(&dgram.unwrap(), now());
server.process_input(dgram.unwrap(), now());
assert_eq!(
server.state().error(),
Some(&CloseReason::Transport(Error::PeerError(0x100 + 121)))
@ -985,8 +985,8 @@ fn ech_retry_fallback_rejected() {
.unwrap();
let dgram = client.process_output(now()).dgram();
let dgram = server.process(dgram.as_ref(), now()).dgram();
client.process_input(&dgram.unwrap(), now());
let dgram = server.process(dgram, now()).dgram();
client.process_input(dgram.unwrap(), now());
let auth_event = ConnectionEvent::EchFallbackAuthenticationNeeded {
public_name: String::from(ECH_PUBLIC_NAME),
};
@ -1000,7 +1000,7 @@ fn ech_retry_fallback_rejected() {
// Pass the error on.
let dgram = client.process_output(now()).dgram();
server.process_input(&dgram.unwrap(), now());
server.process_input(dgram.unwrap(), now());
assert_eq!(
server.state().error(),
Some(&CloseReason::Transport(Error::PeerError(298)))
@ -1018,13 +1018,13 @@ fn bad_min_ack_delay() {
let mut client = default_client();
let dgram = client.process_output(now()).dgram();
let dgram = server.process(dgram.as_ref(), now()).dgram();
client.process_input(&dgram.unwrap(), now());
let dgram = server.process(dgram, now()).dgram();
client.process_input(dgram.unwrap(), now());
client.authenticated(AuthenticationStatus::Ok, now());
assert_eq!(client.state().error(), Some(&EXPECTED_ERROR));
let dgram = client.process_output(now()).dgram();
server.process_input(&dgram.unwrap(), now());
server.process_input(dgram.unwrap(), now());
assert_eq!(
server.state().error(),
Some(&CloseReason::Transport(Error::PeerError(
@ -1044,7 +1044,7 @@ fn only_server_initial() {
let client_dgram = client.process_output(now).dgram();
// 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();
// 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.
// It sends a Handshake probe instead, containing just a PING frame.
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());
assert_eq!(client.stats().dropped_rx, 0);
assert_eq!(client.stats().frame_tx.ping, 1);
@ -1066,17 +1066,17 @@ fn only_server_initial() {
now += AT_LEAST_PTO;
assert_eq!(client.stats().frame_tx.ping, 1);
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());
assert_eq!(client.stats().frame_tx.ping, 2);
assert_eq!(client.stats().dropped_rx, discarded + 1);
// Pass the Handshake packet and complete the handshake.
client.process_input(&handshake.unwrap(), now);
client.process_input(handshake.unwrap(), now);
maybe_authenticate(&mut client);
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram.as_ref(), now).dgram();
client.process_input(&dgram.unwrap(), now);
let dgram = server.process(dgram, now).dgram();
client.process_input(dgram.unwrap(), now);
assert_eq!(*client.state(), State::Confirmed);
assert_eq!(*server.state(), State::Confirmed);
@ -1102,25 +1102,25 @@ fn no_extra_probes_after_confirmed() {
// Finally, run the handshake.
now += AT_LEAST_PTO * 2;
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
// 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());
client.process_input(&dgram.unwrap(), now);
client.process_input(dgram.unwrap(), now);
maybe_authenticate(&mut client);
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram.as_ref(), now).dgram();
client.process_input(&dgram.unwrap(), now);
let dgram = server.process(dgram, now).dgram();
client.process_input(dgram.unwrap(), now);
assert_eq!(*client.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());
let probe = client.process(spare_handshake.as_ref(), now).dgram();
let probe = client.process(spare_handshake, now).dgram();
assert!(probe.is_none());
}
@ -1133,12 +1133,12 @@ fn implicit_rtt_server() {
let dgram = client.process_output(now).dgram();
now += RTT / 2;
let dgram = server.process(dgram.as_ref(), now).dgram();
let dgram = server.process(dgram, now).dgram();
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());
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
// an RTT estimate from having discarded the Initial packet number space.
@ -1157,14 +1157,14 @@ fn emit_authentication_needed_once() {
)
.expect("create a server");
let client1 = client.process(None, now());
let client1 = client.process_output(now());
assert!(client1.as_dgram_ref().is_some());
// The entire server flight doesn't fit in a single packet because the
// certificate is large, therefore the server will produce 2 packets.
let server1 = server.process(client1.as_dgram_ref(), now());
let server1 = server.process(client1.dgram(), now());
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());
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
// also fit in the same packet. Our default test setup achieves this, but
// 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!(client.peer_certificate().is_some());
@ -1192,7 +1192,7 @@ fn emit_authentication_needed_once() {
// `Connection::authenticated`. On receiving the second packet from the
// server, the client must not emit a another
// `ConnectionEvent::AuthenticationNeeded`.
_ = client.process(server2.as_dgram_ref(), now());
_ = client.process(server2.dgram(), now());
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
// retranmissions are identical to the original. Also, verify the PTO durations.
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!(
client.stats().frame_tx,
@ -1213,7 +1213,7 @@ fn client_initial_retransmits_identical() {
..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)));
now += pto;
}
@ -1223,14 +1223,14 @@ fn client_initial_retransmits_identical() {
fn server_initial_retransmits_identical() {
let mut now = now();
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
// retranmissions are identical to the original. Also, verify the PTO durations.
let mut server = default_server();
let mut total_ptos: Duration = Duration::from_secs(0);
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!(
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 {
assert_eq!(pto, DEFAULT_RTT * 3 * (1 << (i - 1)));
} else {

View File

@ -40,17 +40,14 @@ fn test_idle_timeout(client: &mut Connection, server: &mut Connection, timeout:
let now = now();
let res = client.process(None, now);
let res = client.process_output(now);
assert_eq!(res, Output::Callback(timeout));
// Still connected after timeout-1 seconds. Idle timer not reset
mem::drop(client.process(
None,
now + timeout.checked_sub(Duration::from_secs(1)).unwrap(),
));
mem::drop(client.process_output(now + timeout.checked_sub(Duration::from_secs(1)).unwrap()));
assert!(matches!(client.state(), State::Confirmed));
mem::drop(client.process(None, now + timeout));
mem::drop(client.process_output(now + timeout));
// Not connected after timeout.
assert!(matches!(client.state(), State::Closed(_)));
@ -112,19 +109,19 @@ fn asymmetric_idle_timeout() {
connect(&mut client, &mut server);
let c1 = send_something(&mut client, now());
let c2 = send_something(&mut client, now());
server.process_input(&c2, now());
server.process_input(&c1, now());
server.process_input(c2, now());
server.process_input(c1, now());
let s1 = send_something(&mut server, now());
let s2 = send_something(&mut server, now());
client.process_input(&s2, now());
let ack = client.process(Some(&s1), now()).dgram();
client.process_input(s2, now());
let ack = client.process(Some(s1), now()).dgram();
assert!(ack.is_some());
// Now both should have received ACK frames so should be idle.
assert_eq!(server.process(ack, now()), Output::Callback(LOWER_TIMEOUT));
assert_eq!(
server.process(ack.as_ref(), now()),
client.process_output(now()),
Output::Callback(LOWER_TIMEOUT)
);
assert_eq!(client.process(None, now()), Output::Callback(LOWER_TIMEOUT));
}
#[test]
@ -152,17 +149,17 @@ fn tiny_idle_timeout() {
let c1 = send_something(&mut client, now);
let c2 = send_something(&mut client, now);
now += RTT / 2;
server.process_input(&c2, now);
server.process_input(&c1, now);
server.process_input(c2, now);
server.process_input(c1, now);
let s1 = send_something(&mut server, now);
let s2 = send_something(&mut server, now);
now += RTT / 2;
client.process_input(&s2, now);
let ack = client.process(Some(&s1), now).dgram();
client.process_input(s2, now);
let ack = client.process(Some(s1), now).dgram();
assert!(ack.is_some());
// 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);
} else {
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.
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);
} else {
panic!("Client not idle");
@ -186,7 +183,7 @@ fn idle_send_packet1() {
let mut now = now();
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());
now += Duration::from_secs(10);
@ -196,13 +193,13 @@ fn idle_send_packet1() {
// Still connected after 39 seconds because idle timer reset by the
// outgoing packet.
now += default_timeout() - DELTA;
let dgram = client.process(None, now).dgram();
let dgram = client.process_output(now).dgram();
assert!(dgram.is_some()); // PTO
assert!(client.state().connected());
// Not connected after 40 seconds.
now += DELTA;
let out = client.process(None, now);
let out = client.process_output(now);
assert!(matches!(out, Output::None));
assert!(client.state().closed());
}
@ -218,7 +215,7 @@ fn idle_send_packet2() {
let mut now = now();
let timeout = client.process(None, now).callback();
let timeout = client.process_output(now).callback();
assert_eq!(timeout, default_timeout());
// First transmission at t=GAP.
@ -231,14 +228,14 @@ fn idle_send_packet2() {
// Still connected just before GAP + default_timeout().
now += default_timeout() - DELTA;
let dgram = client.process(None, now).dgram();
let dgram = client.process_output(now).dgram();
assert!(dgram.is_some()); // PTO
assert!(matches!(client.state(), State::Confirmed));
// Not connected after 40 seconds because timer not reset by second
// outgoing packet
now += DELTA;
let out = client.process(None, now);
let out = client.process_output(now);
assert!(matches!(out, Output::None));
assert!(matches!(client.state(), State::Closed(_)));
}
@ -253,7 +250,7 @@ fn idle_recv_packet() {
let mut now = now();
let res = client.process(None, now);
let res = client.process_output(now);
assert_eq!(res, Output::Callback(default_timeout()));
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.
// Otherwise, the eventual timeout will be extended (and we're not testing that).
now += Duration::from_secs(10);
let out = client.process(None, now);
server.process_input(&out.dgram().unwrap(), now);
let out = client.process_output(now);
server.process_input(out.dgram().unwrap(), now);
assert_eq!(server.stream_send(stream, b"world").unwrap(), 5);
let out = server.process_output(now);
assert_ne!(out.as_dgram_ref(), None);
mem::drop(client.process(out.as_dgram_ref(), now));
mem::drop(client.process(out.dgram(), now));
assert!(matches!(client.state(), State::Confirmed));
// Add a little less than the idle timeout and we're still connected.
now += default_timeout() - FUDGE;
mem::drop(client.process(None, now));
mem::drop(client.process_output(now));
assert!(matches!(client.state(), State::Confirmed));
now += FUDGE;
mem::drop(client.process(None, now));
mem::drop(client.process_output(now));
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.
// The client then caches the Handshake packet.
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());
client.process_input(&handshake.unwrap(), start);
client.process_input(handshake.unwrap(), start);
// Perform an exchange and keep the connection alive.
let middle = start + AT_LEAST_PTO;
@ -309,7 +306,7 @@ fn idle_caching() {
mem::drop(server.process_output(middle).dgram());
// Now let the server process the RTX'ed client Initial. This causes the server
// to send CRYPTO frames again, so manually extract and discard those.
server.process_input(&dgram.unwrap(), middle);
server.process_input(dgram.unwrap(), middle);
let mut tokens = Vec::new();
server.crypto.streams.write_frame(
PacketNumberSpace::Initial,
@ -333,7 +330,7 @@ fn idle_caching() {
let (initial, _) = split_datagram(&dgram.unwrap());
let crypto_before_c = client.stats().frame_rx.crypto;
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.ack, ack_before + 1);
@ -342,11 +339,11 @@ fn idle_caching() {
let dgram = server.process_output(end).dgram();
let (initial, _) = split_datagram(&dgram.unwrap());
neqo_common::qwarn!("client ingests initial, finally");
mem::drop(client.process(Some(&initial), end));
mem::drop(client.process(Some(initial), end));
maybe_authenticate(&mut client);
let dgram = client.process_output(end).dgram();
let dgram = server.process(dgram.as_ref(), end).dgram();
client.process_input(&dgram.unwrap(), end);
let dgram = server.process(dgram, end).dgram();
client.process_input(dgram.unwrap(), end);
assert_eq!(*client.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();
let req = initiator.process_output(now).dgram();
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.
_ = responder.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
@ -384,15 +381,15 @@ fn create_stream_idle_rtt(
let resp2 = responder.process_output(now).dgram();
now += rtt / 2;
initiator.process_input(&resp2.unwrap(), now);
initiator.process_input(&resp1.unwrap(), now);
initiator.process_input(resp2.unwrap(), now);
initiator.process_input(resp1.unwrap(), now);
let ack = initiator.process_output(now).dgram();
assert!(ack.is_some());
check_idle(initiator, now);
// Receiving the ACK should return the responder to idle too.
now += rtt / 2;
responder.process_input(&ack.unwrap(), now);
responder.process_input(ack.unwrap(), now);
check_idle(responder, now);
(now, stream)
@ -428,9 +425,9 @@ fn keep_alive_initiator() {
assert_eq!(server.stats().frame_tx.ping, pings_before + 1);
// Exchange ack for the PING.
let out = client.process(ping.as_ref(), now).dgram();
let out = server.process(out.as_ref(), now).dgram();
assert!(client.process(out.as_ref(), now).dgram().is_none());
let out = client.process(ping, now).dgram();
let out = server.process(out, now).dgram();
assert!(client.process(out, now).dgram().is_none());
// Check that there will be next keep-alive ping after 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);
// 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);
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
// 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) {
let dgram = sender.process_output(now()).dgram();
let chaff = send_something(sender, now());
receiver.process_input(&chaff, now());
receiver.process_input(&dgram.unwrap(), now());
receiver.process_input(chaff, now());
receiver.process_input(dgram.unwrap(), now());
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.
@ -598,7 +595,7 @@ fn keep_alive_stop_sending() {
// The server will have sent RESET_STREAM, which the client will
// want to acknowledge, so force that out.
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());
// Now the client should be idle.
@ -661,7 +658,7 @@ fn keep_alive_uni() {
_ = client.stream_send(stream, DEFAULT_STREAM_DATA).unwrap();
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();
}

View File

@ -33,7 +33,7 @@ fn check_discarded(
mem::drop(peer.process_output(now()));
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);
let after = peer.stats();
assert_eq!(dropped, after.dropped_rx - before.dropped_rx);
@ -57,17 +57,17 @@ fn overwrite_invocations(n: PacketNumber) {
fn discarded_initial_keys() {
qdebug!("---- client: generate CH");
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_eq!(init_pkt_c.as_ref().unwrap().len(), client.plpmtu());
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
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());
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());
// 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);
qdebug!("---- client: SH..FIN -> FIN");
let out = client.process(None, now()).dgram();
let out = client.process_output(now()).dgram();
assert!(out.is_some());
// The server will process the first Handshake packet.
// 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());
// 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.
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)));
// Send something to propagate the update.
@ -125,7 +125,7 @@ fn key_update_client() {
// The server should now be waiting to discharge read keys.
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 {
assert!(t < idle_timeout);
} else {
@ -142,10 +142,10 @@ fn key_update_client() {
// But at this point the client hasn't received a key update from the server.
// It will be stuck with old keys.
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_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)));
// 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.
let dgram = send_and_receive(&mut client, &mut server, now);
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
// with new keys, so its read timer just started.
if let Output::Callback(t) = res {
@ -170,7 +170,7 @@ fn key_update_client() {
assert_update_blocked(&mut server);
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)));
}
@ -194,11 +194,11 @@ fn key_update_consecutive() {
assert_eq!(client.get_epochs(), (Some(4), Some(3)));
// 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)));
// Now move the server temporarily into the future so that it
// 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)));
} else {
panic!("server should have a timer set");
@ -224,33 +224,33 @@ fn key_update_before_confirmed() {
assert_update_blocked(&mut server);
// Client Initial
let dgram = client.process(None, now()).dgram();
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
assert_update_blocked(&mut client);
// Server Initial + Handshake
let dgram = server.process(dgram.as_ref(), now()).dgram();
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_some());
assert_update_blocked(&mut server);
// Client Handshake
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
assert_update_blocked(&mut client);
assert!(maybe_authenticate(&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_update_blocked(&mut client);
// Server HANDSHAKE_DONE
let dgram = server.process(dgram.as_ref(), now()).dgram();
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_some());
assert!(server.initiate_key_update().is_ok());
// 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!(client.initiate_key_update().is_ok());
}
@ -281,13 +281,13 @@ fn exhaust_read_keys() {
let dgram = send_something(&mut client, now());
overwrite_invocations(0);
let dgram = server.process(Some(&dgram), now()).dgram();
let dgram = server.process(Some(dgram), now()).dgram();
assert!(matches!(
server.state(),
State::Closed(CloseReason::Transport(Error::KeysExhausted))
));
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
assert!(matches!(
client.state(),
State::Draining {

View File

@ -25,7 +25,7 @@ use super::{
};
use crate::{
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,
packet::PacketBuilder,
path::MAX_PATH_PROBES,
@ -75,7 +75,7 @@ fn rebinding_port() {
let dgram = send_something(&mut client, now());
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.
let stream_id = server.stream_create(StreamType::UniDi).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 = change_path(&dgram, DEFAULT_ADDR_V4);
server.process_input(&dgram, now);
server.process_input(dgram, now);
// The server now probes the new (primary) path.
let new_probe = server.process_output(now).dgram().unwrap();
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.
// The server also probes the old path.
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_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 server couldn't pad, so the client is also amplification limited.
let new_resp = client.process(Some(&new_probe), now).dgram().unwrap();
let new_resp = client.process(Some(new_probe), now).dgram().unwrap();
assert_eq!(client.stats().frame_rx.path_challenge, 1);
assert_eq!(client.stats().frame_tx.path_challenge, 1);
assert_eq!(client.stats().frame_tx.path_response, 1);
assert_v4_path(&new_resp, false);
// The client also responds to probes on the old path.
let old_resp = client.process(Some(&old_probe), now).dgram().unwrap();
let old_resp = client.process(Some(old_probe), now).dgram().unwrap();
assert_eq!(client.stats().frame_rx.path_challenge, 2);
assert_eq!(client.stats().frame_tx.path_challenge, 1);
assert_eq!(client.stats().frame_tx.path_response, 2);
@ -137,12 +139,13 @@ fn path_forwarding_attack() {
// Receiving the PATH_RESPONSE from the client opens the amplification
// limit enough for the server to respond.
// This is padded because it includes PATH_CHALLENGE.
let server_data1 = server.process(Some(&new_resp), now).dgram().unwrap();
let server_data1 = server.process(Some(new_resp), now).dgram().unwrap();
assert_v4_path(&server_data1, true);
assert_eq!(server.stats().frame_tx.path_challenge, 3);
assert_path_challenge_min_len(&server, &server_data1, now);
// The client responds to this probe on the new path.
client.process_input(&server_data1, now);
client.process_input(server_data1, now);
let stream_before = client.stats().frame_tx.stream;
let padded_resp = send_something(&mut client, now);
assert_eq!(stream_before, client.stats().frame_tx.stream);
@ -157,7 +160,7 @@ fn path_forwarding_attack() {
assert_v4_path(&server_data2, false);
// Until new data is received from the client on the old path.
server.process_input(&client_data2, now);
server.process_input(client_data2, now);
// The server sends a probe on the new path.
let server_data3 = send_something(&mut server, now);
assert_v4_path(&server_data3, true);
@ -179,13 +182,15 @@ fn migrate_immediate() {
let client1 = send_something(&mut client, now);
assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
assert_path_challenge_min_len(&client, &client1, now);
let client2 = send_something(&mut client, now);
assert_v4_path(&client2, false); // Doesn't.
let server_delayed = send_something(&mut server, now);
// The server accepts the first packet and migrates (but probes).
let server1 = server.process(Some(&client1), now).dgram().unwrap();
let server1 = server.process(Some(client1), now).dgram().unwrap();
assert_v4_path(&server1, true);
let server2 = server.process_output(now).dgram().unwrap();
assert_v6_path(&server2, true);
@ -193,13 +198,13 @@ fn migrate_immediate() {
// The second packet has no real effect, it just elicits an ACK.
let all_before = server.stats().frame_tx.all();
let ack_before = server.stats().frame_tx.ack;
let server3 = server.process(Some(&client2), now).dgram();
let server3 = server.process(Some(client2), now).dgram();
assert!(server3.is_some());
assert_eq!(server.stats().frame_tx.all(), all_before + 1);
assert_eq!(server.stats().frame_tx.ack, ack_before + 1);
// Receiving a packet sent by the server before migration doesn't change path.
client.process_input(&server_delayed, now);
client.process_input(server_delayed, now);
// The client has sent two unpaced packets and this new path has no RTT estimate
// so this might be paced.
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();
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
assert_path_challenge_min_len(&client, &probe, now);
// -1 because first PATH_CHALLENGE already sent above
for _ in 0..MAX_PATH_PROBES * 2 - 1 {
@ -246,6 +252,7 @@ fn migrate_immediate_fail() {
let before = client.stats().frame_tx;
let probe = client.process_output(now).dgram().unwrap();
assert_v4_path(&probe, true); // Contains PATH_CHALLENGE.
assert_path_challenge_min_len(&client, &probe, now);
let after = client.stats().frame_tx;
assert_eq!(after.path_challenge, before.path_challenge + 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.
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;
assert_eq!(after.path_challenge, before.path_challenge + 1);
assert_eq!(after.ping, before.ping + 1);
assert_eq!(after.all(), before.all() + 3);
}
@ -286,14 +294,15 @@ fn migrate_same() {
let probe = client.process_output(now).dgram().unwrap();
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
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_eq!(server.stats().frame_tx.path_response, 1);
assert_eq!(server.stats().frame_tx.path_challenge, 0);
// Everything continues happily.
client.process_input(&resp, now);
client.process_input(resp, now);
let contd = send_something(&mut client, now);
assert_v6_path(&contd, false);
}
@ -312,6 +321,7 @@ fn migrate_same_fail() {
let probe = client.process_output(now).dgram().unwrap();
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
assert_path_challenge_min_len(&client, &probe, now);
// -1 because first PATH_CHALLENGE already sent above
for _ in 0..MAX_PATH_PROBES * 2 - 1 {
@ -322,6 +332,7 @@ fn migrate_same_fail() {
let before = client.stats().frame_tx;
let probe = client.process_output(now).dgram().unwrap();
assert_v6_path(&probe, true); // Contains PATH_CHALLENGE.
assert_path_challenge_min_len(&client, &probe, now);
let after = client.stats().frame_tx;
assert_eq!(after.path_challenge, before.path_challenge + 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.
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;
assert_eq!(after.path_challenge, before.path_challenge + 1);
assert_eq!(after.ping, before.ping + 1);
assert_eq!(after.all(), before.all() + 3);
}
@ -368,11 +380,13 @@ fn migration(mut client: Connection) {
let probe = client.process_output(now).dgram().unwrap();
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);
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_path_challenge_min_len(&server, &resp, now);
assert_eq!(server.stats().frame_tx.path_response, 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);
assert_ne!(get_cid(&client_data), probe_cid);
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);
assert_v6_path(&server_data, false);
// 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);
let migrate_client = send_something(&mut client, now);
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
// received a response to its last probe, because it needs to verify
// 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 probe_old_server = send_something(&mut server, now);
// This is just the double-check probe; no STREAM frames.
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.stream, stream_before);
@ -409,8 +424,8 @@ fn migration(mut client: Connection) {
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.
client.process_input(&migrate_server, now);
client.process_input(&probe_old_server, now);
client.process_input(migrate_server, now);
client.process_input(probe_old_server, now);
let old_probe_resp = send_something(&mut client, now);
assert_v6_path(&old_probe_resp, true);
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.
fn fast_handshake(client: &mut Connection, server: &mut Connection) -> Option<Datagram> {
let dgram = client.process_output(now()).dgram();
let dgram = server.process(dgram.as_ref(), now()).dgram();
client.process_input(&dgram.unwrap(), now());
let dgram = server.process(dgram, now()).dgram();
client.process_input(dgram.unwrap(), now());
assert!(maybe_authenticate(client));
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) {
@ -512,9 +527,10 @@ fn preferred_address(hs_client: SocketAddr, hs_server: SocketAddr, preferred: So
// The client is about to process HANDSHAKE_DONE.
// 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_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));
// 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);
// 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_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);
// 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());
assert_orig_path(&data, false);
// Client gets the probe response back and it migrates.
client.process_input(&resp, now());
client.process_input(&data, now());
client.process_input(resp, now());
client.process_input(data, now());
let data = send_something(&mut client, now());
assert_toward_spa(&data, true);
assert_eq!(client.stats().frame_tx.stream, 2);
assert_eq!(client.stats().frame_tx.path_response, 1);
// 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_eq!(server.stats().frame_tx.path_challenge, 2);
assert_path_challenge_min_len(&server, &probe, now());
// But data now goes on the new path.
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);
// 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));
// Data continues on the main path for the client.
@ -708,14 +726,14 @@ fn migration_invalid_state() {
assert!(client
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.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
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
assert!(client
.migrate(Some(DEFAULT_ADDR), Some(DEFAULT_ADDR), false, now())
.is_err());
@ -814,7 +832,7 @@ fn retire_all() {
let new_cid_before = client.stats().frame_rx.new_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());
assert_eq!(
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();
assert_v4_path(&probe, true);
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));
assert_ne!(original_cid, probe_cid);
@ -861,17 +880,18 @@ fn retire_prior_to_migration_failure() {
// retire all of the available connection IDs.
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_eq!(server.stats().frame_tx.path_response, 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.
client.process_input(&retire_all, now());
client.process_input(retire_all, now());
// 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
// respond without a connection ID. We treat this as a connection error.
client.process_input(&resp, now());
client.process_input(resp, now());
assert!(matches!(
client.state(),
State::Closing {
@ -907,6 +927,7 @@ fn retire_prior_to_migration_success() {
let probe = client.process_output(now()).dgram().unwrap();
assert_v4_path(&probe, true);
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));
assert_ne!(original_cid, probe_cid);
@ -914,15 +935,16 @@ fn retire_prior_to_migration_success() {
// retire all of the available connection IDs.
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_eq!(server.stats().frame_tx.path_response, 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.
// As this occurs in a very specific order, migration succeeds.
client.process_input(&resp, now());
client.process_input(&retire_all, now());
client.process_input(resp, now());
client.process_input(retire_all, now());
// Migration succeeds and the new path gets the last connection ID.
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()));
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 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
// process_output is called.
@ -972,7 +994,7 @@ fn error_on_new_path_with_no_connection_id() {
));
// Wait until the connection is closed.
let mut now = now();
now += client.process(None, now).callback();
now += client.process_output(now).callback();
_ = client.process_output(now);
// No closing frames should be sent, and the connection should be closed.
assert_eq!(client.stats().frame_tx.connection_close, closing_frames);

View File

@ -30,7 +30,7 @@ use crate::{
stats::{FrameStats, Stats, MAX_PTO_COUNTS},
tparams::{DISABLE_MIGRATION, GREASE_QUIC_BIT},
ConnectionIdDecoder, ConnectionIdGenerator, ConnectionParameters, Error, StreamId, StreamType,
Version,
Version, MIN_INITIAL_PACKET_SIZE,
};
// All the tests.
@ -208,7 +208,7 @@ fn handshake_with_modifier(
if should_ping {
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 {
a.test_frame_writer = None;
did_ping[a.role()] = true;
@ -219,7 +219,7 @@ fn handshake_with_modifier(
mem::swap(&mut a, &mut b);
}
if let Some(d) = input {
a.process_input(&d, now);
a.process_input(d, now);
}
now
}
@ -299,7 +299,7 @@ fn exchange_ticket(
server.send_ticket(now, &[]).expect("can send ticket");
let ticket = server.process_output(now).dgram();
assert!(ticket.is_some());
client.process_input(&ticket.unwrap(), now);
client.process_input(ticket.unwrap(), now);
assert_eq!(*client.state(), State::Confirmed);
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!(
"fill_cwnd sent {} bytes",
total_dgrams.iter().map(|d| d.len()).sum::<usize>()
total_dgrams.iter().map(Datagram::len).sum::<usize>()
);
(total_dgrams, now)
}
@ -415,7 +415,7 @@ fn increase_cwnd(
let pkt = sender.process_output(now);
match pkt {
Output::Datagram(dgram) => {
receiver.process_input(&dgram, now + DEFAULT_RTT / 2);
receiver.process_input(dgram, now + DEFAULT_RTT / 2);
}
Output::Callback(t) => {
if t < DEFAULT_RTT {
@ -432,7 +432,7 @@ fn increase_cwnd(
now += DEFAULT_RTT / 2;
let ack = receiver.process_output(now).dgram();
now += DEFAULT_RTT / 2;
sender.process_input(&ack.unwrap(), now);
sender.process_input(ack.unwrap(), now);
now
}
@ -453,7 +453,7 @@ where
let in_dgrams = in_dgrams.into_iter();
qdebug!([dest], "ack_bytes {} datagrams", in_dgrams.len());
for dgram in in_dgrams {
dest.process_input(&dgram, now);
dest.process_input(dgram, now);
}
loop {
@ -524,7 +524,7 @@ fn induce_persistent_congestion(
// An ACK for the third PTO causes persistent congestion.
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));
now
}
@ -635,7 +635,7 @@ fn send_with_modifier_and_receive(
modifier: fn(Datagram) -> Option<Datagram>,
) -> Option<Datagram> {
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`.
@ -669,6 +669,27 @@ fn assert_default_stats(stats: &Stats) {
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]
fn create_client() {
let client = default_client();

View File

@ -26,7 +26,7 @@ fn no_encryption() {
let client_pkt = client.process_output(now()).dgram().unwrap();
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 (len, _) = server.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(len, DATA_CLIENT.len());
@ -35,7 +35,7 @@ fn no_encryption() {
let server_pkt = server.process_output(now()).dgram().unwrap();
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();
assert_eq!(len, DATA_SERVER.len());
assert_eq!(&buf[..len], DATA_SERVER);

View File

@ -41,7 +41,7 @@ fn receive_stream() {
assert_eq!(MESSAGE.len(), client.stream_send(id, MESSAGE).unwrap());
let dgram = client.process_output(now()).dgram();
server.process_input(&dgram.unwrap(), now());
server.process_input(dgram.unwrap(), now());
assert_eq!(
server
.stream_priority(
@ -83,7 +83,7 @@ fn relative() {
.unwrap();
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.
for e in server.events() {
@ -114,7 +114,7 @@ fn reprioritize() {
.unwrap();
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.
for e in server.events() {
@ -133,7 +133,7 @@ fn reprioritize() {
)
.unwrap();
let dgram = client.process_output(now()).dgram();
server.process_input(&dgram.unwrap(), now());
server.process_input(dgram.unwrap(), now());
for e in server.events() {
if let ConnectionEvent::RecvStreamReadable { stream_id } = e {
@ -164,7 +164,7 @@ fn repairing_loss() {
let _lost = client.process_output(now).dgram();
for _ in 0..5 {
match client.process_output(now) {
Output::Datagram(d) => server.process_input(&d, now),
Output::Datagram(d) => server.process_input(d, now),
Output::Callback(delay) => now += delay,
Output::None => unreachable!(),
}
@ -177,9 +177,9 @@ fn repairing_loss() {
let id_normal = client.stream_create(StreamType::UniDi).unwrap();
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.
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
// 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
// normal priority stream.
let dgram = client.process_output(now).dgram();
server.process_input(&dgram.unwrap(), now);
server.process_input(dgram.unwrap(), now);
assert!(server.events().any(
|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.
// That allows this to test that critical streams pre-empt most frame types.
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram.as_ref(), now).dgram();
client.process_input(&dgram.unwrap(), now);
let dgram = server.process(dgram, now).dgram();
client.process_input(dgram.unwrap(), now);
maybe_authenticate(&mut client);
let id = server.stream_create(StreamType::UniDi).unwrap();
@ -238,8 +238,8 @@ fn critical() {
assert_eq!(stats_after.handshake_done, 0);
// Complete the handshake.
let dgram = client.process(dgram.as_ref(), now).dgram();
server.process_input(&dgram.unwrap(), now);
let dgram = client.process(dgram, now).dgram();
server.process_input(dgram.unwrap(), now);
// Critical beats everything but HANDSHAKE_DONE.
let stats_before = server.stats().frame_tx;
@ -261,8 +261,8 @@ fn important() {
// Rather than connect, send stream data in 0.5-RTT.
// That allows this to test that important streams pre-empt most frame types.
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram.as_ref(), now).dgram();
client.process_input(&dgram.unwrap(), now);
let dgram = server.process(dgram, now).dgram();
client.process_input(dgram.unwrap(), now);
maybe_authenticate(&mut client);
let id = server.stream_create(StreamType::UniDi).unwrap();
@ -290,8 +290,8 @@ fn important() {
assert_eq!(stats_after.stream, stats_before.stream + 1);
// Complete the handshake.
let dgram = client.process(dgram.as_ref(), now).dgram();
server.process_input(&dgram.unwrap(), now);
let dgram = client.process(dgram, now).dgram();
server.process_input(dgram.unwrap(), now);
// Important beats everything but flow control.
let stats_before = server.stats().frame_tx;
@ -314,8 +314,8 @@ fn high_normal() {
// Rather than connect, send stream data in 0.5-RTT.
// That allows this to test that important streams pre-empt most frame types.
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram.as_ref(), now).dgram();
client.process_input(&dgram.unwrap(), now);
let dgram = server.process(dgram, now).dgram();
client.process_input(dgram.unwrap(), now);
maybe_authenticate(&mut client);
let id = server.stream_create(StreamType::UniDi).unwrap();
@ -343,8 +343,8 @@ fn high_normal() {
assert_eq!(stats_after.stream, stats_before.stream + 1);
// Complete the handshake.
let dgram = client.process(dgram.as_ref(), now).dgram();
server.process_input(&dgram.unwrap(), now);
let dgram = client.process(dgram, now).dgram();
server.process_input(dgram.unwrap(), now);
// High or Normal doesn't beat NEW_CONNECTION_ID,
// but they beat CRYPTO/NEW_TOKEN.

View File

@ -45,7 +45,7 @@ fn pto_works_basic() {
let mut now = now();
let res = client.process(None, now);
let res = client.process_output(now);
let idle_timeout = ConnectionParameters::default().get_idle_timeout();
assert_eq!(res, Output::Callback(idle_timeout));
@ -59,19 +59,19 @@ fn pto_works_basic() {
// Send a packet after some time.
now += Duration::from_secs(10);
let out = client.process(None, now);
let out = client.process_output(now);
assert!(out.dgram().is_some());
// Nothing to do, should return callback
let out = client.process(None, now);
let out = client.process_output(now);
assert!(matches!(out, Output::Callback(_)));
// One second later, it should want to send PTO packet
now += AT_LEAST_PTO;
let out = client.process(None, now);
let out = client.process_output(now);
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);
}
@ -96,7 +96,7 @@ fn pto_works_full_cwnd() {
// Both datagrams contain one or more STREAM frames.
for d in dgrams {
let stream_before = server.stats().frame_rx.stream;
server.process_input(&d, now);
server.process_input(d, now);
assert!(server.stats().frame_rx.stream > stream_before);
}
}
@ -115,49 +115,49 @@ fn pto_works_ping() {
let pkt3 = send_something(&mut client, now);
// 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:
// RTT + max(rttvar * 4, GRANULARITY) + max_ack_delay
// With zero RTT and rttvar, max_ack_delay is minimum too (GRANULARITY)
assert_eq!(cb, GRANULARITY * 2);
// 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
now += Duration::from_millis(20);
// 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
now += Duration::from_millis(20);
// 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
assert!(srv2.is_some());
// client processes ack
let pkt4 = client.process(srv2.as_ref(), now).dgram();
let pkt4 = client.process(srv2, now).dgram();
// client resends data from pkt0
assert!(pkt4.is_some());
// 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());
// Accept the acknowledgment.
let pkt5 = client.process(srv3.as_ref(), now).dgram();
let pkt5 = client.process(srv3, now).dgram();
assert!(pkt5.is_none());
now += Duration::from_millis(70);
// PTO expires. No unacked data. Only send 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);
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);
}
@ -168,40 +168,40 @@ fn pto_initial() {
qdebug!("---- client: generate CH");
let mut client = default_client();
let pkt1 = client.process(None, now).dgram();
let pkt1 = client.process_output(now).dgram();
assert!(pkt1.is_some());
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);
// Resend initial after PTO.
now += delay;
let pkt2 = client.process(None, now).dgram();
let pkt2 = client.process_output(now).dgram();
assert!(pkt2.is_some());
assert_eq!(pkt2.unwrap().len(), client.plpmtu());
let delay = client.process(None, now).callback();
let delay = client.process_output(now).callback();
// PTO has doubled.
assert_eq!(delay, INITIAL_PTO * 2);
// Server process the first initial pkt.
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());
// 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
// packet number space will be discarded.
// 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());
// 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 same as the initial PTO value, and there is only one sample,
// 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);
}
@ -215,37 +215,37 @@ fn pto_handshake_complete() {
let mut client = default_client();
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);
let cb = client.process(None, now).callback();
let cb = client.process_output(now).callback();
assert_eq!(cb, Duration::from_millis(300));
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);
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());
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 handshake PTO is set based on that.
assert_eq!(cb, HALF_RTT * 6);
now += HALF_RTT;
let pkt = server.process(pkt.as_ref(), now).dgram();
let pkt = server.process(pkt, now).dgram();
assert!(pkt.is_none());
now += HALF_RTT;
client.authenticated(AuthenticationStatus::Ok, now);
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_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);
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.
qdebug!("---- client: PTO");
now += HALF_RTT * 6;
let pkt2 = client.process(None, now).dgram();
let pkt2 = client.process_output(now).dgram();
assert_handshake(pkt2.as_ref().unwrap());
pto_counts[0] = 1;
@ -267,14 +267,14 @@ fn pto_handshake_complete() {
let stream_id = client.stream_create(StreamType::UniDi).unwrap();
client.stream_close_send(stream_id).unwrap();
now += HALF_RTT * 6;
let pkt3 = client.process(None, now).dgram();
let pkt3 = client.process_output(now).dgram();
assert_handshake(pkt3.as_ref().unwrap());
let (pkt3_hs, pkt3_1rtt) = split_datagram(&pkt3.unwrap());
assert_handshake(&pkt3_hs);
assert!(pkt3_1rtt.is_some());
// PTO has been doubled.
let cb = client.process(None, now).callback();
let cb = client.process_output(now).callback();
assert_eq!(cb, HALF_RTT * 12);
// 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.
let server_acks = server.stats().frame_tx.ack;
let server_done = server.stats().frame_tx.handshake_done;
server.process_input(&pkt3_1rtt.unwrap(), now);
let ack = server.process(pkt1.as_ref(), now).dgram();
server.process_input(pkt3_1rtt.unwrap(), now);
let ack = server.process(pkt1, now).dgram();
assert!(ack.is_some());
assert_eq!(server.stats().frame_tx.ack, server_acks + 2);
assert_eq!(server.stats().frame_tx.handshake_done, server_done + 1);
@ -302,14 +302,14 @@ fn pto_handshake_complete() {
assert!(pkt2_1rtt.is_some());
let dropped_before1 = server.stats().dropped_rx;
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!(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 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!(server.stats().frame_rx.all(), server_frames2);
@ -317,14 +317,14 @@ fn pto_handshake_complete() {
// Let the client receive the ACK.
// 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.
let expected_ack_delay = HALF_RTT * 2 / 4;
assert_eq!(cb, expected_ack_delay);
// Let the ACK delay timer expire.
now += cb;
let out = client.process(None, now).dgram();
let out = client.process_output(now).dgram();
assert!(out.is_some());
}
@ -334,19 +334,19 @@ fn pto_handshake_frames() {
let mut now = now();
qdebug!("---- client: generate CH");
let mut client = default_client();
let pkt = client.process(None, now);
let pkt = client.process_output(now);
now += Duration::from_millis(10);
qdebug!("---- server: CH -> SH, EE, CERT, CV, FIN");
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);
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);
mem::drop(server.process(pkt.as_dgram_ref(), now));
mem::drop(server.process(pkt.dgram(), now));
now += Duration::from_millis(10);
client.authenticated(AuthenticationStatus::Ok, now);
@ -355,21 +355,21 @@ fn pto_handshake_frames() {
assert_eq!(stream, 2);
assert_eq!(client.stream_send(stream, b"zero").unwrap(), 4);
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());
// Get PTO timer.
let out = client.process(None, now);
let out = client.process_output(now);
assert_eq!(out, Output::Callback(Duration::from_millis(60)));
// Wait for PTO to expire and resend a handshake packet.
now += Duration::from_millis(60);
let pkt2 = client.process(None, now).dgram();
let pkt2 = client.process_output(now).dgram();
assert!(pkt2.is_some());
now += Duration::from_millis(10);
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);
}
@ -388,21 +388,21 @@ fn handshake_ack_pto() {
let big = TransportParameter::Bytes(vec![0; Pmtud::default_plpmtu(DEFAULT_ADDR.ip())]);
server.set_local_tparam(0xce16, big).unwrap();
let c1 = client.process(None, now).dgram();
let c1 = client.process_output(now).dgram();
now += RTT / 2;
let s1 = server.process(c1.as_ref(), now).dgram();
let s1 = server.process(c1, now).dgram();
assert!(s1.is_some());
let s2 = server.process(None, now).dgram();
let s2 = server.process_output(now).dgram();
assert!(s1.is_some());
// Now let the client have the Initial, but drop the first coalesced Handshake packet.
now += RTT / 2;
let (initial, _) = split_datagram(&s1.unwrap());
client.process_input(&initial, now);
let c2 = client.process(s2.as_ref(), now).dgram();
client.process_input(initial, now);
let c2 = client.process(s2, now).dgram();
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);
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.
now += delay;
let c3 = client.process(None, now).dgram();
let c3 = client.process_output(now).dgram();
assert!(c3.is_some());
now += RTT / 2;
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);
pto_counts[0] = 1;
assert_eq!(client.stats.borrow().pto_counts, pto_counts);
// Now complete the handshake as cheaply as possible.
let dgram = server.process(None, now).dgram();
client.process_input(&dgram.unwrap(), now);
let dgram = server.process_output(now).dgram();
client.process_input(dgram.unwrap(), now);
maybe_authenticate(&mut client);
let dgram = client.process(None, now).dgram();
let dgram = client.process_output(now).dgram();
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);
client.process_input(&dgram.unwrap(), now);
client.process_input(dgram.unwrap(), now);
assert_eq!(*client.state(), State::Confirmed);
assert_eq!(client.stats.borrow().pto_counts, pto_counts);
@ -450,12 +450,12 @@ fn loss_recovery_crash() {
assert!(ack.is_some());
// 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));
// Now we leap into the future. The server should regard the first
// 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());
// This crashes.
@ -480,10 +480,10 @@ fn ack_after_pto() {
now += AT_LEAST_PTO;
// We can use MAX_PTO_PACKET_COUNT, because we know the handshake is over.
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!(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
// 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
// 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());
// Make sure that the packet only contained an ACK frame.
let all_frames_before = server.stats().frame_rx.all();
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.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.
now += RTT / 2;
let ack = server.process(Some(&p2), now).dgram();
let ack = server.process(Some(p2), now).dgram();
assert!(ack.is_some());
// The client also sends another two packets (p3, p4), again losing the first.
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.
// The client doesn't call p1 lost at this stage, but it will soon.
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.
let lr_timer = res.callback();
// Loss recovery timer should be RTT/8, but only check for 0 or >=RTT/2.
assert_ne!(lr_timer, Duration::from_secs(0));
assert!(lr_timer < (RTT / 2));
// 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());
// At t=RTT*3/2 the client should declare p1 to be lost.
now += RTT / 2;
// 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());
// When the client processes the ACK, it should engage the
// 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();
assert_eq!(lr_timer, lr_timer2);
}
@ -569,9 +569,9 @@ fn loss_time_past_largest_acked() {
let mut now = now();
// Start the handshake.
let c_in = client.process(None, now).dgram();
let c_in = client.process_output(now).dgram();
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.
// 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
// be much smaller than an RTT and so the server shouldn't see
// 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!(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());
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!(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());
// 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.
// Reordering delivery ensures that the later packet is also acknowledged.
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.
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.
// The we need the outstanding packet to be sent after the
// application data packet, so space these out a tiny bit.
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.
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.
// Process c_hs2 and c_hs4, but skip c_hs3.
// Then get an ACK for the client.
now += RTT / 2;
// Deliver c_hs4 first, but don't generate a packet.
server.process_input(&c_hs4.unwrap(), now);
let s_ack = server.process(c_hs2.as_ref(), now).dgram();
server.process_input(c_hs4.unwrap(), now);
let s_ack = server.process(c_hs2, now).dgram();
assert!(s_ack.is_some());
// This includes an ACK, but it also includes HANDSHAKE_DONE,
// 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 += 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.
let c_ack = client.process(None, now).dgram();
let c_ack = client.process_output(now).dgram();
assert!(c_ack.is_none());
// 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!(lr_time < (RTT / 2));
}
@ -648,12 +648,12 @@ fn trickle(sender: &mut Connection, receiver: &mut Connection, mut count: usize,
while count > 0 {
qdebug!("trickle: remaining={}", count);
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());
}
sender.process_input(&maybe_ack.unwrap(), now);
sender.process_input(maybe_ack.unwrap(), now);
}
/// Ensure that a PING frame is sent with ACK sometimes.
@ -744,7 +744,7 @@ fn fast_pto() {
let mut server = default_server();
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);
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.
now += cb;
let dgram = client.process(None, now).dgram();
let dgram = client.process_output(now).dgram();
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);
}
@ -781,7 +781,7 @@ fn fast_pto_persistent_congestion() {
let mut server = default_server();
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);
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 += DEFAULT_RTT / 2;
let ack = server.process(Some(&dgram), now).dgram();
let ack = server.process(Some(dgram), now).dgram();
now += DEFAULT_RTT / 2;
client.process_input(&ack.unwrap(), now);
client.process_input(ack.unwrap(), now);
assert_eq!(cwnd(&client), cwnd_min(&client));
}
@ -841,7 +841,7 @@ fn ack_for_unsent() {
.unwrap();
// Now deliver the packet with the spoofed ACK frame
client.process_input(&spoofed, now());
client.process_input(spoofed, now());
assert!(matches!(
client.state(),
State::Closing {

View File

@ -66,7 +66,7 @@ fn remember_smoothed_rtt() {
let ticket = server.process_output(now).dgram();
assert!(ticket.is_some());
now += RTT1 / 2;
client.process_input(&ticket.unwrap(), now);
client.process_input(ticket.unwrap(), now);
let token = get_tokens(&mut client).pop().unwrap();
let mut client = default_client();
@ -102,7 +102,7 @@ fn ticket_rtt(rtt: Duration) -> Duration {
let client_dcid = client_dcid.to_owned();
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 (protected_header, _, _, payload) =
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 += rtt / 2;
client.process_input(&si, now);
client.process_input(&server_hs.unwrap(), now);
client.process_input(si, now);
client.process_input(server_hs.unwrap(), now);
client.authenticated(AuthenticationStatus::Ok, now);
let finished = client.process_output(now);
assert_eq!(*client.state(), State::Connected);
now += rtt / 2;
_ = server.process(finished.as_dgram_ref(), now);
_ = server.process(finished.dgram(), now);
assert_eq!(*server.state(), State::Confirmed);
// 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();
assert!(ticket.is_some());
now += rtt / 2;
client.process_input(&ticket.unwrap(), now);
client.process_input(ticket.unwrap(), now);
let token = get_tokens(&mut client).pop().unwrap();
// And connect again.
@ -213,7 +213,7 @@ fn address_validation_token_resume() {
let mut server = resumed_server(&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);
// 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());
// 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.
assert_eq!(get_tokens(&mut client).len(), 0);
// We need to wait for release_resumption_token_timer to expire. The timer will be
// set to 3 * PTO
let mut now = now() + 3 * client.pto();
mem::drop(client.process(None, now));
mem::drop(client.process_output(now));
let mut recv_tokens = get_tokens(&mut client);
assert_eq!(recv_tokens.len(), 1);
let token1 = recv_tokens.pop().unwrap();
// Wai for anottheer 3 * PTO to get the nex okeen.
now += 3 * client.pto();
mem::drop(client.process(None, now));
mem::drop(client.process_output(now));
let mut recv_tokens = get_tokens(&mut client);
assert_eq!(recv_tokens.len(), 1);
let token2 = recv_tokens.pop().unwrap();
// Wait for 3 * PTO, but now there are no more tokens.
now += 3 * client.pto();
mem::drop(client.process(None, now));
mem::drop(client.process_output(now));
assert_eq!(get_tokens(&mut client).len(), 0);
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");
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);
assert_eq!(all_tokens.len(), 2);
let token1 = all_tokens.pop().unwrap();
@ -303,8 +303,8 @@ fn take_token() {
connect(&mut client, &mut server);
server.send_ticket(now(), &[]).unwrap();
let dgram = server.process(None, now()).dgram();
client.process_input(&dgram.unwrap(), now());
let dgram = server.process_output(now()).dgram();
client.process_input(dgram.unwrap(), now());
// There should be no ResumptionToken event here.
let tokens = get_tokens(&mut client);

View File

@ -32,14 +32,14 @@ use crate::{
fn stream_create() {
let mut client = default_client();
let out = client.process(None, now());
let out = client.process_output(now());
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());
mem::drop(server.process(out.as_dgram_ref(), now()));
let out = client.process(out.dgram(), now());
mem::drop(server.process(out.dgram(), now()));
assert!(maybe_authenticate(&mut client));
let out = client.process(None, now());
let out = client.process_output(now());
// client now in State::Connected
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(), 4);
mem::drop(server.process(out.as_dgram_ref(), now()));
mem::drop(server.process(out.dgram(), now()));
// server now in State::Connected
assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 3);
assert_eq!(server.stream_create(StreamType::UniDi).unwrap(), 7);
@ -86,7 +86,7 @@ fn transfer() {
qdebug!("---- server receives");
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.
assert!(out.as_dgram_ref().is_some());
qdebug!("Output={:0x?}", out.as_dgram_ref());
@ -151,7 +151,7 @@ fn sendorder_test(order_of_sendorder: &[Option<SendOrder>]) {
qdebug!("---- server receives");
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());
}
assert_eq!(*server.state(), State::Confirmed);
@ -317,12 +317,12 @@ fn report_fin_when_stream_closed_wo_data() {
// create a stream
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
client.stream_send(stream_id, &[0x00]).unwrap();
let out = client.process(None, now());
mem::drop(server.process(out.as_dgram_ref(), now()));
let out = client.process_output(now());
mem::drop(server.process(out.dgram(), now()));
server.stream_close_send(stream_id).unwrap();
let out = server.process(None, now());
mem::drop(client.process(out.as_dgram_ref(), now()));
let out = server.process_output(now());
mem::drop(client.process(out.dgram(), now()));
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
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) {
let mut input = None;
loop {
let out = client.process(input.as_ref(), now()).dgram();
let out = client.process(input, now()).dgram();
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 {
break;
}
@ -373,8 +373,8 @@ fn sending_max_data() {
assert_eq!(received, SMALL_MAX_DATA);
assert!(!fin);
let out = server.process(None, now()).dgram();
client.process_input(&out.unwrap(), now());
let out = server.process_output(now()).dgram();
client.process_input(out.unwrap(), now());
assert_eq!(
client
@ -511,8 +511,8 @@ fn do_not_accept_data_after_stop_sending() {
// create a stream
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
client.stream_send(stream_id, &[0x00]).unwrap();
let out = client.process(None, now());
mem::drop(server.process(out.as_dgram_ref(), now()));
let out = client.process_output(now());
mem::drop(server.process(out.dgram(), now()));
let stream_readable = |e| matches!(e, ConnectionEvent::RecvStreamReadable { .. });
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
// has already requested stop_sending.
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.
assert_eq!(
Ok(()),
@ -529,10 +529,10 @@ fn do_not_accept_data_after_stop_sending() {
// Receive the second data frame. The frame should be ignored and
// 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));
mem::drop(client.process(out.as_dgram_ref(), now()));
mem::drop(client.process(out.dgram(), now()));
assert_eq!(
Err(Error::FinalSizeError),
client.stream_send(stream_id, &[0x00])
@ -549,8 +549,8 @@ fn simultaneous_stop_sending_and_reset() {
// create a stream
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
client.stream_send(stream_id, &[0x00]).unwrap();
let out = client.process(None, now());
let ack = server.process(out.as_dgram_ref(), now()).dgram();
let out = client.process_output(now());
let ack = server.process(out.dgram(), now()).dgram();
let stream_readable =
|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
// has already requested stop_sending.
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
// acknowledgment at the next opportunity.
let force_ack = send_something(&mut client, now());
server.process_input(&force_ack, now());
server.process_input(force_ack, now());
// Call stop sending.
server.stream_stop_sending(stream_id, 0).unwrap();
// Receive the second data frame. The frame should be ignored and
// 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!(!server.events().any(stream_readable));
// The client gets the STOP_SENDING frame.
client.process_input(&ack.unwrap(), now());
client.process_input(ack.unwrap(), now());
assert_eq!(
Err(Error::InvalidStreamId),
client.stream_send(stream_id, &[0x00])
@ -588,35 +588,35 @@ fn client_fin_reorder() {
let mut server = default_server();
// Send ClientHello.
let client_hs = client.process(None, now());
let client_hs = client.process_output(now());
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...
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());
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!(maybe_authenticate(&mut client));
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());
let client_stream_id = client.stream_create(StreamType::UniDi).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());
// 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_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());
}
@ -629,10 +629,10 @@ fn after_fin_is_read_conn_events_for_stream_should_be_removed() {
let id = server.stream_create(StreamType::BiDi).unwrap();
server.stream_send(id, &[6; 10]).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());
mem::drop(client.process(out.as_ref(), now()));
mem::drop(client.process(out, now()));
// read from the stream before checking connection events.
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();
server.stream_send(id, &[6; 10]).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());
mem::drop(client.process(out.as_ref(), now()));
mem::drop(client.process(out, now()));
// send stop seending.
client
@ -682,11 +682,11 @@ fn stream_data_blocked_generates_max_stream_data() {
// Send some data and consume some flow control.
let stream_id = server.stream_create(StreamType::UniDi).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());
// Consume the data.
client.process_input(&dgram.unwrap(), now);
client.process_input(dgram.unwrap(), now);
let mut buf = [0; 10];
let (count, end) = client.stream_recv(stream_id, &mut buf[..]).unwrap();
assert_eq!(count, DEFAULT_STREAM_DATA.len());
@ -703,14 +703,14 @@ fn stream_data_blocked_generates_max_stream_data() {
assert!(dgram.is_some());
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!(dgram.is_some());
// Client should have sent a MAX_STREAM_DATA frame with just a small increase
// on the default window size.
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);
// 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.
_ = client.stream_send(stream_id, REQUEST).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.
server.process_input(&dgram.unwrap(), now());
server.process_input(dgram.unwrap(), now());
server.stream_send(stream_id, RESPONSE).unwrap();
let dgram = server.process_output(now()).dgram();
// 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();
assert!(matches!(e, Error::StreamLimitError));
// Closing the stream isn't enough.
server.stream_close_send(stream_id).unwrap();
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());
// 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,
// so give the client one more packet just in case.
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.
let dgram = send_something(&mut client, now());
let dgram = server.process(Some(&dgram), now()).dgram();
client.process_input(&dgram.unwrap(), now());
let dgram = server.process(Some(dgram), now()).dgram();
client.process_input(dgram.unwrap(), now());
assert!(client.stream_create(StreamType::BiDi).is_ok());
assert!(client.stream_create(StreamType::BiDi).is_err());
}
@ -790,8 +790,8 @@ fn no_dupdata_readable_events() {
// create a stream
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
client.stream_send(stream_id, &[0x00]).unwrap();
let out = client.process(None, now());
mem::drop(server.process(out.as_dgram_ref(), now()));
let out = client.process_output(now());
mem::drop(server.process(out.dgram(), now()));
// We have a data_readable event.
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,
// therefore there should not be a new DataReadable event.
client.stream_send(stream_id, &[0x00]).unwrap();
let out_second_data_frame = client.process(None, now());
mem::drop(server.process(out_second_data_frame.as_dgram_ref(), now()));
let out_second_data_frame = client.process_output(now());
mem::drop(server.process(out_second_data_frame.dgram(), now()));
assert!(!server.events().any(stream_readable));
// One more frame with a fin will not produce a new DataReadable event, because the
// previous stream data has not been read yet.
client.stream_send(stream_id, &[0x00]).unwrap();
client.stream_close_send(stream_id).unwrap();
let out_third_data_frame = client.process(None, now());
mem::drop(server.process(out_third_data_frame.as_dgram_ref(), now()));
let out_third_data_frame = client.process_output(now());
mem::drop(server.process(out_third_data_frame.dgram(), now()));
assert!(!server.events().any(stream_readable));
}
@ -822,8 +822,8 @@ fn no_dupdata_readable_events_empty_last_frame() {
// create a stream
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
client.stream_send(stream_id, &[0x00]).unwrap();
let out = client.process(None, now());
mem::drop(server.process(out.as_dgram_ref(), now()));
let out = client.process_output(now());
mem::drop(server.process(out.dgram(), now()));
// We have a data_readable event.
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
// the previous stream data has not been read yet.
client.stream_close_send(stream_id).unwrap();
let out_second_data_frame = client.process(None, now());
mem::drop(server.process(out_second_data_frame.as_dgram_ref(), now()));
let out_second_data_frame = client.process_output(now());
mem::drop(server.process(out_second_data_frame.dgram(), now()));
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);
// Send the stream to the client.
let out = server.process(None, now());
mem::drop(client.process(out.as_dgram_ref(), now()));
let out = server.process_output(now());
mem::drop(client.process(out.dgram(), now()));
// change max_stream_data for stream_id.
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.
let out2 = client.process(None, now());
let out3 = server.process(out2.as_dgram_ref(), now());
let out2 = client.process_output(now());
let out3 = server.process(out2.dgram(), now());
let expected = usize::from(RECV_BUFFER_START < new_fc);
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.
let out4 = client.process(out3.as_dgram_ref(), now());
let out5 = server.process(out4.as_dgram_ref(), now());
mem::drop(client.process(out5.as_dgram_ref(), now()));
let out4 = client.process(out3.dgram(), now());
let out5 = server.process(out4.dgram(), now());
mem::drop(client.process(out5.dgram(), now()));
// read all data by client
let mut buf = [0x0; 10000];
let (read, _) = client.stream_recv(stream_id, &mut buf).unwrap();
assert_eq!(u64::try_from(read).unwrap(), max(RECV_BUFFER_START, new_fc));
let out4 = client.process(None, now());
mem::drop(server.process(out4.as_dgram_ref(), now()));
let out4 = client.process_output(now());
mem::drop(server.process(out4.dgram(), now()));
let written3 = server.stream_send(stream_id, &[0x0; 10000]).unwrap();
assert_eq!(u64::try_from(written3).unwrap(), new_fc);
@ -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.
// The server sends STOP_SENDING -> the client sends RESET -> the server
// sends MAX_DATA.
let out = server.process(None, now()).dgram();
let out = client.process(out.as_ref(), now()).dgram();
let out = server.process_output(now()).dgram();
let out = client.process(out, now()).dgram();
// the client is still limited.
let stream_id2 = client.stream_create(StreamType::UniDi).unwrap();
assert_eq!(client.stream_avail_send_space(stream_id2).unwrap(), 0);
let out = server.process(out.as_ref(), now()).dgram();
client.process_input(&out.unwrap(), now());
let out = server.process(out, now()).dgram();
client.process_input(out.unwrap(), now());
assert_eq!(
client.stream_avail_send_space(stream_id2).unwrap(),
SMALL_MAX_DATA
@ -977,12 +977,12 @@ fn session_flow_control_stop_sending_state_size_known() {
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).
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
.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
// and the server releases flow control immediately and sends STOP_SENDING and
// MAX_DATA in the same packet.
let out = server.process(out1.as_ref(), now()).dgram();
client.process_input(&out.unwrap(), now());
let out = server.process(out1, now()).dgram();
client.process_input(out.unwrap(), now());
// The flow control should have been updated and the client can again send
// 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) {
let mut client = default_client();
let out = client.process(None, now());
let out = client.process_output(now());
let mut server = new_server(
ConnectionParameters::default()
.max_streams(StreamType::BiDi, bidi_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());
mem::drop(server.process(out.as_dgram_ref(), now()));
let out = client.process(out.dgram(), now());
mem::drop(server.process(out.dgram(), now()));
assert!(maybe_authenticate(&mut client));

View File

@ -27,11 +27,11 @@ const INITIAL_PTO: Duration = Duration::from_millis(300);
fn unknown_version() {
let mut client = default_client();
// Start the handshake.
mem::drop(client.process(None, now()).dgram());
mem::drop(client.process_output(now()).dgram());
let mut unknown_version_packet = vec![0x80, 0x1a, 0x1a, 0x1a, 0x1a];
unknown_version_packet.resize(MIN_INITIAL_PACKET_SIZE, 0x0);
mem::drop(client.process(Some(&datagram(unknown_version_packet)), now()));
mem::drop(client.process(Some(datagram(unknown_version_packet)), now()));
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);
assert_eq!(
server.process(Some(&datagram(unknown_version_packet)), now()),
server.process(Some(datagram(unknown_version_packet)), now()),
Output::None
);
@ -72,7 +72,7 @@ fn version_negotiation_current_version() {
let mut client = default_client();
// Start the handshake.
let initial_pkt = client
.process(None, now())
.process_output(now())
.dgram()
.expect("a datagram")
.to_vec();
@ -83,7 +83,7 @@ fn version_negotiation_current_version() {
);
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!(*client.state(), State::WaitInitial);
assert_eq!(1, client.stats().dropped_rx);
@ -94,7 +94,7 @@ fn version_negotiation_version0() {
let mut client = default_client();
// Start the handshake.
let initial_pkt = client
.process(None, now())
.process_output(now())
.dgram()
.expect("a datagram")
.to_vec();
@ -102,7 +102,7 @@ fn version_negotiation_version0() {
let vn = create_vn(&initial_pkt, &[0, 0x1a1a_1a1a]);
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!(*client.state(), State::WaitInitial);
assert_eq!(1, client.stats().dropped_rx);
@ -113,7 +113,7 @@ fn version_negotiation_only_reserved() {
let mut client = default_client();
// Start the handshake.
let initial_pkt = client
.process(None, now())
.process_output(now())
.dgram()
.expect("a datagram")
.to_vec();
@ -121,7 +121,7 @@ fn version_negotiation_only_reserved() {
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]);
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() {
State::Closed(err) => {
assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation));
@ -135,7 +135,7 @@ fn version_negotiation_corrupted() {
let mut client = default_client();
// Start the handshake.
let initial_pkt = client
.process(None, now())
.process_output(now())
.dgram()
.expect("a datagram")
.to_vec();
@ -143,7 +143,7 @@ fn version_negotiation_corrupted() {
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a]);
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!(*client.state(), State::WaitInitial);
assert_eq!(1, client.stats().dropped_rx);
@ -154,7 +154,7 @@ fn version_negotiation_empty() {
let mut client = default_client();
// Start the handshake.
let initial_pkt = client
.process(None, now())
.process_output(now())
.dgram()
.expect("a datagram")
.to_vec();
@ -162,7 +162,7 @@ fn version_negotiation_empty() {
let vn = create_vn(&initial_pkt, &[]);
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!(*client.state(), State::WaitInitial);
assert_eq!(1, client.stats().dropped_rx);
@ -173,14 +173,14 @@ fn version_negotiation_not_supported() {
let mut client = default_client();
// Start the handshake.
let initial_pkt = client
.process(None, now())
.process_output(now())
.dgram()
.expect("a datagram")
.to_vec();
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
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() {
State::Closed(err) => {
assert_eq!(*err, CloseReason::Transport(Error::VersionNegotiation));
@ -194,7 +194,7 @@ fn version_negotiation_bad_cid() {
let mut client = default_client();
// Start the handshake.
let mut initial_pkt = client
.process(None, now())
.process_output(now())
.dgram()
.expect("a datagram")
.to_vec();
@ -203,7 +203,7 @@ fn version_negotiation_bad_cid() {
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
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!(*client.state(), State::WaitInitial);
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.
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
let dgram = server.process(dgram.as_ref(), now()).dgram();
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_some());
// The following uses the Version from *outside* this crate.
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);
assert_eq!(client.version(), Version::Version2);
@ -308,7 +308,7 @@ fn version_negotiation_downgrade() {
let initial = client.process_output(now()).dgram().unwrap();
let vn = create_vn(&initial, &[DOWNGRADE.wire_version()]);
let dgram = datagram(vn);
client.process_input(&dgram, now());
client.process_input(dgram, now());
connect_fail(
&mut client,
@ -328,7 +328,7 @@ fn invalid_server_version() {
new_server(ConnectionParameters::default().versions(Version::Version2, Version::all()));
let dgram = client.process_output(now()).dgram();
server.process_input(&dgram.unwrap(), now());
server.process_input(dgram.unwrap(), now());
// One packet received.
assert_eq!(server.stats().packets_rx, 1);
@ -459,7 +459,7 @@ fn compatible_upgrade_0rtt_rejected() {
let initial = send_something(&mut client, now());
assertions::assert_version(&initial, Version::Version1.wire_version());
assertions::assert_coalesced_0rtt(&initial);
server.process_input(&initial, now());
server.process_input(initial, now());
assert!(!server
.events()
.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
// maybe_authenticate() too liberally and that eats the events we want to check.
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 = server.process(dgram.as_ref(), now()).dgram(); // HANDSHAKE_DONE
client.process_input(&dgram.unwrap(), now());
let dgram = client.process(dgram, now()).dgram(); // Client Finished (note: no authentication)
let dgram = server.process(dgram, now()).dgram(); // HANDSHAKE_DONE
client.process_input(dgram.unwrap(), now());
assert!(matches!(client.state(), State::Confirmed));
assert!(matches!(server.state(), State::Confirmed));

View File

@ -52,24 +52,24 @@ fn zero_rtt_send_recv() {
let mut server = resumed_server(&client);
// Send ClientHello.
let client_hs = client.process(None, now());
let client_hs = client.process_output(now());
assert!(client_hs.as_dgram_ref().is_some());
// Now send a 0-RTT packet.
let client_stream_id = client.stream_create(StreamType::UniDi).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());
// 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);
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...
let all_frames = server.stats().frame_tx.all();
let ack_frames = server.stats().frame_tx.ack;
let server_process_0rtt = server.process(client_0rtt.as_dgram_ref(), now());
assert!(server_process_0rtt.as_dgram_ref().is_some());
let server_process_0rtt = server.process(client_0rtt.dgram(), now());
assert!(server_process_0rtt.dgram().is_some());
assert_eq!(server.stats().frame_tx.all(), all_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.
let client_stream_id = client.stream_create(StreamType::UniDi).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());
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...
let server_stream_id = server
@ -153,18 +153,18 @@ fn zero_rtt_send_reject() {
.expect("enable 0-RTT");
// Send ClientHello.
let client_hs = client.process(None, now());
let client_hs = client.process_output(now());
assert!(client_hs.as_dgram_ref().is_some());
// Write some data on the client.
let stream_id = client.stream_create(StreamType::UniDi).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());
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...
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());
// 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));
// 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;
assert!(client.events().any(recvd_0rtt_reject));
// 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());
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());
// ...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();
assert_eq!(stream_id, stream_id_after_reject);
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());
// 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));
}
@ -227,15 +227,15 @@ fn zero_rtt_update_flow_control() {
);
// 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();
assert!(!client.stream_send_atomic(uni_stream, MESSAGE).unwrap());
let bidi_stream = client.stream_create(StreamType::BiDi).unwrap();
assert!(!client.stream_send_atomic(bidi_stream, MESSAGE).unwrap());
// Now get the server transport parameters.
let server_hs = server.process(client_hs.as_ref(), now()).dgram();
client.process_input(&server_hs.unwrap(), now());
let server_hs = server.process(client_hs, now()).dgram();
client.process_input(server_hs.unwrap(), now());
// The streams should report a writeable event.
let mut uni_stream_event = false;
@ -299,7 +299,7 @@ fn zero_rtt_loss_accepted() {
}
// 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());
let server_stream_id = server
@ -312,7 +312,7 @@ fn zero_rtt_loss_accepted() {
assert_eq!(client_stream_id, server_stream_id.as_u64());
// 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;
assert!(
!client.events().any(recvd_0rtt_reject),

View File

@ -107,7 +107,6 @@ pub enum Error {
DecodingFrame,
DecryptError,
DisabledVersion,
HandshakeFailed,
IdleTimeout,
IntegerOverflow,
InvalidInput,

View File

@ -718,7 +718,7 @@ impl Path {
// with the current value.
let tos = self.tos();
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`

View File

@ -195,7 +195,7 @@ impl Server {
fn handle_initial(
&mut self,
initial: InitialDetails,
dgram: &Datagram,
dgram: Datagram<impl AsRef<[u8]>>,
now: Instant,
) -> Output {
qdebug!([self], "Handle initial");
@ -297,7 +297,7 @@ impl Server {
fn accept_connection(
&mut self,
initial: InitialDetails,
dgram: &Datagram,
dgram: Datagram<impl AsRef<[u8]>>,
orig_dcid: Option<ConnectionId>,
now: Instant,
) -> 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[..]));
// This is only looking at the first packet header in the datagram.
@ -430,7 +430,7 @@ impl Server {
let mut callback = None;
for connection in &mut self.connections {
match connection.borrow_mut().process(None, now) {
match connection.borrow_mut().process_output(now) {
Output::None => {}
d @ Output::Datagram(_) => return d,
Output::Callback(next) => match callback {
@ -443,8 +443,14 @@ impl Server {
callback.map_or(Output::None, Output::Callback)
}
/// Short-hand for [`Server::process`] without an input datagram.
#[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
.map_or(Output::None, |d| self.process_input(d, now))
.or_else(|| self.process_next_output(now));

View File

@ -58,27 +58,27 @@ pub fn connect(client: &mut Connection, server: &mut Server) -> ConnectionRef {
server.set_validation(ValidateAddress::Never);
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());
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());
// 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.
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.
// Now mark the server as authenticated.
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_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
// 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_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);
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
let out = server.process(None, now());
client.process_input(out.as_dgram_ref().unwrap(), now()); // Consume ticket, ignore output.
let out = server.process_output(now());
client.process_input(out.dgram().unwrap(), now()); // Consume ticket, ignore output.
let ticket = find_ticket(&mut client);
// Have the client close the connection and then let the server clean up.
client.close(now(), 0, "got a ticket");
let out = client.process_output(now());
mem::drop(server.process(out.as_dgram_ref(), now()));
mem::drop(server.process(out.dgram(), now()));
// Calling active_connections clears the set of active connections.
assert_eq!(server.active_connections().len(), 1);
ticket

View File

@ -265,7 +265,7 @@ fn process_client_initial(v: Version, packet: &[u8]) {
let dgram = datagram(packet.to_vec());
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!(out.dgram().is_some());
}

View File

@ -29,9 +29,9 @@ fn truncate_long_packet() {
let mut client = default_client();
let mut server = default_server();
let out = client.process(None, now());
let out = client.process_output(now());
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());
// This will truncate the Handshake packet from the server.
@ -44,18 +44,18 @@ fn truncate_long_packet() {
dupe.tos(),
&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());
// 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!(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!(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!(server.state().connected());
}
@ -76,7 +76,7 @@ fn reorder_server_initial() {
decode_initial_header(client_initial.as_dgram_ref().unwrap(), Role::Client).unwrap();
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 (protected_header, _, _, payload) =
decode_initial_header(&server_initial, Role::Server).unwrap();
@ -119,16 +119,16 @@ fn reorder_server_initial() {
// Now a connection can be made successfully.
// 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.
client.process_input(&reordered, now());
client.process_input(&server_hs.unwrap(), now());
client.process_input(reordered, now());
client.process_input(server_hs.unwrap(), now());
assert!(test_fixture::maybe_authenticate(&mut client));
let finished = client.process_output(now());
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);
client.process_input(done.as_dgram_ref().unwrap(), now());
client.process_input(done.dgram().unwrap(), now());
assert_eq!(*client.state(), State::Confirmed);
}
@ -171,12 +171,13 @@ fn packet_without_frames() {
let mut server = default_server();
let client_initial = client.process_output(now());
let client_initial_clone = client_initial.as_dgram_ref().unwrap().clone();
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, &[]);
client.process_input(&modified, now());
client.process_input(modified, now());
assert_eq!(
client.state(),
&State::Closed(CloseReason::Transport(Error::ProtocolViolation))
@ -192,12 +193,13 @@ fn packet_with_only_padding() {
let mut server = default_server();
let client_initial = client.process_output(now());
let client_initial_clone = client_initial.as_dgram_ref().unwrap().clone();
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]);
client.process_input(&modified, now());
client.process_input(modified, now());
assert_eq!(client.state(), &State::WaitInitial);
}
@ -215,7 +217,7 @@ fn overflow_crypto() {
decode_initial_header(client_initial.as_ref().unwrap(), Role::Client).unwrap();
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());
// Now decrypt the server packet to get AEAD and HP instances.
@ -261,7 +263,7 @@ fn overflow_crypto() {
server_initial.tos(),
packet,
);
client.process_input(&dgram, now());
client.process_input(dgram, now());
if let State::Closing { error, .. } = client.state() {
assert!(
matches!(error, CloseReason::Transport(Error::CryptoBufferExceeded)),

View File

@ -35,23 +35,23 @@ fn retry_basic() {
server.set_validation(ValidateAddress::Always);
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());
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
let dgram = server.process(dgram, now()).dgram(); // Retry
assert!(dgram.is_some());
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());
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Initial, HS
let dgram = server.process(dgram, now()).dgram(); // Initial, HS
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());
let dgram = client.process(None, now()).dgram(); // Send Finished
let dgram = client.process_output(now()).dgram(); // Send Finished
assert!(dgram.is_some());
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...
connected_server(&server);
}
@ -66,12 +66,12 @@ fn implicit_rtt_retry() {
let mut client = default_client();
let mut now = now();
let dgram = client.process(None, now).dgram();
let dgram = client.process_output(now).dgram();
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());
now += RTT / 2;
client.process_input(&dgram.unwrap(), now);
client.process_input(dgram.unwrap(), now);
assert_eq!(client.stats().rtt, RTT);
}
@ -83,18 +83,18 @@ fn retry_expired() {
let mut client = default_client();
let mut now = now();
let dgram = client.process(None, now).dgram(); // Initial
let dgram = client.process_output(now).dgram(); // Initial
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());
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());
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());
}
@ -111,26 +111,26 @@ fn retry_0rtt() {
let client_stream = client.stream_create(StreamType::UniDi).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());
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());
assertions::assert_retry(dgram.as_ref().unwrap());
// 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());
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());
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
// as there is no certificate; authentication is based on the ticket.
assert!(dgram.is_some());
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());
connected_server(&server);
assert!(client.tls_info().unwrap().resumed());
@ -142,14 +142,14 @@ fn retry_different_ip() {
server.set_validation(ValidateAddress::Always);
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());
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
let dgram = server.process(dgram, now()).dgram(); // Retry
assert!(dgram.is_some());
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());
// 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_addr = SocketAddr::new(other_v4, 443);
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());
}
@ -170,7 +170,7 @@ fn new_token_different_ip() {
let mut client = default_client();
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());
assertions::assert_initial(dgram.as_ref().unwrap(), true);
@ -178,7 +178,7 @@ fn new_token_different_ip() {
let d = dgram.unwrap();
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 = server.process(dgram.as_ref(), now()).dgram(); // Retry
let dgram = server.process(dgram, now()).dgram(); // Retry
assert!(dgram.is_some());
assertions::assert_retry(dgram.as_ref().unwrap());
}
@ -192,7 +192,7 @@ fn new_token_expired() {
let mut client = default_client();
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());
assertions::assert_initial(dgram.as_ref().unwrap(), true);
@ -203,7 +203,7 @@ fn new_token_expired() {
let d = dgram.unwrap();
let src = SocketAddr::new(d.source().ip(), d.source().port() + 1);
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());
assertions::assert_retry(dgram.as_ref().unwrap());
}
@ -215,34 +215,34 @@ fn retry_after_initial() {
retry_server.set_validation(ValidateAddress::Always);
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());
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());
// We need to have the client just process the Initial.
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!(*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());
assertions::assert_retry(retry.as_ref().unwrap());
// 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());
// 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!(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_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());
connected_server(&server);
}
@ -253,9 +253,9 @@ fn retry_bad_integrity() {
server.set_validation(ValidateAddress::Always);
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());
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
let dgram = server.process(dgram, now()).dgram(); // Retry
assert!(dgram.is_some());
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);
// 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());
}
@ -278,16 +278,14 @@ fn retry_bad_token() {
let mut server = default_server();
// 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());
let retry = retry_server
.process(client_initial1.as_ref(), now())
.dgram();
let retry = retry_server.process(client_initial1, now()).dgram();
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());
let dgram = server.process(client_initial2.as_ref(), now()).dgram();
let dgram = server.process(client_initial2, now()).dgram();
assert!(dgram.is_none());
}
@ -303,20 +301,20 @@ fn retry_after_pto() {
server.set_validation(ValidateAddress::Always);
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
// Let PTO fire on the client and then let it exhaust its PTO packets.
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);
let cb = client.process(None, now).callback();
let cb = client.process_output(now).callback();
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());
let ci2 = client.process(retry.as_ref(), now).dgram();
let ci2 = client.process(retry, now).dgram();
assert!(ci2.unwrap().len() >= MIN_INITIAL_PACKET_SIZE);
}
@ -326,14 +324,14 @@ fn vn_after_retry() {
server.set_validation(ValidateAddress::Always);
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());
let dgram = server.process(dgram.as_ref(), now()).dgram(); // Retry
let dgram = server.process(dgram, now()).dgram(); // Retry
assert!(dgram.is_some());
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());
let mut encoder = Encoder::default();
@ -345,7 +343,7 @@ fn vn_after_retry() {
let vn = datagram(encoder.into());
assert_ne!(
client.process(Some(&vn), now()).callback(),
client.process(Some(vn), now()).callback(),
Duration::from_secs(0)
);
}
@ -368,13 +366,11 @@ fn mitm_retry() {
let mut server = default_server();
// 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());
let retry = retry_server
.process(client_initial1.as_ref(), now())
.dgram();
let retry = retry_server.process(client_initial1, now()).dgram();
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());
// Now to start the epic process of decrypting the packet,
@ -432,15 +428,15 @@ fn mitm_retry() {
notoken_packet,
);
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());
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());
let dgram = server.process(dgram.as_ref(), now()).dgram();
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_none());
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!(matches!(
*client.state(),

View File

@ -47,8 +47,8 @@ pub fn complete_connection(
};
while !is_done(client) {
_ = test_fixture::maybe_authenticate(client);
let out = client.process(datagram.as_ref(), now());
let out = server.process(out.as_dgram_ref(), now());
let out = client.process(datagram, now());
let out = server.process(out.dgram(), now());
datagram = out.dgram();
}
@ -111,9 +111,9 @@ fn connect_single_version_server() {
// Run the version negotiation exchange if necessary.
let out = client.process_output(now());
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());
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
}
let server_conn = connect(&mut client, &mut server);
@ -133,14 +133,16 @@ fn duplicate_initial() {
let mut client = default_client();
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());
// The server should ignore a packets with the same remote address and
// 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());
let dgram = server.process(initial.as_dgram_ref(), now()).dgram();
let dgram = server.process(initial.dgram(), now()).dgram();
assert!(dgram.is_none());
assert_eq!(server.active_connections().len(), 1);
@ -153,7 +155,7 @@ fn duplicate_initial_new_path() {
let mut client = default_client();
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(
SocketAddr::new(initial.source().ip(), initial.source().port() ^ 23),
initial.destination(),
@ -161,11 +163,11 @@ fn duplicate_initial_new_path() {
&initial[..],
);
let server_initial = server.process(Some(&initial), now()).dgram();
let server_initial = server.process(Some(initial), now()).dgram();
assert!(server_initial.is_some());
// 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_eq!(server.active_connections().len(), 1);
@ -178,20 +180,16 @@ fn different_initials_same_path() {
let mut client1 = 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());
let client_initial2 = client2.process(None, now());
let client_initial2 = client2.process_output(now());
assert!(client_initial2.as_dgram_ref().is_some());
// The server should respond to both as these came from different addresses.
let server_initial1 = server
.process(client_initial1.as_dgram_ref(), now())
.dgram();
let server_initial1 = server.process(client_initial1.dgram(), now()).dgram();
assert!(server_initial1.is_some());
let server_initial2 = server
.process(client_initial2.as_dgram_ref(), now())
.dgram();
let server_initial2 = server.process(client_initial2.dgram(), now()).dgram();
assert!(server_initial2.is_some());
assert_eq!(server.active_connections().len(), 2);
@ -204,17 +202,19 @@ fn same_initial_after_connected() {
let mut server = default_server();
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());
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());
complete_connection(&mut client, &mut server, server_initial);
assert_eq!(server.active_connections().len(), 1);
// 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.
let dgram = server.process(client_initial.as_dgram_ref(), now()).dgram();
let dgram = server.process(client_initial.dgram(), now()).dgram();
assert!(dgram.is_some());
// The server should make a new connection object.
assert_eq!(server.active_connections().len(), 2);
@ -236,7 +236,7 @@ fn drop_non_initial() {
bogus_data.resize(MIN_INITIAL_PACKET_SIZE, 66);
let bogus = datagram(bogus_data);
assert!(server.process(Some(&bogus), now()).dgram().is_none());
assert!(server.process(Some(bogus), now()).dgram().is_none());
}
#[test]
@ -255,7 +255,7 @@ fn drop_short_initial() {
bogus_data.resize(1199, 66);
let bogus = datagram(bogus_data);
assert!(server.process(Some(&bogus), now()).dgram().is_none());
assert!(server.process(Some(bogus), now()).dgram().is_none());
}
#[test]
@ -272,7 +272,7 @@ fn drop_short_header_packet_for_unknown_connection() {
bogus_data.resize(MIN_INITIAL_PACKET_SIZE, 66);
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
@ -286,9 +286,9 @@ fn zero_rtt() {
// Discharge the old connection so that we don't have to worry about it.
let mut now = now();
let t = server.process(None, now).callback();
let t = server.process_output(now).callback();
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);
let start_time = now;
@ -298,12 +298,12 @@ fn zero_rtt() {
let mut client_send = || {
let client_stream = client.stream_create(StreamType::UniDi).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::Callback(t) => {
// Pacing...
now += t;
client.process(None, now).dgram().unwrap()
client.process_output(now).dgram().unwrap()
}
Output::None => panic!(),
}
@ -317,12 +317,12 @@ fn zero_rtt() {
let c4 = client_send();
// 0-RTT packets that arrive before the handshake get dropped.
mem::drop(server.process(Some(&c2), now));
mem::drop(server.process(Some(c2), now));
assert!(server.active_connections().is_empty());
// Now handshake and let another 0-RTT packet in.
let shs = server.process(Some(&c1), now);
mem::drop(server.process(Some(&c3), now));
let shs = server.process(Some(c1), now);
mem::drop(server.process(Some(c3), now));
// The server will have received two STREAM frames now if it processed both packets.
// `ActiveConnectionRef` `Hash` implementation doesnt access any of the interior mutable types.
#[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
// a little so that the pacer doesn't prevent the Finished from being sent.
now += now - start_time;
let cfin = client.process(shs.as_dgram_ref(), now);
mem::drop(server.process(cfin.as_dgram_ref(), now));
let cfin = client.process(shs.dgram(), now);
mem::drop(server.process(cfin.dgram(), now));
// 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 doesnt access any of the interior mutable types.
#[allow(clippy::mutable_key_type)]
let active = server.active_connections();
@ -377,20 +377,20 @@ fn new_token_0rtt() {
let client_stream = client.stream_create(StreamType::UniDi).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());
assertions::assert_initial(out.as_dgram_ref().unwrap(), true);
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());
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
// as there is no certificate; authentication is based on the ticket.
assert!(out.as_dgram_ref().is_some());
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());
connected_server(&server);
assert!(client.tls_info().unwrap().resumed());
@ -405,7 +405,7 @@ fn new_token_different_port() {
let mut client = default_client();
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());
assertions::assert_initial(dgram.as_ref().unwrap(), true);
@ -413,7 +413,7 @@ fn new_token_different_port() {
let d = dgram.unwrap();
let src = SocketAddr::new(d.source().ip(), d.source().port() + 1);
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());
assertions::assert_initial(dgram.as_ref().unwrap(), false);
}
@ -423,7 +423,7 @@ fn bad_client_initial() {
let mut client = default_client();
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 (aead, hp) = initial_aead_and_hp(d_cid, Role::Client);
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);
// 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();
// The resulting datagram might contain multiple packets, but each is small.
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.
// 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());
// 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!(matches!(
*client.state(),
@ -502,7 +502,7 @@ fn bad_client_initial() {
}
// 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);
}
@ -511,7 +511,7 @@ fn bad_client_initial_connection_close() {
let mut client = default_client();
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 (aead, hp) = initial_aead_and_hp(d_cid, Role::Client);
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.
let mut now = now();
let response = server.process(Some(&bad_dgram), now);
let response = server.process(Some(bad_dgram), now);
now += response.callback();
let response = server.process(None, now);
let response = server.process_output(now);
assert_eq!(response, Output::None);
}
@ -565,7 +565,7 @@ fn version_negotiation_ignored() {
let mut client = default_client();
// 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();
input[1] ^= 0x12;
let damaged = Datagram::new(
@ -574,7 +574,7 @@ fn version_negotiation_ignored() {
dgram.tos(),
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 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");
// 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_eq!(client.state(), &State::WaitInitial);
}
@ -615,9 +615,9 @@ fn version_negotiation() {
// `connect()` runs a fixed exchange, so manually run the Version Negotiation.
let dgram = client.process_output(now()).dgram();
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());
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
let sconn = connect(&mut client, &mut server);
assert_eq!(client.version(), VN_VERSION);
@ -651,22 +651,22 @@ fn version_negotiation_and_compatible() {
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
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());
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());
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());
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
client.authenticated(AuthenticationStatus::Ok, now());
let dgram = client.process_output(now()).dgram();
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
assert_eq!(*client.state(), State::Connected);
let dgram = server.process(dgram.as_ref(), now()).dgram(); // ACK + HANDSHAKE_DONE + NST
client.process_input(&dgram.unwrap(), now());
let dgram = server.process(dgram, now()).dgram(); // ACK + HANDSHAKE_DONE + NST
client.process_input(dgram.unwrap(), now());
assert_eq!(*client.state(), State::Confirmed);
let sconn = connected_server(&server);
@ -698,8 +698,8 @@ fn compatible_upgrade_resumption_and_vn() {
assert_eq!(server_conn.borrow().version(), COMPAT_VERSION);
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
let dgram = server.process(None, now()).dgram();
client.process_input(&dgram.unwrap(), now()); // Consume ticket, ignore output.
let dgram = server.process_output(now()).dgram();
client.process_input(dgram.unwrap(), now()); // Consume ticket, ignore output.
let ticket = find_ticket(&mut client);
// 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();
assert!(dgram.is_some());
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());
client.process_input(&dgram.unwrap(), now());
client.process_input(dgram.unwrap(), now());
let server_conn = connect(&mut client, &mut server);
assert_eq!(client.version(), RESUMPTION_VERSION);
@ -730,14 +730,14 @@ fn closed() {
connect(&mut client, &mut server);
// 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));
// 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));
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);
}
@ -825,8 +825,8 @@ fn max_streams_after_0rtt_rejection() {
client.enable_resumption(now(), &token).unwrap();
_ = client.stream_create(StreamType::BiDi).unwrap();
let dgram = client.process_output(now()).dgram();
let dgram = server.process(dgram.as_ref(), now()).dgram();
let dgram = client.process(dgram.as_ref(), now()).dgram();
let dgram = server.process(dgram, now()).dgram();
let dgram = client.process(dgram, now()).dgram();
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.
@ -863,8 +863,8 @@ fn has_active_connections() {
assert!(!server.has_active_connections());
let initial = client.process(None, now());
_ = server.process(initial.as_dgram_ref(), now()).dgram();
let initial = client.process_output(now());
_ = server.process(initial.dgram(), now()).dgram();
assert!(server.has_active_connections());
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"f115cdd60c3993b4b7b5611ee8ccffe2a92e6b4180cca93fed8c198805543ace","src/lib.rs":"bf3bc79b1d799a42b73e64d2b203ce688cc0859d7afa6c66eec429ec36199ba6"},"package":null}
{"files":{"Cargo.toml":"9dfe3aad758bbe584ac465f6cb35a9a7d3e32d859cb3878a23390fcff3f4f828","src/lib.rs":"d175cfb8f2ed2cc1a0e552c910fdee0e780a38a582d570554db32ff417115e55"},"package":null}

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.76.0"
name = "neqo-udp"
version = "0.9.2"
version = "0.10.0"
authors = ["The Neqo Authors <necko@mozilla.com>"]
build = false
autobins = false

View File

@ -7,10 +7,9 @@
#![allow(clippy::missing_errors_doc)] // Functions simply delegate to tokio and quinn-udp.
use std::{
cell::RefCell,
io::{self, IoSliceMut},
net::SocketAddr,
slice,
slice::{self, Chunks},
};
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.
//
// TODO: Experiment with different values across platforms.
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 const RECV_BUF_SIZE: usize = u16::MAX as usize;
pub fn send_inner(
state: &UdpSocketState,
@ -57,63 +52,89 @@ use std::os::fd::AsFd as SocketRef;
#[cfg(windows)]
use std::os::windows::io::AsSocket as SocketRef;
pub fn recv_inner(
local_address: &SocketAddr,
pub fn recv_inner<'a>(
local_address: SocketAddr,
state: &UdpSocketState,
socket: impl SocketRef,
) -> Result<Vec<Datagram>, io::Error> {
let dgrams = RECV_BUF.with_borrow_mut(|recv_buf| -> Result<Vec<Datagram>, io::Error> {
let mut meta;
recv_buf: &'a mut [u8],
) -> Result<DatagramIter<'a>, io::Error> {
let mut meta;
loop {
meta = RecvMeta::default();
let data = loop {
meta = RecvMeta::default();
state.recv(
(&socket).into(),
&mut [IoSliceMut::new(recv_buf)],
slice::from_mut(&mut meta),
)?;
state.recv(
(&socket).into(),
&mut [IoSliceMut::new(recv_buf)],
slice::from_mut(&mut meta),
)?;
if meta.len == 0 || meta.stride == 0 {
qdebug!(
"ignoring datagram from {} to {} len {} stride {}",
meta.addr,
local_address,
meta.len,
meta.stride
);
continue;
}
break;
if meta.len == 0 || meta.stride == 0 {
qdebug!(
"ignoring datagram from {} to {} len {} stride {}",
meta.addr,
local_address,
meta.len,
meta.stride
);
continue;
}
Ok(recv_buf[0..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())
})?;
break &recv_buf[..meta.len];
};
qtrace!(
"received {} datagrams ({:?})",
dgrams.len(),
dgrams.iter().map(|d| d.len()).collect::<Vec<_>>(),
"received {} bytes from {} to {} in {} segments",
data.len(),
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.
@ -138,8 +159,12 @@ impl<S: SocketRef> Socket<S> {
/// Receive a batch of [`Datagram`]s on the given [`Socket`], each
/// set with the provided local address.
pub fn recv(&self, local_address: &SocketAddr) -> Result<Vec<Datagram>, io::Error> {
recv_inner(local_address, &self.state, &self.inner)
pub fn recv<'a>(
&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)?;
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);
Ok(())
@ -191,17 +217,15 @@ mod tests {
sender.send(&datagram)?;
let received_datagram = receiver
.recv(&receiver_addr)
.expect("receive to succeed")
.into_iter()
.next()
.expect("receive to yield datagram");
let mut recv_buf = vec![0; RECV_BUF_SIZE];
let mut received_datagrams = receiver
.recv(receiver_addr, &mut recv_buf)
.expect("receive to succeed");
// Assert that the ECN is correct.
assert_eq!(
IpTosEcn::from(datagram.tos()),
IpTosEcn::from(received_datagram.tos())
IpTosEcn::from(received_datagrams.next().unwrap().tos())
);
Ok(())
@ -236,11 +260,11 @@ mod tests {
// Allow for one GSO sendmmsg to result in multiple GRO recvmmsg.
let mut num_received = 0;
let mut recv_buf = vec![0; RECV_BUF_SIZE];
while num_received < max_gso_segments {
receiver
.recv(&receiver_addr)
.recv(receiver_addr, &mut recv_buf)
.expect("receive to succeed")
.into_iter()
.for_each(|d| {
assert_eq!(
SEGMENT_SIZE,
@ -253,4 +277,20 @@ mod tests {
Ok(())
}
#[test]
fn fmt_datagram_iter() {
let dgrams = [];
let i = DatagramIter {
meta: RecvMeta::default(),
datagrams: dgrams.chunks(1),
local_address: "[::]:0".parse().unwrap(),
};
assert_eq!(
&format!("{i:?}"),
"DatagramIter { meta: RecvMeta { addr: [::]:0, len: 0, stride: 0, ecn: None, dst_ip: None }, local_address: [::]:0 }"
);
}
}