pub mod wire;
mod connection;
mod driver;
mod endpoint;
mod shared;
mod staged;
mod stream;
pub use self::connection::Connection;
pub use self::endpoint::{Connecting, Endpoint, EndpointBuilder};
pub use self::shared::Notification;
pub use self::staged::{Claimed, Intro, Proven};
pub use self::stream::{BiStream, RecvStream, SendStream};
#[cfg(any(feature = "sink", feature = "tower"))]
pub(crate) use self::shared::WakerSlot;
#[cfg(test)]
mod tests {
use std::time::Duration;
use crate::error::{ConnectError, ConnectionLost};
use crate::testutil::{Pair, local, settle};
#[tokio::test(start_paused = true)]
async fn a_dial_and_a_staged_accept_meet() {
local(async {
let pair = Pair::seeded(0x5117E5);
let (a, b) = pair.establish().await;
assert!(a.is_established());
assert!(b.is_established());
assert_eq!(a.remote_address(), pair.b.addr());
assert_eq!(a.remote_static().as_ref(), pair.b.public_static.as_ref());
assert_eq!(b.remote_static().as_ref(), pair.a.public_static.as_ref());
assert_eq!(a.session_id(), b.session_id());
assert_eq!(pair.a.dhs.get(), 4, "§6.1's initiator ladder is 4 DH");
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_close_reaches_the_peer_as_peer_closed() {
local(async {
let pair = Pair::seeded(1);
let (a, b) = pair.establish().await;
a.close(0x2a, b"so long").await;
assert_eq!(a.closed().await, ConnectionLost::LocallyClosed);
assert_eq!(
b.closed().await,
ConnectionLost::PeerClosed {
code: 0x2a,
reason: b"so long".to_vec(),
}
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn closed_is_latched_concurrent_and_cancel_safe() {
local(async {
let pair = Pair::seeded(2);
let (a, b) = pair.establish().await;
{
let mut parked = Box::pin(b.closed());
assert!(
futures_lite_poll_once(&mut parked).is_none(),
"a healthy connection resolved `closed()`",
);
}
let one = b.closed();
let two = b.closed();
let three = b.closed();
a.close(7, b"").await;
let (one, two, three) = tokio::join!(one, two, three);
assert_eq!(one, two);
assert_eq!(two, three);
assert_eq!(b.closed().await, one);
assert_eq!(b.closed().await, one);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_cancelled_dial_frees_the_static_with_no_clock_advance() {
local(async {
let pair = Pair::seeded(3);
let dialling = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("the static is NONE");
assert_eq!(
pair.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.err(),
Some(ConnectError::AlreadyConnected),
);
drop(dialling);
let redial = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("the cancellation is ordered ahead of this verb");
drop(redial);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn the_endpoint_is_not_the_last_handle() {
local(async {
let pair = Pair::seeded(4);
let (a, b) = pair.establish().await;
let crate::testutil::Pair {
net,
a: peer_a,
b: peer_b,
} = pair;
drop(peer_a.endpoint);
settle().await;
assert!(a.is_established(), "the driver stopped with the endpoint");
let before = net.sends();
a.close(0, b"").await;
settle().await;
assert!(net.sends() > before, "the CLOSE never left");
assert!(matches!(
b.closed().await,
ConnectionLost::PeerClosed { .. }
));
drop(peer_b);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn the_coincident_last_handle_drop_transmits_nothing() {
local(async {
let pair = Pair::seeded(5);
let (a, b) = pair.establish().await;
let crate::testutil::Pair {
net,
a: peer_a,
b: peer_b,
} = pair;
let tap = net.tap();
let a_addr = peer_a.addr();
let from_a = |tap: &crate::testutil::Tap| {
tap.snapshot()
.iter()
.filter(|spied| spied.src == a_addr)
.count()
};
drop(peer_a.endpoint);
settle().await;
let before = from_a(&tap);
drop(a);
settle().await;
assert_eq!(
from_a(&tap),
before,
"§15.4's endpoint-dropped row transmitted something",
);
assert!(b.is_established());
drop(b);
drop(peer_b.endpoint);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_non_coincident_last_connection_drop_does_transmit() {
local(async {
let pair = Pair::seeded(9);
let (a, b) = pair.establish().await;
let tap = pair.net.tap();
let addr_a = pair.a.addr();
let from_a = || {
tap.snapshot()
.iter()
.filter(|spied| spied.src == addr_a)
.count()
};
let before = from_a();
drop(a);
settle().await;
assert!(from_a() > before, "the graceful CLOSE was never sealed");
assert!(matches!(
b.closed().await,
ConnectionLost::PeerClosed { code: 0, .. },
));
})
.await;
}
#[tokio::test(start_paused = true)]
async fn dropping_an_intro_is_silent() {
local(async {
let pair = Pair::seeded(6);
let dialling = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("connect");
let intro = pair.b.endpoint.accept().await.expect("an introduction");
assert_eq!(intro.source(), pair.a.addr());
assert_ne!(intro.sender_index(), 0, "§17.2 mints nonzero indices");
let before = pair.b.dhs.get();
drop(intro);
settle().await;
assert_eq!(pair.b.dhs.get(), before, "a rejected intro cost DH");
tokio::time::advance(Duration::from_secs(6)).await;
let again = pair.b.endpoint.accept().await.expect("a retransmission");
drop(again);
drop(dialling);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_dial_nobody_answers_gives_up_at_the_giveup_and_not_before() {
local(async {
let pair = Pair::seeded(7);
pair.net.partition(pair.b.addr());
let started = tokio::time::Instant::now();
let outcome = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("connect")
.await;
let elapsed = tokio::time::Instant::now() - started;
assert_eq!(outcome.err(), Some(ConnectError::TimedOut));
assert!(
elapsed >= crate::constants::HANDSHAKE_GIVEUP,
"gave up early, at {elapsed:?}",
);
assert!(
elapsed < crate::constants::HANDSHAKE_GIVEUP + Duration::from_secs(6),
"gave up late, at {elapsed:?}",
);
drop(
pair.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("a redial after the give-up"),
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn an_idle_connection_dies_at_dead_timeout() {
local(async {
let pair = Pair::seeded(8);
let (a, b) = pair.establish().await;
let started = tokio::time::Instant::now();
assert_eq!(a.closed().await, ConnectionLost::TimedOut);
let elapsed = tokio::time::Instant::now() - started;
assert!(
elapsed >= crate::constants::DEAD_TIMEOUT,
"died early, at {elapsed:?}",
);
assert_eq!(b.closed().await, ConnectionLost::TimedOut);
assert!(!a.is_established());
assert!(!b.is_established());
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_closed_connection_frees_its_static_when_the_linger_expires() {
local(async {
let pair = Pair::seeded(10);
let (a, b) = pair.establish().await;
a.close(0, b"").await;
settle().await;
assert!(a.is_established(), "the linger dropped state early");
assert_eq!(
pair.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.err(),
Some(ConnectError::AlreadyConnected),
"the static was freed before the linger expired",
);
tokio::time::advance(crate::constants::CLOSE_LINGER + Duration::from_millis(1)).await;
settle().await;
assert!(!a.is_established(), "the linger never expired");
drop(a);
drop(b);
let tap = pair.net.tap();
let from_a = || {
tap.snapshot()
.iter()
.filter(|spied| spied.src == pair.a.addr())
.count()
};
let before = from_a();
let redial = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect(
"`mint_pending` still found the static occupied after the linger: \
`Retired` never reached the endpoint core (ruling 90)",
);
settle().await;
assert!(
from_a() > before,
"no msg1 left the wire: `core::Endpoint::connect` refused the redial, \
so `Retired` never reached the endpoint core and the static leaked",
);
let accept = async {
let intro = pair.b.endpoint.accept().await.expect("an introduction");
let claimed = intro.read_identity().await.expect("read_identity");
let proven = claimed.authenticate().await.expect("authenticate");
proven.accept().await.expect("accept")
};
let (again_a, again_b) = tokio::join!(
async {
redial.await.expect(
"the endpoint core still held the static: `Retired` was not delivered",
)
},
accept,
);
assert!(again_a.is_established());
assert!(again_b.is_established());
})
.await;
}
#[tokio::test(start_paused = true)]
async fn an_expired_introduction_is_not_handed_to_a_later_accept() {
local(async {
let pair = Pair::seeded(11);
let dialling = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("connect");
settle().await;
drop(dialling);
tokio::time::advance(crate::constants::INTRO_TTL + Duration::from_secs(1)).await;
settle().await;
let dialling = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("the static is NONE again");
let intro = pair.b.endpoint.accept().await.expect("an introduction");
let claimed = intro
.read_identity()
.await
.expect("accept() handed over an introduction that had already expired");
assert_eq!(
claimed.claimed_static().as_ref(),
pair.a.public_static.as_ref(),
);
drop(claimed);
drop(dialling);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_waker_that_polls_inline_does_not_re_enter_a_live_borrow() {
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
local(async {
let pair = Pair::seeded(12);
let (a, b) = pair.establish().await;
let a = Rc::new(a);
let waker = inline_waker();
let outcome: Rc<Cell<Option<ConnectionLost>>> = Rc::new(Cell::new(None));
let mut parked: Pin<Box<dyn Future<Output = ConnectionLost>>> = Box::pin(a.closed());
assert!(
parked
.as_mut()
.poll(&mut Context::from_waker(&waker))
.is_pending(),
"a healthy connection resolved `closed()`",
);
ON_WAKE.with(|slot| {
let handle = Rc::clone(&a);
let outcome = Rc::clone(&outcome);
*slot.borrow_mut() = Some(Box::new(move || {
let mut inline = Box::pin(handle.closed());
let polled = inline
.as_mut()
.poll(&mut Context::from_waker(Waker::noop()));
if let Poll::Ready(lost) = polled {
outcome.set(Some(lost));
}
}));
});
b.close(9, b"inline").await;
settle().await;
assert_eq!(
outcome.take(),
Some(ConnectionLost::PeerClosed {
code: 9,
reason: b"inline".to_vec(),
}),
"the inline re-poll never completed: the waker ran under \
`ConnCell`'s borrow and the driver task panicked",
);
assert_eq!(
pair.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.err(),
Some(ConnectError::AlreadyConnected),
"the driver stopped: `Driver::drop` ran `stop()` on an unwind",
);
ON_WAKE.with(|slot| *slot.borrow_mut() = None);
drop(parked);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn an_inline_waker_may_re_poll_a_connecting_from_wake() {
use std::cell::{Cell, RefCell};
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
local(async {
let pair = Pair::seeded(13);
pair.net.partition(pair.b.addr());
let dialling = pair
.a
.endpoint
.connect(pair.b.addr(), pair.b.public_static)
.expect("the static is NONE");
settle().await;
type Dial = Pin<Box<crate::shell::Connecting<crate::testutil::TestIdentity>>>;
let dialling: Rc<RefCell<Dial>> = Rc::new(RefCell::new(Box::pin(dialling)));
let outcome: Rc<Cell<Option<ConnectError>>> = Rc::new(Cell::new(None));
let waker = inline_waker();
assert!(
dialling
.borrow_mut()
.as_mut()
.poll(&mut Context::from_waker(&waker))
.is_pending(),
"the dial resolved before the give-up",
);
ON_WAKE.with(|action| {
let dialling = Rc::clone(&dialling);
let outcome = Rc::clone(&outcome);
*action.borrow_mut() = Some(Box::new(move || {
let polled = dialling
.borrow_mut()
.as_mut()
.poll(&mut Context::from_waker(Waker::noop()));
if let Poll::Ready(Err(error)) = polled {
outcome.set(Some(error));
}
}));
});
tokio::time::advance(crate::constants::HANDSHAKE_GIVEUP + Duration::from_secs(1)).await;
settle().await;
assert_eq!(
outcome.take(),
Some(ConnectError::TimedOut),
"the inline re-poll never completed: the waker ran under \
`PendingSlot`'s borrow and the driver task panicked",
);
ON_WAKE.with(|action| *action.borrow_mut() = None);
})
.await;
}
thread_local! {
static ON_WAKE: std::cell::RefCell<Option<Box<dyn FnMut()>>> =
const { std::cell::RefCell::new(None) };
}
struct InlineWaker;
impl std::task::Wake for InlineWaker {
fn wake(self: std::sync::Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &std::sync::Arc<Self>) {
let action = ON_WAKE.with(|slot| slot.borrow_mut().take());
if let Some(mut action) = action {
action();
ON_WAKE.with(|slot| *slot.borrow_mut() = Some(action));
}
}
}
fn inline_waker() -> std::task::Waker {
std::task::Waker::from(std::sync::Arc::new(InlineWaker))
}
fn futures_lite_poll_once<F: std::future::Future>(
future: &mut std::pin::Pin<Box<F>>,
) -> Option<F::Output> {
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
match future.as_mut().poll(&mut cx) {
std::task::Poll::Ready(value) => Some(value),
std::task::Poll::Pending => None,
}
}
#[tokio::test(start_paused = true)]
async fn a_finished_uni_stream_survives_its_senders_drop() {
local(async {
let pair = Pair::seeded(0x4B_0010);
let (a, b) = pair.establish().await;
let mut send = a.open_uni().await.expect("open_uni");
let payload = b"the spec is the authority";
let mut written = 0;
while written < payload.len() {
written += send.write(&payload[written..]).await.expect("write");
}
send.finish().await.expect("finish");
let id = send.id();
assert!(
id.is_some(),
"ruling 116: a live handle's id is always Some"
);
drop(send);
settle().await;
let mut recv = b.accept_uni().await.expect("accept_uni");
assert_eq!(recv.id(), id, "both ends name the same stream");
let mut got = Vec::new();
let mut buf = [0u8; 8];
while let Some(n) = recv.read(&mut buf).await.expect("read") {
got.extend_from_slice(&buf[..n]);
}
assert_eq!(got, payload);
assert_eq!(recv.read(&mut buf).await, Ok(None));
assert_eq!(recv.id(), id, "ruling 116: `id()` keeps answering");
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_finished_streams_eof_outlives_its_connection() {
local(async {
let pair = Pair::seeded(0x4B_0020);
let (a, b) = pair.establish().await;
let mut send = a.open_uni().await.expect("open_uni");
send.write(b"done").await.expect("write");
send.finish().await.expect("finish");
settle().await;
let mut recv = b.accept_uni().await.expect("accept_uni");
let mut buf = [0u8; 8];
let n = recv.read(&mut buf).await.expect("read").expect("bytes");
assert_eq!(&buf[..n], b"done");
assert_eq!(recv.read(&mut buf).await, Ok(None), "EOF");
b.close(0, b"").await;
settle().await;
assert_eq!(
recv.read(&mut buf).await,
Ok(None),
"ruling 124: the stream ended before the connection did, and \
the handle reports the fate of its own stream"
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_finished_send_half_answers_from_its_own_state_after_death() {
local(async {
use crate::error::WriteError;
let pair = Pair::seeded(0x4B_0021);
let (a, _b) = pair.establish().await;
let mut send = a.open_uni().await.expect("open_uni");
send.write(b"x").await.expect("write");
send.finish().await.expect("finish");
a.close(0, b"").await;
settle().await;
assert_eq!(
send.finish().await,
Ok(()),
"ruling 124: `finish` stays idempotent across the death"
);
assert_eq!(
send.write(b"more").await,
Err(WriteError::Finished),
"ruling 124: the half's own terminal state, not the \
connection's"
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn the_last_handle_to_a_connection_may_be_a_stream() {
local(async {
let pair = Pair::seeded(0x4B_0012);
let (a, b) = pair.establish().await;
let mut send = a.open_uni().await.expect("open_uni");
send.finish().await.expect("finish");
drop(a);
settle().await;
assert!(
b.is_established(),
"ruling 115: a live `SendStream` is a handle, so this was \
not the last one and no CLOSE is owed yet",
);
drop(send);
settle().await;
assert_eq!(
b.closed().await,
ConnectionLost::PeerClosed {
code: crate::constants::NO_ERROR,
reason: Vec::new(),
},
"§16.2: the last handle to a connection performs \
`close(NO_ERROR, \"\")`, whatever kind of handle it is",
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_reset_is_sticky_at_the_reader() {
local(async {
let pair = Pair::seeded(0x4B_0011);
let (a, b) = pair.establish().await;
let mut send = a.open_uni().await.expect("open_uni");
send.write(b"partial").await.expect("write");
settle().await;
let mut recv = b.accept_uni().await.expect("accept_uni");
let mut buf = [0u8; 32];
assert_eq!(recv.read(&mut buf).await, Ok(Some(7)));
send.reset(0x2a);
settle().await;
assert_eq!(
recv.read(&mut buf).await,
Err(crate::error::ReadError::Reset(0x2a))
);
assert_eq!(
recv.read(&mut buf).await,
Err(crate::error::ReadError::Reset(0x2a)),
"ruling 121: the core is not sticky, so the handle must be",
);
assert!(a.is_established() && b.is_established());
})
.await;
}
#[tokio::test(start_paused = true)]
async fn dropping_stream_handles_empties_the_waker_maps() {
use std::task::Context;
use super::BiStream;
local(async {
let pair = Pair::seeded(0x4B_0001);
let (a, _b) = pair.establish().await;
assert_eq!(
a.stream_waker_entries(),
(0, 0),
"a connection with no streams holds no waker-map entries",
);
const N: usize = 8;
let mut handles = Vec::new();
for _ in 0..N {
handles.push(a.open_bi().await.expect("open_bi"));
}
let waker = std::task::Waker::noop();
let mut cx = Context::from_waker(waker);
let mut buf = [0u8; 8];
let mut halves: Vec<_> = handles.into_iter().map(BiStream::split).collect();
for (_, recv) in &mut halves {
assert!(
recv.poll_read(&mut cx, &mut buf).is_pending(),
"a stream nobody has written to should park its reader",
);
}
assert_eq!(
a.stream_waker_entries(),
(N, N),
"every live half owns exactly one per-`StreamRef` entry",
);
drop(halves);
assert_eq!(
a.stream_waker_entries(),
(0, 0),
"a dropped handle must take its map entry with it (§16.8)",
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_parked_stream_waiter_resolves_when_the_driver_stops() {
use std::cell::RefCell;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
use crate::error::{ReadError, WriteError};
type Halves = (
crate::testutil::TestSendStream,
crate::testutil::TestRecvStream,
);
let outcomes: Rc<RefCell<Vec<(&'static str, ConnectionLost)>>> =
Rc::new(RefCell::new(Vec::new()));
let set = tokio::task::LocalSet::new();
#[expect(
unused_variables,
reason = "held past `drop(set)` so the driver's death is not a handle-count effect"
)]
let (pair, a, b, kept): (_, _, _, Rc<RefCell<Option<Halves>>>) = set
.run_until(async {
let pair = Pair::seeded(0x4B_0002);
let (a, b) = pair.establish().await;
let (send, recv) = a.open_bi().await.expect("open_bi").split();
let kept = Rc::new(RefCell::new(Some((send, recv))));
let waker = inline_waker();
let mut cx = Context::from_waker(&waker);
let mut buf = [0u8; 8];
{
let mut borrow = kept.borrow_mut();
let (send, recv) = borrow.as_mut().expect("both halves");
assert!(recv.poll_read(&mut cx, &mut buf).is_pending());
let chunk = vec![0x5Au8; 8 * 1024];
let mut parked = false;
for _ in 0..64 {
if send.poll_write(&mut cx, &chunk).is_pending() {
parked = true;
break;
}
}
assert!(parked, "the writer never reached §10.1's stream window");
}
ON_WAKE.with(|action| {
let kept = Rc::clone(&kept);
let outcomes = Rc::clone(&outcomes);
*action.borrow_mut() = Some(Box::new(move || {
let mut borrow = kept.borrow_mut();
let Some((send, recv)) = borrow.as_mut() else {
return;
};
let mut cx = Context::from_waker(Waker::noop());
let mut buf = [0u8; 8];
if let Poll::Ready(Err(ReadError::ConnectionLost(lost))) =
recv.poll_read(&mut cx, &mut buf)
{
outcomes.borrow_mut().push(("read", lost));
}
if let Poll::Ready(Err(WriteError::ConnectionLost(lost))) =
send.poll_write(&mut cx, b"x")
{
outcomes.borrow_mut().push(("write", lost));
}
}));
});
(pair, a, b, kept)
})
.await;
drop(set);
let recorded = outcomes.borrow().clone();
for half in ["read", "write"] {
assert!(
recorded.contains(&(half, ConnectionLost::EndpointDropped)),
"the parked {half} was never swept by `Driver::latch`; \
parking for ever is F1's shape — recorded: {recorded:?}",
);
}
ON_WAKE.with(|action| *action.borrow_mut() = None);
drop(kept.borrow_mut().take());
}
#[test]
fn a_stream_handle_may_be_dropped_with_no_runtime() {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.start_paused(true)
.build()
.expect("a current-thread runtime");
let set = tokio::task::LocalSet::new();
let (pair, a, b, bi) = runtime.block_on(set.run_until(async {
let pair = Pair::seeded(0x4B_0003);
let (a, b) = pair.establish().await;
let bi = a.open_bi().await.expect("open_bi");
(pair, a, b, bi)
}));
drop(set);
drop(runtime);
drop(bi);
drop(a);
drop(b);
drop(pair);
}
#[tokio::test(start_paused = true)]
async fn the_claim_verbs_park_in_their_own_sets_and_release_on_drop() {
local(async {
let pair = Pair::seeded(0x6_0001);
let (_a, b) = pair.establish().await;
assert_eq!(b.sugar_waker_entries(), (0, 0, 0), "nothing parked yet");
{
let mut message = Box::pin(b.recv_message());
let mut datagram = Box::pin(b.recv_datagram());
assert!(futures_lite_poll_once(&mut message).is_none());
assert!(futures_lite_poll_once(&mut datagram).is_none());
assert_eq!(
b.sugar_waker_entries(),
(1, 1, 0),
"each parked future holds exactly its own slot"
);
}
assert_eq!(
b.sugar_waker_entries(),
(0, 0, 0),
"a dropped future leaves the sets as it found them"
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_datagram_crosses_and_wakes_a_parked_claim() {
local(async {
let pair = Pair::seeded(0x6_0002);
let (a, b) = pair.establish().await;
let mut waiting = Box::pin(b.recv_datagram());
assert!(futures_lite_poll_once(&mut waiting).is_none());
a.send_datagram(b"unreliable").expect("send_datagram");
settle().await;
assert_eq!(waiting.await.expect("the datagram arrived"), b"unreliable");
})
.await;
}
#[tokio::test(start_paused = true)]
async fn an_oversize_datagram_is_rejected_and_queues_nothing() {
local(async {
let pair = Pair::seeded(0x6_0003);
let (a, b) = pair.establish().await;
a.send_datagram(b"first").expect("send_datagram");
let over = vec![0xAB; crate::constants::MAX_DATAGRAM_PAYLOAD + 1];
assert!(matches!(
a.send_datagram(&over),
Err(crate::error::DatagramError::TooLarge)
));
settle().await;
assert_eq!(b.recv_datagram().await.expect("the legal one"), b"first");
})
.await;
}
#[tokio::test(start_paused = true)]
async fn a_message_survives_the_senders_close() {
local(async {
let pair = Pair::seeded(0x6_0004);
let (a, b) = pair.establish().await;
a.send_message(b"one whole message").await.expect("send");
a.acked().await.expect("the peer acknowledged it");
a.close(0, b"").await;
settle().await;
assert_eq!(
b.recv_message().await.expect("drained after the latch"),
b"one whole message"
);
assert!(
b.recv_message().await.is_err(),
"with nothing left to claim the death is reported"
);
})
.await;
}
#[tokio::test(start_paused = true)]
async fn an_oversize_message_is_rejected_at_the_handle() {
local(async {
let pair = Pair::seeded(0x6_0005);
let (a, _b) = pair.establish().await;
let over = vec![0u8; crate::constants::MESSAGE_RECV_MAX as usize + 1];
assert!(matches!(
a.send_message(&over).await,
Err(crate::error::MessageError::TooLarge)
));
})
.await;
}
thread_local! {
static REENTRANT_STREAM: std::cell::RefCell<Option<crate::testutil::TestSendStream>> =
const { std::cell::RefCell::new(None) };
static REENTRANT_ARMED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
static REENTRANT_FIRED: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
}
struct InlinePoller;
impl std::task::Wake for InlinePoller {
fn wake(self: std::sync::Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &std::sync::Arc<Self>) {
if !REENTRANT_ARMED.with(std::cell::Cell::get) {
return;
}
REENTRANT_ARMED.with(|c| c.set(false));
REENTRANT_FIRED.with(|c| c.set(c.get() + 1));
REENTRANT_STREAM.with(|slot| {
let mut slot = slot.borrow_mut();
let send = slot.as_mut().expect("the stream is parked here");
let waker = std::task::Waker::noop().clone();
let mut cx = std::task::Context::from_waker(&waker);
let wrote = std::pin::Pin::new(send).poll_write(&mut cx, b"reentrant-write");
assert!(
matches!(wrote, std::task::Poll::Ready(Ok(15))),
"the reentrant write must be accepted by the core, or this test \
asserts nothing about what happens to it afterwards: {wrote:?}"
);
});
}
}
#[tokio::test(start_paused = true)]
async fn a_reentrant_consumer_write_in_the_post_drain_tail_is_not_destroyed() {
local(async {
let pair = Pair::seeded(0x262_0001);
let (a, b) = pair.establish().await;
settle().await;
let (send, _recv) = b.open_bi().await.expect("open_bi").split();
settle().await;
let third: crate::testutil::TestIdentity =
crate::testutil::CountingIdentity::seeded([0x5C; 32]);
let third = super::Endpoint::builder()
.identity(third)
.wire(pair.net.endpoint(crate::testutil::addr_c()))
.config(crate::config::Config::new())
.rng_seed([0x5D; 32])
.build();
REENTRANT_STREAM.with(|slot| *slot.borrow_mut() = Some(send));
REENTRANT_ARMED.with(|c| c.set(true));
let mut accepting = Box::pin(pair.b.endpoint.accept());
let waker = std::task::Waker::from(std::sync::Arc::new(InlinePoller));
let mut cx = std::task::Context::from_waker(&waker);
assert!(
std::future::Future::poll(accepting.as_mut(), &mut cx).is_pending(),
"accept() must park, or the waker is never registered and this test \
exercises nothing"
);
settle().await;
let _dialling = third
.connect(pair.b.addr(), pair.b.public_static)
.expect("the third endpoint dials");
settle().await;
settle().await;
assert_eq!(
REENTRANT_FIRED.with(std::cell::Cell::get),
1,
"the inline waker must have fired from serve()'s tail, or the window \
this test exists for was never entered"
);
let accepted = tokio::time::timeout(Duration::from_millis(1), a.accept_bi())
.await
.expect(
"ruling 262: the reentrant write's datagram must reach the peer. A \
driver that collects deadlines with poll_output() pops it and \
discards it, and nothing retransmits within zero virtual time",
)
.expect("accept_bi");
let mut reading = accepted.split().1;
let mut got = vec![0u8; 64];
let n = reading
.read(&mut got)
.await
.expect("read")
.expect("bytes, not end of stream");
assert_eq!(
&got[..n],
b"reentrant-write",
"the bytes the core accepted must be the bytes the peer receives"
);
REENTRANT_STREAM.with(|slot| slot.borrow_mut().take());
})
.await;
}
}