summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/packetimpact/tests/tcp_outside_the_window_test.go18
-rw-r--r--test/syscalls/linux/tcp_socket.cc36
2 files changed, 54 insertions, 0 deletions
diff --git a/test/packetimpact/tests/tcp_outside_the_window_test.go b/test/packetimpact/tests/tcp_outside_the_window_test.go
index 1b041932a..8909a348e 100644
--- a/test/packetimpact/tests/tcp_outside_the_window_test.go
+++ b/test/packetimpact/tests/tcp_outside_the_window_test.go
@@ -84,6 +84,24 @@ func TestTCPOutsideTheWindow(t *testing.T) {
if tt.expectACK && err != nil {
t.Fatalf("expected an ACK packet within %s but got none: %s", timeout, err)
}
+ // Data packets w/o SYN bits are always acked by Linux. Netstack ACK's data packets
+ // always right now. So only send a second segment and test for no ACK for packets
+ // with no data.
+ if tt.expectACK && tt.payload == nil {
+ // Sending another out-of-window segment immediately should not trigger
+ // an ACK if less than 500ms(default rate limit for out-of-window ACKs)
+ // has passed since the last ACK was sent.
+ t.Logf("sending another segment")
+ conn.Send(t, testbench.TCP{
+ Flags: testbench.Uint8(tt.tcpFlags),
+ SeqNum: testbench.Uint32(uint32(conn.LocalSeqNum(t).Add(windowSize))),
+ }, tt.payload...)
+ timeout := 3 * time.Second
+ gotACK, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), AckNum: localSeqNum}, timeout)
+ if err == nil {
+ t.Fatalf("expected no ACK packet but got one: %s", gotACK)
+ }
+ }
if !tt.expectACK && gotACK != nil {
t.Fatalf("expected no ACK packet within %s but got one: %s", timeout, gotACK)
}
diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc
index 9028ab024..f56c50e61 100644
--- a/test/syscalls/linux/tcp_socket.cc
+++ b/test/syscalls/linux/tcp_socket.cc
@@ -1168,6 +1168,42 @@ TEST_P(SimpleTcpSocketTest, SelfConnectSendRecv_NoRandomSave) {
EXPECT_EQ(read_bytes, kBufSz);
}
+TEST_P(SimpleTcpSocketTest, SelfConnectSend_NoRandomSave) {
+ // Initialize address to the loopback one.
+ sockaddr_storage addr =
+ ASSERT_NO_ERRNO_AND_VALUE(InetLoopbackAddr(GetParam()));
+ socklen_t addrlen = sizeof(addr);
+
+ const FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+
+ constexpr int max_seg = 256;
+ ASSERT_THAT(
+ setsockopt(s.get(), SOL_TCP, TCP_MAXSEG, &max_seg, sizeof(max_seg)),
+ SyscallSucceeds());
+
+ ASSERT_THAT(bind(s.get(), reinterpret_cast<struct sockaddr*>(&addr), addrlen),
+ SyscallSucceeds());
+ // Get the bound port.
+ ASSERT_THAT(
+ getsockname(s.get(), reinterpret_cast<struct sockaddr*>(&addr), &addrlen),
+ SyscallSucceeds());
+ ASSERT_THAT(RetryEINTR(connect)(
+ s.get(), reinterpret_cast<struct sockaddr*>(&addr), addrlen),
+ SyscallSucceeds());
+
+ std::vector<char> writebuf(512 << 10); // 512 KiB.
+
+ // Try to send the whole thing.
+ int n;
+ ASSERT_THAT(n = SendFd(s.get(), writebuf.data(), writebuf.size(), 0),
+ SyscallSucceeds());
+
+ // We should have written the whole thing.
+ EXPECT_EQ(n, writebuf.size());
+ EXPECT_THAT(shutdown(s.get(), SHUT_WR), SyscallSucceedsWithValue(0));
+}
+
TEST_P(SimpleTcpSocketTest, NonBlockingConnect) {
const FileDescriptor listener =
ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));