Skip to content

Commit f7d28ed

Browse files
authored
feat: add contains_handshake and assert_contains_handshake helpers (mozilla#3533)
* feat: add contains_handshake and assert_contains_handshake helpers Add helpers that scan through coalesced long-header packets in a datagram to find a Handshake packet. This reduces test fragility when packet sizing causes a small Initial to be coalesced before the Handshake. Follows the same scanning pattern as assert_no_1rtt. Fixes mozilla#3447 * test(transport): migrate pto_handshake_complete to assert_contains_handshake The two assertions after the server's second handshake burst were commented out because the datagram can contain a small coalesced Initial in front of the Handshake packet, which tripped the first-packet-only check in assert_handshake. Use the new assert_contains_handshake helper so the check is deterministic regardless of whether an Initial is coalesced at the front of the datagram. --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
1 parent dddf634 commit f7d28ed

2 files changed

Lines changed: 51 additions & 7 deletions

File tree

neqo-transport/src/connection/tests/recovery.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use std::time::{Duration, Instant};
99
use neqo_common::qdebug;
1010
use neqo_crypto::AuthenticationStatus;
1111
use test_fixture::{
12-
assertions::{assert_handshake, assert_initial, is_handshake, is_initial},
12+
assertions::{
13+
assert_contains_handshake, assert_handshake, assert_initial, is_handshake, is_initial,
14+
},
1315
now, split_datagram,
1416
};
1517

@@ -229,15 +231,15 @@ fn pto_handshake_complete() {
229231

230232
now += HALF_RTT;
231233
let pkt = server.process(pkt, now).dgram();
232-
// This is probably a Handshake packet, but it might also contain
233-
// extra Initial data at the start.
234-
// assert_handshake(pkt.as_ref().unwrap());
234+
// This datagram contains a Handshake packet, but it might also have
235+
// extra Initial data coalesced at the start.
236+
assert_contains_handshake(pkt.as_ref().unwrap());
235237

236238
now += HALF_RTT;
237239
let pkt = client.process(pkt, now).dgram();
238-
// ...and, if the Initial was sent in that last one,
239-
// this will acknowledge it.
240-
// assert_handshake(pkt.as_ref().unwrap());
240+
// ...and, if the Initial was sent in that last one, this will acknowledge
241+
// it, so a coalesced Initial may sit in front of the Handshake.
242+
assert_contains_handshake(pkt.as_ref().unwrap());
241243

242244
let cb = client.process_output(now).callback();
243245
// The client now has a single RTT estimate (20ms), so

test-fixture/src/assertions.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,48 @@ pub fn assert_handshake(payload: &[u8]) {
133133
assert!(is_handshake(payload));
134134
}
135135

136+
/// Check if a datagram contains a Handshake packet, scanning through coalesced
137+
/// long-header packets (e.g., an Initial followed by a Handshake).
138+
#[must_use]
139+
pub fn contains_handshake(payload: &[u8]) -> bool {
140+
let mut dec = Decoder::from(payload);
141+
while let Some(b1) = dec.decode_uint::<u8>() {
142+
if payload.iter().skip(dec.offset()).all(|b| *b == 0) {
143+
return false;
144+
}
145+
if b1 & 0x80 == 0 {
146+
return false; // Short header, no more long packets.
147+
}
148+
let Ok(version) = Version::try_from(dec.decode_uint::<version::Wire>().unwrap()) else {
149+
return false;
150+
};
151+
if is_long_packet_type(b1, 0b1010_0000, version) {
152+
return true;
153+
}
154+
dec.skip_vec(1); // DCID
155+
dec.skip_vec(1); // SCID
156+
let initial_type = if version == Version::Version2 {
157+
0b1001_0000
158+
} else {
159+
0b1000_0000
160+
};
161+
if (b1 & PACKET_TYPE_MASK) == initial_type {
162+
dec.skip_vvec(); // Initial token.
163+
}
164+
dec.skip_vvec(); // Skip the payload.
165+
}
166+
false
167+
}
168+
169+
/// Assert that a datagram contains a Handshake packet, scanning through
170+
/// coalesced long-header packets.
171+
pub fn assert_contains_handshake(payload: &[u8]) {
172+
assert!(
173+
contains_handshake(payload),
174+
"expected datagram to contain a Handshake packet"
175+
);
176+
}
177+
136178
pub fn assert_no_1rtt(payload: &[u8]) {
137179
let mut dec = Decoder::from(payload);
138180
while let Some(b1) = dec.decode_uint::<u8>() {

0 commit comments

Comments
 (0)