in src/dumbo/src/pdu/tcp.rs [635:809]
fn test_constructors() {
let mut a = [1u8; 1460];
let b = [2u8; 1000];
let c = [3u8; 2000];
let src_addr = Ipv4Addr::new(10, 1, 2, 3);
let dst_addr = Ipv4Addr::new(192, 168, 44, 77);
let src_port = 1234;
let dst_port = 5678;
let seq_number = 11_111_222;
let ack_number = 34_566_543;
let flags_after_ns = Flags::SYN | Flags::RST;
let window_size = 19999;
let mss_left = 1460;
let mss_option = Some(mss_left);
let payload = Some((b.as_ref(), b.len()));
let header_len = OPTIONS_OFFSET + OPTION_LEN_MSS;
let segment_len = {
let mut segment = TcpSegment::write_segment(
a.as_mut(),
src_port,
dst_port,
seq_number,
ack_number,
flags_after_ns,
window_size,
mss_option,
mss_left,
payload,
Some((src_addr, dst_addr)),
)
.unwrap();
assert_eq!(segment.source_port(), src_port);
assert_eq!(segment.destination_port(), dst_port);
assert_eq!(segment.sequence_number(), seq_number);
assert_eq!(segment.ack_number(), ack_number);
assert_eq!(segment.header_len_rsvd_ns(), (header_len, 0, false));
assert_eq!(segment.flags_after_ns(), flags_after_ns);
assert_eq!(segment.window_size(), window_size);
let checksum = segment.checksum();
segment.set_checksum(0);
let computed_checksum = segment.compute_checksum(src_addr, dst_addr);
assert_eq!(checksum, computed_checksum);
segment.set_checksum(checksum);
assert_eq!(segment.compute_checksum(src_addr, dst_addr), 0);
assert_eq!(segment.urgent_pointer(), 0);
{
let options = segment.options_unchecked(header_len);
assert_eq!(options.len(), OPTION_LEN_MSS);
assert_eq!(options[0], OPTION_KIND_MSS);
assert_eq!(options[1], OPTION_LEN_MSS as u8);
assert_eq!(options.ntohs_unchecked(2), mss_left);
}
// Payload was smaller than mss_left after options.
assert_eq!(segment.len(), header_len + b.len());
segment.len()
// Mutable borrow of a goes out of scope.
};
{
let segment =
TcpSegment::from_bytes(&a[..segment_len], Some((src_addr, dst_addr))).unwrap();
assert_eq!(
segment.parse_mss_option_unchecked(header_len),
Ok(Some(NonZeroU16::new(mss_left as u16).unwrap()))
);
}
// Let's quickly see what happens when the payload buf is larger than our mutable slice.
{
let segment_len = TcpSegment::write_segment(
a.as_mut(),
src_port,
dst_port,
seq_number,
ack_number,
flags_after_ns,
window_size,
mss_option,
mss_left,
Some((c.as_ref(), c.len())),
Some((src_addr, dst_addr)),
)
.unwrap()
.len();
assert_eq!(segment_len, mss_left as usize);
}
// Now let's test the error value for from_bytes().
// Using a helper function here instead of a closure because it's hard (impossible?) to
// specify lifetime bounds for closure arguments.
fn p(buf: &mut [u8]) -> TcpSegment<&mut [u8]> {
TcpSegment::from_bytes_unchecked(buf)
}
// Just a helper closure.
let look_for_error = |buf: &[u8], err: Error| {
assert_eq!(
TcpSegment::from_bytes(buf, Some((src_addr, dst_addr))).unwrap_err(),
err
);
};
// Header length too short.
p(a.as_mut()).set_header_len_rsvd_ns(OPTIONS_OFFSET.checked_sub(1).unwrap(), false);
look_for_error(a.as_ref(), Error::HeaderLen);
// Header length too large.
p(a.as_mut()).set_header_len_rsvd_ns(MAX_HEADER_LEN.checked_add(4).unwrap(), false);
look_for_error(a.as_ref(), Error::HeaderLen);
// The previously set checksum should be valid.
assert_eq!(
p(a.as_mut())
.set_header_len_rsvd_ns(header_len, false)
.compute_checksum(src_addr, dst_addr),
0
);
// Let's make it invalid.
let checksum = p(a.as_mut()).checksum();
p(a.as_mut()).set_checksum(checksum.wrapping_add(1));
look_for_error(a.as_ref(), Error::Checksum);
// Now we use a very small buffer.
let mut small_buf = [0u8; 1];
look_for_error(small_buf.as_ref(), Error::SliceTooShort);
assert_eq!(
TcpSegment::write_segment(
small_buf.as_mut(),
src_port,
dst_port,
seq_number,
ack_number,
flags_after_ns,
window_size,
mss_option,
mss_left,
payload,
Some((src_addr, dst_addr)),
)
.unwrap_err(),
Error::SliceTooShort
);
// Make sure we get the proper error for an insufficient value of mss_remaining.
assert_eq!(
TcpSegment::write_segment(
small_buf.as_mut(),
src_port,
dst_port,
seq_number,
ack_number,
flags_after_ns,
window_size,
mss_option,
0,
payload,
Some((src_addr, dst_addr)),
)
.unwrap_err(),
Error::MssRemaining
);
}