diff options
author | Bhasker Hariharan <bhaskerh@google.com> | 2020-10-09 18:59:48 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-10-09 19:02:03 -0700 |
commit | db36d948fa63ce950d94a5e8e9ebc37956543661 (patch) | |
tree | 123b5ab20650dbb5f79300a4d68d2d98e4c79cfe /test/syscalls | |
parent | d75fe7660a61a454ece9472658eac609b3bf61e6 (diff) |
TCP Receive window advertisement fixes.
The fix in commit 028e045da93b7c1c26417e80e4b4e388b86a713d was incorrect as
it can cause the right edge of the window to shrink when we announce
a zero window due to receive buffer being full as its done before the check
for seeing if the window is being shrunk because of the selected window.
Further the window was calculated purely on available space but in cases where
we are getting full sized segments it makes more sense to use the actual bytes
being held. This CL changes to use the lower of the total available space vs
the available space in the maximal window we could advertise minus the actual
payload bytes being held.
This change also cleans up the code so that the window selection logic is
not duplicated between getSendParams() and windowCrossedACKThresholdLocked.
PiperOrigin-RevId: 336404827
Diffstat (limited to 'test/syscalls')
-rw-r--r-- | test/syscalls/linux/tcp_socket.cc | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc index e0981e28a..9f522f833 100644 --- a/test/syscalls/linux/tcp_socket.cc +++ b/test/syscalls/linux/tcp_socket.cc @@ -903,6 +903,58 @@ TEST_P(SimpleTcpSocketTest, NonBlockingConnectNoListener) { EXPECT_EQ(err, ECONNREFUSED); } +TEST_P(SimpleTcpSocketTest, SelfConnectSendRecv_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)); + + 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()); + + constexpr int kBufSz = 1 << 20; // 1 MiB + std::vector<char> writebuf(kBufSz); + + // Start reading the response in a loop. + int read_bytes = 0; + ScopedThread t([&s, &read_bytes]() { + // Too many syscalls. + const DisableSave ds; + + char readbuf[2500] = {}; + int n = -1; + while (n != 0) { + ASSERT_THAT(n = RetryEINTR(read)(s.get(), &readbuf, sizeof(readbuf)), + SyscallSucceeds()); + read_bytes += n; + } + }); + + // Try to send the whole thing. + int n; + ASSERT_THAT(n = SendFd(s.get(), writebuf.data(), kBufSz, 0), + SyscallSucceeds()); + + // We should have written the whole thing. + EXPECT_EQ(n, kBufSz); + EXPECT_THAT(shutdown(s.get(), SHUT_WR), SyscallSucceedsWithValue(0)); + t.Join(); + + // We should have read the whole thing. + EXPECT_EQ(read_bytes, kBufSz); +} + TEST_P(SimpleTcpSocketTest, NonBlockingConnect) { const FileDescriptor listener = ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP)); |