in src/dumbo/src/tcp/endpoint.rs [371:569]
fn test_endpoint() {
let mut buf1 = [0u8; 500];
let mut buf2 = [0u8; 500];
let mut write_buf = [0u8; RCV_BUF_MAX_SIZE + 100];
let mut t = ConnectionTester::new();
let mut syn = t.write_syn(buf1.as_mut());
// Put another flag on the SYN so it becomes invalid.
syn.set_flags_after_ns(TcpFlags::ACK);
assert_eq!(
Endpoint::new_with_defaults(&syn).unwrap_err(),
PassiveOpenError::InvalidSyn
);
// Fix the SYN and create an endpoint.
syn.set_flags_after_ns(TcpFlags::SYN);
let remote_isn = syn.sequence_number();
let mut e = Endpoint::new_with_defaults(&syn).unwrap();
// Let's complete the three-way handshake. The next segment sent by the endpoint should
// be a SYNACK.
assert_eq!(e.next_segment_status(), NextSegmentStatus::Available);
let endpoint_isn = {
// We need this block to delimit the mut borrow of write_buf.
let s = e
.write_next_segment(write_buf.as_mut(), t.mss_reserved)
.unwrap();
assert_eq!(s.inner().flags_after_ns(), TcpFlags::SYN | TcpFlags::ACK);
s.inner().sequence_number()
};
// A RTO should be pending until the SYNACK is ACKed.
if let NextSegmentStatus::Timeout(_) = e.next_segment_status() {
assert_eq!(
e.next_segment_status(),
e.connection().control_segment_or_timeout_status()
);
} else {
panic!("missing expected timeout.");
}
// And now we ACK the SYNACK.
let mut ctrl = t.write_ctrl(buf2.as_mut());
ctrl.set_flags_after_ns(TcpFlags::ACK);
ctrl.set_ack_number(endpoint_isn.wrapping_add(1));
assert!(!e.connection.is_established());
e.receive_segment(&ctrl, mock_callback);
assert!(e.connection.is_established());
// Also, there should be nothing to send now anymore, nor any timeout pending.
assert_eq!(e.next_segment_status(), NextSegmentStatus::Nothing);
// Incomplete because it's missing the newlines at the end.
let incomplete_request = b"GET http://169.254.169.255/asdfghjkl HTTP/1.1";
{
let mut data = t.write_data(write_buf.as_mut(), incomplete_request.as_ref());
data.set_flags_after_ns(TcpFlags::ACK);
data.set_sequence_number(remote_isn.wrapping_add(1));
data.set_ack_number(endpoint_isn.wrapping_add(1));
e.receive_segment(&data, mock_callback);
}
assert_eq!(e.receive_buf_left, incomplete_request.len());
// 1 for the SYN.
let mut remote_first_not_sent =
remote_isn.wrapping_add(1 + incomplete_request.len() as u32);
// The endpoint should write an ACK at this point.
{
assert_eq!(e.next_segment_status(), NextSegmentStatus::Available);
let s = e
.write_next_segment(write_buf.as_mut(), t.mss_reserved)
.unwrap();
assert_eq!(s.inner().flags_after_ns(), TcpFlags::ACK);
assert_eq!(s.inner().ack_number(), remote_first_not_sent);
}
// There should be nothing else to send.
assert_eq!(e.next_segment_status(), NextSegmentStatus::Nothing);
let rest_of_the_request = b"\r\n\r\n";
// Let's also send the newlines.
{
let mut data = t.write_data(write_buf.as_mut(), rest_of_the_request.as_ref());
data.set_flags_after_ns(TcpFlags::ACK);
data.set_sequence_number(remote_first_not_sent);
data.set_ack_number(endpoint_isn + 1);
e.receive_segment(&data, mock_callback);
}
remote_first_not_sent =
remote_first_not_sent.wrapping_add(rest_of_the_request.len() as u32);
let mut endpoint_first_not_sent;
// We should get a data segment that also ACKs the latest bytes received.
{
assert_eq!(e.next_segment_status(), NextSegmentStatus::Available);
let s = e
.write_next_segment(write_buf.as_mut(), t.mss_reserved)
.unwrap();
assert_eq!(s.inner().flags_after_ns(), TcpFlags::ACK);
assert_eq!(s.inner().ack_number(), remote_first_not_sent);
let response = from_utf8(s.inner().payload()).unwrap();
// The response should contain "200" because the HTTP request is correct.
assert!(response.contains("200"));
endpoint_first_not_sent = s
.inner()
.sequence_number()
.wrapping_add(s.inner().payload_len() as u32);
}
// Cool, now let's check that even though receive_buf is limited to some value, we can
// respond to any number of requests, as long as each fits individually inside the buffer.
// We're going to use the simple approach where we send the same request over and over
// again, for a relatively large number of iterations.
let complete_request = b"GET http://169.254.169.255/asdfghjkl HTTP/1.1\r\n\r\n";
let last_request = b"GET http://169.254.169.255/asdfghjkl HTTP/1.1\r\n\r\n123";
// Send one request for each byte in receive_buf, just to be sure.
let max_iter = e.receive_buf.len();
for i in 1..=max_iter {
// We want to use last_request for the last request.
let request = if i == max_iter {
last_request.as_ref()
} else {
complete_request.as_ref()
};
// Send request.
{
let mut data = t.write_data(write_buf.as_mut(), request);
data.set_flags_after_ns(TcpFlags::ACK);
data.set_sequence_number(remote_first_not_sent);
data.set_ack_number(endpoint_first_not_sent);
e.receive_segment(&data, mock_callback);
}
remote_first_not_sent = remote_first_not_sent.wrapping_add(request.len() as u32);
// Check response.
{
let s = e
.write_next_segment(write_buf.as_mut(), t.mss_reserved)
.unwrap();
assert_eq!(s.inner().flags_after_ns(), TcpFlags::ACK);
assert_eq!(s.inner().ack_number(), remote_first_not_sent);
let response = from_utf8(s.inner().payload()).unwrap();
assert!(response.contains("200"));
endpoint_first_not_sent =
endpoint_first_not_sent.wrapping_add(s.inner().payload_len() as u32);
}
}
// The value of receive_buf_left should be 3 right now, because of the trailing chars from
// last_request.
assert_eq!(e.receive_buf_left, 3);
// Unless the machine running the tests is super slow for some reason, we should be nowhere
// near the expiry of the eviction timer.
assert!(!e.is_evictable());
// Let's hack this a bit and change the eviction_threshold to 0.
e.set_eviction_threshold(0);
// The endpoint should be evictable now.
assert!(e.is_evictable());
// Finally, let's fill self.receive_buf with the following request, and see if we get the
// reset we expect on the next segment.
let request_to_fill = vec![0u8; RCV_BUF_MAX_SIZE - e.receive_buf_left];
{
// Hack: have to artificially increase t.mss to create this segment which is 2k+.
t.mss = RCV_BUF_MAX_SIZE as u16;
let mut data = t.write_data(write_buf.as_mut(), request_to_fill.as_ref());
data.set_flags_after_ns(TcpFlags::ACK);
data.set_sequence_number(remote_first_not_sent);
data.set_ack_number(endpoint_first_not_sent);
e.receive_segment(&data, mock_callback);
}
{
let s = e
.write_next_segment(write_buf.as_mut(), t.mss_reserved)
.unwrap();
assert_eq!(s.inner().flags_after_ns(), TcpFlags::RST);
}
}