fn test_endpoint()

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);
        }
    }