#![allow(clippy::items_after_statements)]
#![allow(clippy::too_many_lines)]
use std::time::{Duration, Instant};
use super::*;
use super::testfix::*;
use super::timers::TimerKind;
use crate::constants::{
AEAD_TAG_LEN, AMPLIFICATION_FACTOR, DATA_HEADER_LEN, FRAME_ACK, FRAME_PADDING,
FRAME_PATH_CHALLENGE, FRAME_PATH_RESPONSE, FRAME_PING, INIT_PACKET_LEN, KEEPALIVE_TIMEOUT,
MAX_PLAINTEXT, RESP_PACKET_LEN,
};
use crate::error::ConnectionLost;
const PKT_OVERHEAD: u64 = (DATA_HEADER_LEN + AEAD_TAG_LEN) as u64;
const PROBE_PACKET_LEN: u64 = PKT_OVERHEAD + 1;
const KEEPALIVE_PACKET_LEN: u64 = PKT_OVERHEAD;
const RESPONDER_CAP: u64 = AMPLIFICATION_FACTOR * INIT_PACKET_LEN as u64;
const COALESCED_PROBE_LEN: u64 = PKT_OVERHEAD + 9 + 1;
const COALESCED_PROBE_BOTH_LEN: u64 = PKT_OVERHEAD + 9 + 9 + 1;
fn c_addr() -> SocketAddr {
v4(3, 3)
}
fn packet_counter(dgram: &[u8]) -> u64 {
u64::from_le_bytes(dgram[6..14].try_into().expect("§3.4's 14-byte header"))
}
fn mark(s: &mut Solo, now: Instant) -> Drained {
s.conn.mark_contested(now);
drain(&mut s.conn)
}
fn responder_at(now: Instant) -> Solo {
Solo::installed_from_msg1_at(now)
}
fn dialled_at(now: Instant) -> Solo {
let (mut conn, sa, sb) = Solo::connecting();
conn.handle_endpoint_event(
now,
Install {
session: sa,
role: Role::Initiator,
anchor_from_msg1: false,
},
);
let _ = drain(&mut conn);
Solo::around(conn, sb)
}
fn budget(s: &Solo) -> (u64, u64) {
s.conn
.amplification_budget()
.expect("§3.2: the address is unvalidated, so a budget is armed")
}
fn room(s: &Solo) -> u64 {
let (sent, recv) = budget(s);
(AMPLIFICATION_FACTOR * recv).saturating_sub(sent)
}
fn spend_to_the_cap(s: &mut Solo, now: Instant) {
spend_leaving(s, now, 0);
}
fn spend_leaving(s: &mut Solo, now: Instant, target: u64) {
if let Some(at) = s.conn.timer(TimerKind::AckDelay) {
s.conn.handle_timeout(at);
let _ = drain(&mut s.conn);
}
let (sent_before, recv_before) = budget(s);
let space = room(s);
assert!(
space >= target,
"the fixture cannot manufacture room: had {space}, asked to leave \
{target}"
);
let spend = space - target;
let path = if s.conn.outstanding_challenge().is_some() {
(1 + 8) as u64
} else {
0
};
assert!(
spend > path + PKT_OVERHEAD + 1 + 1,
"the fixture needs room for one shaping datagram; had {spend} to \
spend"
);
let payload = {
let one = spend - path - PKT_OVERHEAD - 1 - 1;
if one < 64 {
one as usize
} else {
(spend - path - PKT_OVERHEAD - 1 - 2) as usize
}
};
assert!(
payload < 16_384,
"the varint arithmetic above covers payloads below 16384; got {payload}"
);
s.conn
.send_datagram(now, &ramp(0, payload))
.expect("§11: a sub-maximum datagram is accepted");
let d = drain(&mut s.conn);
assert_eq!(
d.transmits().len(),
1,
"the shaping datagram is sized to fit the budget exactly, so it \
must leave: §7.3's check is a strict `>`"
);
assert_eq!(
d.transmits()[0].data.len() as u64,
spend,
"the shaping packet must be exactly the room it was told to spend, \
or every later assertion in this file is calibrated against the \
wrong cap"
);
assert_eq!(
budget(s),
(sent_before + spend, recv_before),
"§3.2: sending credits `budget_sent` in datagram bytes and leaves \
`budget_recv` alone"
);
assert_eq!(
room(s),
target,
"the point of the fixture: the budget now admits exactly {target} \
more bytes"
);
}
fn responder_at_the_cap(now: Instant) -> Solo {
let mut s = responder_at(now);
assert_eq!(
budget(&s),
(RESP_PACKET_LEN as u64, INIT_PACKET_LEN as u64),
"§3.2's second arming event, with the msg2 it provoked charged to it"
);
spend_to_the_cap(&mut s, now);
s
}
fn release_the_budget(s: &mut Solo, now: Instant) -> Drained {
s.deliver(now, &[])
}
fn ack_frame(largest: u64, ack_delay: u64, first_range: u64, pairs: &[(u64, u64)]) -> Vec<u8> {
let mut f = Vec::new();
put(&mut f, FRAME_ACK);
put(&mut f, largest);
put(&mut f, ack_delay);
put(&mut f, pairs.len() as u64);
put(&mut f, first_range);
for (gap, range) in pairs {
put(&mut f, *gap);
put(&mut f, *range);
}
f
}
fn path_response_frame(value: [u8; 8]) -> Vec<u8> {
let mut f = Vec::new();
put(&mut f, FRAME_PATH_RESPONSE);
f.extend_from_slice(&value);
f
}
fn has_ping(frames: &[Wire]) -> bool {
frames.iter().any(|f| matches!(f, Wire::Ping))
}
fn has_datagram(frames: &[Wire]) -> bool {
frames.iter().any(|f| matches!(f, Wire::Datagram { .. }))
}
fn contested_events(d: &Drained) -> usize {
d.count_events(|e| matches!(e, ConnEvent::Contested))
}
fn cleared_events(d: &Drained) -> usize {
d.count_events(|e| matches!(e, ConnEvent::ContestCleared))
}
fn assert_nothing_happened(s: &mut Solo, d: &Drained, why: &str) {
assert!(
d.transmits().is_empty(),
"{why}: §5.1 marking — NO PING. A probe left anyway"
);
assert_eq!(contested_events(d), 0, "{why}: §5.1 marking — NO EVENT");
assert_eq!(
cleared_events(d),
0,
"{why}: `ContestCleared` is emitted only where `Contested` was \
(ruling 176)"
);
assert_eq!(
s.conn.timer(TimerKind::Contested),
None,
"{why}: §5.1 marking — NO TIMER. §7.5 arms at the transmission, \
not at the mark"
);
assert!(
d.closed().is_none(),
"{why}: a mark the budget refuses is pending, not failed"
);
}
#[test]
fn a_responder_anchored_from_msg1_starts_unvalidated_with_the_msg1_credited() {
let t = t0();
let s = responder_at(t);
assert_eq!(
s.conn.amplification_budget(),
Some((RESP_PACKET_LEN as u64, INIT_PACKET_LEN as u64)),
"§3.2: armed at the msg1 anchor, the msg1 credited — *\"its \
handshake tail tags having verified at admission\"* — and **[A2]** \
the msg2 the endpoint already sent to it charged against it"
);
assert_eq!(
room(&s),
RESPONDER_CAP - RESP_PACKET_LEN as u64,
"the cap is AMPLIFICATION_FACTOR * INIT_PACKET_LEN = 588, of which \
the msg2's 107 bytes are already spent"
);
}
#[test]
fn a_dialled_connection_starts_validated_with_no_budget_armed() {
let t = t0();
let s = dialled_at(t);
assert_eq!(
s.conn.amplification_budget(),
None,
"§3.2: a `connect()`-supplied address is not armed"
);
}
#[test]
fn a_committed_roam_rearms_the_budget_and_credits_only_the_roaming_packet() {
let t = t0();
let mut s = responder_at(t);
let t1 = t + Duration::from_millis(500);
spend_to_the_cap(&mut s, t);
assert_eq!(budget(&s), (RESPONDER_CAP, INIT_PACKET_LEN as u64));
let d = s.deliver_from(t1, c_addr(), &[]);
assert_eq!(
s.conn.remote_address(),
Some(c_addr()),
"§7.3: the anchor moved"
);
assert_eq!(s.conn.path_generation(), 1, "§14.6: one committed roam");
assert_eq!(
d.count_events(|e| matches!(
e,
ConnEvent::AddressMoved { from, to } if *from == a_addr() && *to == c_addr()
)),
1,
"§16.4: exactly one `AddressMoved`, with §5.2's exact field names"
);
assert_eq!(
budget(&s),
(0, KEEPALIVE_PACKET_LEN),
"§3.1 step 5: *\"both counters reset, then the triggering packet's \
datagram length credits the received counter\"* — 30 bytes, not \
226, and `budget_sent` back to 0"
);
}
#[test]
fn nothing_leaves_and_nothing_is_emitted_at_a_mark_the_budget_will_not_admit() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
assert!(
room(&s) < PROBE_PACKET_LEN,
"premise: §7.3 will not admit a 31-byte probe"
);
let budget_before = budget(&s);
let d = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d, "at a mark the budget refuses");
assert_eq!(
budget(&s),
budget_before,
"§3.2: a HELD datagram is *\"not dropped, not truncated, not an \
error\"* — and it is not sent either, so it spends nothing"
);
}
#[test]
fn a_second_mark_while_pending_is_a_total_no_op() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t + Duration::from_secs(2);
let t3 = t + Duration::from_secs(3);
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "first mark");
let d2 = mark(&mut s, t2);
assert_nothing_happened(&mut s, &d2, "second mark while pending");
let d3 = release_the_budget(&mut s, t3);
let frames = s.drain_frames(&d3);
assert_eq!(
frames.iter().filter(|f| matches!(f, Wire::Ping)).count(),
1,
"ruling 41: two marks collapse into one probe"
);
assert_eq!(
contested_events(&d3),
1,
"ruling 41: one contested state, so one `Contested`"
);
}
#[test]
fn a_mark_on_a_closing_connection_is_a_total_no_op() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t + Duration::from_secs(2);
s.conn.close(t1, 0, b"");
let _ = drain(&mut s.conn);
let d1 = mark(&mut s, t1);
assert_eq!(contested_events(&d1), 0, "ruling 179: NOT marked");
assert_eq!(
s.conn.timer(TimerKind::Contested),
None,
"ruling 179: no deadline on a closing connection"
);
let d2 = release_the_budget(&mut s, t2);
let frames = s.drain_frames(&d2);
assert!(
!has_ping(&frames),
"ruling 179: no probe is owed, so none may leave when the budget \
opens"
);
assert_eq!(contested_events(&d2), 0, "ruling 179: and no notification");
}
#[test]
fn the_probe_the_notification_and_the_deadline_all_land_at_the_transmission_instant() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
assert_ne!(t1, t2, "the whole point of the test");
let challenge = s
.conn
.outstanding_challenge()
.expect("§7.3: an armed budget owes a challenge");
let floor = s.conn.next_counter().expect("installed");
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let in_flight_before = s.conn.bytes_in_flight();
let d2 = release_the_budget(&mut s, t2);
assert_eq!(
d2.transmits().len(),
1,
"ruling 250: the probe and the owed challenge are **one packet**"
);
let probe = d2.transmits().swap_remove(0);
assert_eq!(
probe.data.len() as u64,
COALESCED_PROBE_LEN,
"§7.3's own arithmetic, one header and one tag: 14 + 9 + 1 + 16 = \
40. The two-packet build pays 39 + 31"
);
let pt = s.peer.open_dgram(&probe.data);
let mut want = vec![FRAME_PATH_CHALLENGE as u8];
want.extend_from_slice(&challenge);
want.push(FRAME_PING as u8);
assert_eq!(
pt, want,
"§8.5 (ruling 208): the path frames are **first among the control \
frames**, PING is last among length-prefixed frames — so the nine \
challenge bytes precede the one PING byte **inside one plaintext**"
);
assert_eq!(
packet_counter(&probe.data),
floor,
"ruling 250: *\"the probe takes the floor counter again\"* — a \
build that seals the path frames in their own packet first leaves \
the probe on `floor + 1`"
);
assert_eq!(
s.conn.next_counter().expect("installed"),
floor + 1,
"one packet, **one counter**: the pre-pass build consumed two"
);
assert_eq!(
s.conn.bytes_in_flight(),
in_flight_before + COALESCED_PROBE_LEN,
"one **sent-map entry** — ruling 43's *\"exempt from admission, \
never from accounting\"* applies to the packet as built, so the \
two-packet build shows 39 + 31 = 70 here"
);
for t in d2.transmits() {
assert_eq!(t.to, a_addr(), "§5.6: aimed at the anchor");
}
assert_eq!(
contested_events(&d2),
1,
"§5.1 transmission step 3: `Contested` is queued **here**, not at \
the mark (rulings 45/46, FAB-6)"
);
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t2 + KEEPALIVE_TIMEOUT),
"§5.1 transmission step 2: `armed_at` is the transmission instant, \
so the deadline is t2 + 10 s — **not** t1 + 10 s"
);
assert_ne!(
s.conn.timer(TimerKind::Contested),
Some(t1 + KEEPALIVE_TIMEOUT),
"stated from the other side: a build arming at the mark fails here"
);
let ping_at = d2
.position(|o| matches!(o, ConnOutput::Transmit(_)))
.expect("the probe");
let event_at = d2
.position(|o| matches!(o, ConnOutput::Event(ConnEvent::Contested)))
.expect("the notification");
assert!(
ping_at < event_at,
"§12.2: `Transmit(PING)` … then `Event(Contested)` — *\"in that \
order\"*"
);
}
#[test]
fn a_response_that_validates_the_address_releases_the_probe_without_clearing_the_mark() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
let highest_sealed = s.conn.next_counter().expect("installed") - 1;
assert_eq!(
highest_sealed, 0,
"premise: the shaping datagram is the only packet sealed so far"
);
let challenge = s
.conn
.outstanding_challenge()
.expect("an armed budget owes a challenge");
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let d2 = s.deliver(t2, &ack_frame(0, 0, 0, &[]));
assert!(
s.conn.amplification_budget().is_some(),
"**[ruling 208]** an ACK validates no address: `largest` is an \
assertion by whoever holds the key, and §7.3's roaming threat \
model *is* the key holder. A build that kept the old predicate \
beside the new one leaves the bypass unlocked"
);
assert_eq!(
cleared_events(&d2),
0,
"ruling 41: `probe_floor` is 1; an ACK covering only 0 clears \
nothing"
);
let frames = s.drain_frames(&d2);
assert!(
has_ping(&frames),
"the mark survived and the credited budget admits the probe, so \
§7.5's PING leaves at this instant"
);
assert_eq!(contested_events(&d2), 1, "and `Contested` fires with it");
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t2 + KEEPALIVE_TIMEOUT),
"armed at the transmission, as always"
);
let t3 = t2 + Duration::from_secs(1);
let d3 = s.deliver(t3, &path_response_frame(challenge));
assert_eq!(
s.conn.amplification_budget(),
None,
"**[ruling 208]** an authenticated, window-fresh packet from the \
anchor carrying a `PATH_RESPONSE` that echoes the arming's \
challenge is the return-routability proof — the address is \
validated and the budget disarms"
);
assert_eq!(
cleared_events(&d3),
0,
"a `PATH_RESPONSE` covers no counter at all, so §7.5's probe floor \
is untouched and the verdict is still outstanding"
);
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t2 + KEEPALIVE_TIMEOUT),
"…and the deadline still stands at the transmission instant"
);
}
#[test]
fn a_pending_probe_outranks_a_queued_datagram_when_the_budget_admits_only_one() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t + Duration::from_secs(2);
let released_room = AMPLIFICATION_FACTOR * KEEPALIVE_PACKET_LEN;
let payload = (released_room - PKT_OVERHEAD - 1) as usize;
s.conn
.send_datagram(t1, &ramp(7, payload))
.expect("§11: accepted into the send queue");
let held = drain(&mut s.conn);
assert!(
held.transmits().is_empty(),
"§3.2: the budget HELD it — *\"not dropped, not truncated, not an \
error\"*"
);
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark, with a datagram queued");
let d2 = release_the_budget(&mut s, t2);
assert_eq!(
room(&s)
+ d2.transmits()
.iter()
.map(|x| x.data.len() as u64)
.sum::<u64>(),
released_room,
"premise: exactly 90 bytes were released and this drain spent from \
them"
);
let frames = s.drain_frames(&d2);
assert!(
has_ping(&frames),
"ruling 171(a): the pending probe goes first, ahead of new Data"
);
assert!(
!has_datagram(&frames),
"…and the datagram waits, because 91 bytes of PING+DATAGRAM do not \
fit in 90 (ruling 181's packing is the reason this is a real \
choice and not an artefact)"
);
}
#[test]
fn an_ack_above_the_highest_sealed_counter_does_not_clear_a_pending_mark() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
let floor = s.conn.next_counter().expect("installed");
let highest_sealed = floor - 1;
assert_eq!(
highest_sealed, 0,
"premise: the floor recorded at the mark is one above the highest \
counter ever sealed — which is the whole difficulty"
);
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let d2 = s.deliver(t2, &ack_frame(floor, 0, floor, &[]));
assert_eq!(
cleared_events(&d2),
0,
"§12.5: an ACK above the highest sealed counter is ignored whole, \
so it covers nothing and clears nothing"
);
let frames = s.drain_frames(&d2);
assert!(
has_ping(&frames),
"the mark is intact, and the packet's own 35 bytes lifted the cap \
by 105 — so the probe leaves here"
);
assert_eq!(contested_events(&d2), 1, "at the transmission, once");
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t2 + KEEPALIVE_TIMEOUT),
);
}
#[test]
fn a_roam_while_pending_leaves_the_mark_intact_and_the_probe_still_goes_out() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let d2 = s.deliver_from(t2, c_addr(), &[]);
assert_eq!(
s.conn.remote_address(),
Some(c_addr()),
"premise: the roam committed"
);
assert_eq!(s.conn.path_generation(), 1, "premise: one committed roam");
assert_eq!(
cleared_events(&d2),
0,
"ruling 176: a roam is not a clear — and `ContestCleared` is \
emitted only where `Contested` was"
);
let frames = s.drain_frames(&d2);
assert!(
has_ping(&frames),
"ruling 176: the mark survived the roam, and the re-armed budget \
(sent = 0, cap = 90) admits the 31-byte probe"
);
assert_eq!(
contested_events(&d2),
1,
"one mark, one probe, one `Contested` — at the transmission"
);
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t2 + KEEPALIVE_TIMEOUT),
"armed at this transmission, not at the mark and not at the roam \
being a separate event"
);
assert_eq!(
d2.transmits()[0].to,
c_addr(),
"§7.3: and it is aimed at the new anchor"
);
}
#[test]
fn an_ack_covering_the_floor_while_armed_clears_the_mark_and_disarms_the_deadline() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
let t3 = t2 + Duration::from_secs(1);
let floor = s.conn.next_counter().expect("installed");
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let d2 = release_the_budget(&mut s, t2);
assert!(
has_ping(&s.drain_frames(&d2)),
"premise: the probe went out"
);
assert_eq!(contested_events(&d2), 1, "premise: armed");
let highest = s.conn.next_counter().expect("installed") - 1;
assert_eq!(
highest, floor,
"ruling 250: one packet, one counter — the probe is sealed **at** \
the mark's floor ({highest} against {floor})"
);
let d3 = s.deliver(t3, &ack_frame(highest, 0, highest, &[]));
assert_eq!(
cleared_events(&d3),
1,
"§5.1 `Armed`: `ContestCleared` is queued"
);
assert_eq!(
contested_events(&d3),
0,
"and no second `Contested` — ruling 46 removed the bool precisely \
so the two could not be read as one toggle"
);
assert_eq!(
s.conn.timer(TimerKind::Contested),
None,
"§5.1 `Armed`: the verdict deadline is disarmed"
);
assert!(d3.closed().is_none(), "§7.5: the connection lives");
}
#[test]
fn a_second_mark_while_armed_does_not_move_the_deadline() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
let t3 = t2 + Duration::from_secs(1);
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let d2 = release_the_budget(&mut s, t2);
assert!(has_ping(&s.drain_frames(&d2)), "premise: armed");
let d3 = mark(&mut s, t3);
assert!(
!has_ping(&s.drain_frames(&d3)),
"§5.1 `Armed`: no second PING"
);
assert_eq!(contested_events(&d3), 0, "§5.1 `Armed`: no event");
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t2 + KEEPALIVE_TIMEOUT),
"§5.1 `Armed`: the deadline is NOT re-armed — still the *first* \
transmission's, not t3's"
);
}
#[test]
fn the_verdict_closes_the_connection_transmits_nothing_and_emits_no_third_notification() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let d2 = release_the_budget(&mut s, t2);
assert!(has_ping(&s.drain_frames(&d2)), "premise: armed");
let deadline = t2 + KEEPALIVE_TIMEOUT;
assert_eq!(s.conn.timer(TimerKind::Contested), Some(deadline));
let _ = s.deliver(t2 + Duration::from_secs(1), &[]);
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(deadline),
"an ordinary receive does not move the verdict deadline"
);
tick(&mut s.conn, deadline - Duration::from_millis(1));
let early = drain(&mut s.conn);
assert!(
early.closed().is_none(),
"one millisecond before the deadline the verdict has not been \
reached"
);
tick(&mut s.conn, deadline);
let d = drain(&mut s.conn);
assert_eq!(
d.closed(),
Some(ConnectionLost::TimedOut),
"§15.4: the same variant as liveness — **no new one**"
);
assert_eq!(
contested_events(&d) + cleared_events(&d),
0,
"§7.5: *\"No third notification\"* — a mark that is never answered \
emits `Contested` at the transmission and then nothing; the death \
arrives on `closed()`. Deliberately **not** asserted as \"no other \
event of any kind\": §7.5 claims only that this pair is silent, and \
a teardown may legitimately wake other machinery"
);
assert!(
d.outs
.iter()
.any(|o| matches!(o, ConnOutput::ToEndpoint(ToEndpoint::Retired { .. }))),
"§5.1 verdict step 2: `ToEndpoint::Retired` in the same drain"
);
assert!(
d.transmits().is_empty(),
"§5.1 verdict step 3: **nothing is transmitted**"
);
}
#[test]
fn the_pending_gap_is_reachable_by_roaming_too() {
let t = t0();
let mut s = responder_at(t);
let t1 = t + Duration::from_secs(1);
let t2 = t + Duration::from_secs(2);
let t3 = t + Duration::from_secs(3);
let roamed = s.deliver_from(t1, c_addr(), &[]);
assert_eq!(
roamed.count_events(|e| matches!(e, ConnEvent::AddressMoved { .. })),
1,
"premise: the roam committed"
);
assert_eq!(budget(&s), (0, KEEPALIVE_PACKET_LEN));
spend_to_the_cap(&mut s, t1);
assert!(room(&s) < PROBE_PACKET_LEN, "premise: the budget refuses");
let d1 = mark(&mut s, t2);
assert_nothing_happened(&mut s, &d1, "a mark after a roam");
let d2 = s.deliver_from(t3, c_addr(), &[]);
assert!(
has_ping(&s.drain_frames(&d2)),
"§7.5: *\"the endpoint sends it, and arms, at the first instant the \
budget allows\"*"
);
assert_eq!(contested_events(&d2), 1);
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t3 + KEEPALIVE_TIMEOUT),
"the transmission instant, three seconds after the mark's"
);
}
#[test]
fn a_room_that_admits_the_bare_probe_but_not_the_coalesced_one_sends_the_probe_alone() {
let t = t0();
let mut s = responder_at(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(1);
let challenge = s
.conn
.outstanding_challenge()
.expect("§7.3: an armed budget owes a challenge");
spend_leaving(&mut s, t, COALESCED_PROBE_LEN - 1);
assert!(
room(&s) >= PROBE_PACKET_LEN,
"premise: the bare 31-byte probe fits"
);
assert!(
room(&s) < COALESCED_PROBE_LEN,
"premise: …and the 40-byte coalesced one does not — this is the \
whole band"
);
assert_eq!(
room(&s),
PKT_OVERHEAD + 9,
"premise, stated the other way: the room is exactly a dedicated \
challenge datagram, so the pre-250 pre-pass fits and spends it all"
);
let d = mark(&mut s, t1);
assert_eq!(
d.transmits().len(),
1,
"§7.3 rank 2 beats rank 4: one packet leaves, and it is the probe"
);
let probe = d.transmits().swap_remove(0);
assert_eq!(
probe.data.len() as u64,
PROBE_PACKET_LEN,
"*\"emits the bare 31 B PING otherwise\"*"
);
assert_eq!(
s.peer.open_dgram(&probe.data),
vec![FRAME_PING as u8],
"and nothing rides with it: the coalesced form did not fit, so the \
challenge is not trimmed into the packet in some partial shape"
);
assert_eq!(
contested_events(&d),
1,
"§5.1 transmission step 3 — the verdict is **not** deferred by a \
frame ranked below the probe"
);
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t1 + KEEPALIVE_TIMEOUT),
"…and step 2 arms here, at the probe's own transmission"
);
assert_eq!(
room(&s),
(COALESCED_PROBE_LEN - 1) - PROBE_PACKET_LEN,
"39 admitted, 31 spent: 8 left, which admits neither path frame"
);
assert_eq!(
s.conn.outstanding_challenge(),
Some(challenge),
"§8.7: the challenge is **owed for as long as the arming lasts** — \
a probe that could not carry it does not discharge it"
);
let d2 = s.deliver(t2, &[FRAME_PING as u8]);
let mut frames = s.drain_frames(&d2);
if let Some(at) = s.conn.timer(TimerKind::AckDelay) {
s.conn.handle_timeout(at);
let d3 = drain(&mut s.conn);
let more = s.drain_frames(&d3);
frames.extend(more);
}
assert!(
frames
.iter()
.any(|f| matches!(f, Wire::PathChallenge(v) if *v == challenge)),
"the same eight bytes, on the first packet room admitted after the \
probe — a build that drops an uncoalescable challenge leaves the \
address unvalidated for ever. Frames: {frames:?}"
);
}
#[test]
fn both_owed_path_frames_ride_the_probe_in_one_packet_in_spec_8_5_order() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t1 + Duration::from_secs(3);
let armed_at_the_anchor = s
.conn
.outstanding_challenge()
.expect("§3.2: the msg1 anchor armed one");
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark");
let peer_value = [0x3c, 0x2b, 0x1a, 0x09, 0xf8, 0xe7, 0xd6, 0xc5];
let d2 = s.deliver_from(t2, c_addr(), &path_challenge_frame(peer_value));
assert_eq!(
s.conn.remote_address(),
Some(c_addr()),
"premise: the roam committed"
);
let fresh = s
.conn
.outstanding_challenge()
.expect("§7.3: the new arming draws one");
assert_ne!(
fresh, armed_at_the_anchor,
"§7.3: **one challenge per arming, never reused across armings**"
);
let (_, recv) = budget(&s);
assert!(
AMPLIFICATION_FACTOR * recv >= COALESCED_PROBE_BOTH_LEN,
"premise: the re-armed cap admits 49 bytes — 3 × the 39-byte \
roaming packet is 117"
);
for t in d2.transmits() {
assert_eq!(t.to, c_addr(), "§7.3: aimed at the new anchor");
}
let packets = s.packets(&d2);
let probes: Vec<&Vec<Wire>> = packets
.iter()
.filter(|p| p.iter().any(|f| matches!(f, Wire::Ping)))
.collect();
assert_eq!(
probes.len(),
1,
"premise: §7.5 emits one probe. Packets: {packets:?}"
);
let carried: Vec<Wire> = probes[0]
.iter()
.filter(|f| !matches!(f, Wire::Ack { .. }))
.cloned()
.collect();
assert_eq!(
carried,
vec![
Wire::PathResponse(peer_value),
Wire::PathChallenge(fresh),
Wire::Ping,
],
"ruling 250: *\"One packet, one counter, one sent-map entry\"* — \
the response, the challenge and the PING are **one packet**, in \
§8.5's order: path frames first among the control frames, \
`PATH_RESPONSE` before `PATH_CHALLENGE` (*\"answering an \
obligation before raising one\"*), PING last. The pre-250 pre-pass \
puts both path frames in a datagram of their own and leaves the \
probe carrying `[Ping]`. Packets: {packets:?}"
);
let responses = packets
.iter()
.flatten()
.filter(|f| matches!(f, Wire::PathResponse(_)))
.count();
let challenges = packets
.iter()
.flatten()
.filter(|f| matches!(f, Wire::PathChallenge(_)))
.count();
assert_eq!(
(responses, challenges),
(1, 1),
"…and **one** of each across the whole drain: a build that \
coalesces them into the probe *and* keeps the dedicated packet \
pays 79 bytes of a 117-byte budget for 19 bytes of frames"
);
assert_eq!(
contested_events(&d2),
1,
"one mark, one probe, one `Contested`, at this transmission"
);
assert_eq!(
s.conn.timer(TimerKind::Contested),
Some(t2 + KEEPALIVE_TIMEOUT),
"armed at the coalesced packet's instant"
);
}
#[test]
fn an_admitted_probe_does_not_stop_the_pump_on_that_pass() {
let t = t0();
let mut s = responder_at_the_cap(t);
let t1 = t + Duration::from_secs(1);
let t2 = t + Duration::from_secs(2);
let r = s.conn.open(Dir::Uni).expect("a uni stream");
write_all(&mut s.conn, t1, r, &ramp(0, 2_000));
let held = drain(&mut s.conn);
assert!(
held.transmits().is_empty(),
"premise: room is 0, so §7.3 holds the stream bytes"
);
let d1 = mark(&mut s, t1);
assert_nothing_happened(&mut s, &d1, "the mark, with stream data queued");
let d2 = s.deliver(t2, &vec![FRAME_PADDING as u8; MAX_PLAINTEXT]);
let packets = s.packets(&d2);
assert!(
!packets.is_empty(),
"premise: the released room admits output"
);
assert!(
packets[0].iter().any(|f| matches!(f, Wire::Ping)),
"ruling 250(i): the probe is built **first**, at rank 2 — the \
pre-pass build's first packet is the dedicated challenge. Packet: \
{:?}",
packets[0]
);
assert!(
packets[0]
.iter()
.any(|f| matches!(f, Wire::PathChallenge(_))),
"…carrying the owed challenge with it, since 3600 bytes admit the \
coalesced 40. Packet: {:?}",
packets[0]
);
assert!(
packets
.iter()
.flatten()
.any(|f| matches!(f, Wire::Stream { .. })),
"…and the pump **continues on the same pass**: the early return is \
gone, so rank 9 leaves in this drain. Packets: {packets:?}"
);
assert_eq!(
contested_events(&d2),
1,
"one probe, one `Contested`, whatever else left beside it"
);
}
#[test]
fn the_coalesced_probe_keeps_the_probes_cwnd_exemption() {
let t = t0();
let mut s = responder_at(t);
let t1 = t + Duration::from_millis(10);
let challenge = s
.conn
.outstanding_challenge()
.expect("§7.3: an armed budget owes a challenge");
for _ in 0..8 {
let d = s.deliver(t, &vec![FRAME_PADDING as u8; MAX_PLAINTEXT]);
assert!(
d.transmits().is_empty(),
"PADDING elicits nothing, so nothing is owed and no packet is \
manufactured to carry a challenge (§8.7's boundary)"
);
}
let r = s.conn.open(Dir::Uni).expect("a uni stream");
write_all(&mut s.conn, t, r, &ramp(0, 24_000));
let _ = drain(&mut s.conn);
let idle = drain(&mut s.conn);
assert!(
idle.transmits().is_empty(),
"premise: the gate has closed on the queued remainder"
);
let in_flight = s.conn.bytes_in_flight();
assert!(
in_flight + COALESCED_PROBE_LEN > s.conn.congestion_window(),
"premise: §14.5's gate refuses a 40-byte candidate — {in_flight} \
in flight against a {} window",
s.conn.congestion_window()
);
assert!(
room(&s) >= COALESCED_PROBE_LEN,
"premise: and §7.3's budget does **not** refuse it, so cwnd is the \
only constraint under test"
);
let d = mark(&mut s, t1);
assert_eq!(
d.transmits().len(),
1,
"§14.5: the probe is exempt from the admission gate, and ruling \
250(iv) says the exemption covers the packet **as built**"
);
let probe = d.transmits().swap_remove(0);
assert_eq!(
probe.data.len() as u64,
COALESCED_PROBE_LEN,
"the challenge rides the exempt packet: a build that leaves the \
path frames on the gated path emits 31 here and the address stays \
unvalidated until the window opens"
);
let mut want = vec![FRAME_PATH_CHALLENGE as u8];
want.extend_from_slice(&challenge);
want.push(FRAME_PING as u8);
assert_eq!(s.peer.open_dgram(&probe.data), want, "§8.5's order");
assert_eq!(
s.conn.bytes_in_flight(),
in_flight + COALESCED_PROBE_LEN,
"ruling 43: exempt from **admission**, never from accounting — the \
piggyback is 18 B at most and §17.5's bound still covers it"
);
assert_eq!(contested_events(&d), 1, "and the verdict deadline arms");
}