diff options
Diffstat (limited to 'test/syscalls/linux/socket_inet_loopback.cc')
-rw-r--r-- | test/syscalls/linux/socket_inet_loopback.cc | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/test/syscalls/linux/socket_inet_loopback.cc b/test/syscalls/linux/socket_inet_loopback.cc index 67893033c..425084228 100644 --- a/test/syscalls/linux/socket_inet_loopback.cc +++ b/test/syscalls/linux/socket_inet_loopback.cc @@ -1111,6 +1111,82 @@ TEST_P(SocketInetLoopbackTest, AcceptedInheritsTCPUserTimeout) { EXPECT_EQ(get, kUserTimeout); } +TEST_P(SocketInetLoopbackTest, TCPAcceptAfterReset) { + auto const& param = GetParam(); + TestAddress const& listener = param.listener; + TestAddress const& connector = param.connector; + + // Create the listening socket. + const FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE( + Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP)); + sockaddr_storage listen_addr = listener.addr; + ASSERT_THAT(bind(listen_fd.get(), reinterpret_cast<sockaddr*>(&listen_addr), + listener.addr_len), + SyscallSucceeds()); + ASSERT_THAT(listen(listen_fd.get(), SOMAXCONN), SyscallSucceeds()); + + // Get the port bound by the listening socket. + { + socklen_t addrlen = listener.addr_len; + ASSERT_THAT( + getsockname(listen_fd.get(), reinterpret_cast<sockaddr*>(&listen_addr), + &addrlen), + SyscallSucceeds()); + } + + const uint16_t port = + ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr)); + + // Connect to the listening socket. + FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE( + Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP)); + + sockaddr_storage conn_addr = connector.addr; + ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port)); + ASSERT_THAT(RetryEINTR(connect)(conn_fd.get(), + reinterpret_cast<sockaddr*>(&conn_addr), + connector.addr_len), + SyscallSucceeds()); + + // Trigger a RST by turning linger off and closing the socket. + struct linger opt = { + .l_onoff = 1, + .l_linger = 0, + }; + ASSERT_THAT( + setsockopt(conn_fd.get(), SOL_SOCKET, SO_LINGER, &opt, sizeof(opt)), + SyscallSucceeds()); + ASSERT_THAT(close(conn_fd.release()), SyscallSucceeds()); + + // TODO(gvisor.dev/issue/3780): Remove this. + if (IsRunningOnGvisor()) { + // Wait for the RST to be observed. + absl::SleepFor(absl::Milliseconds(100)); + } + + sockaddr_storage accept_addr; + socklen_t addrlen = sizeof(accept_addr); + + // TODO(gvisor.dev/issue/3780): Remove this. + if (IsRunningOnGvisor()) { + ASSERT_THAT(accept(listen_fd.get(), + reinterpret_cast<sockaddr*>(&accept_addr), &addrlen), + SyscallFailsWithErrno(ENOTCONN)); + return; + } + + conn_fd = ASSERT_NO_ERRNO_AND_VALUE(Accept( + listen_fd.get(), reinterpret_cast<sockaddr*>(&accept_addr), &addrlen)); + ASSERT_EQ(addrlen, listener.addr_len); + + int err; + socklen_t optlen = sizeof(err); + ASSERT_THAT(getsockopt(conn_fd.get(), SOL_SOCKET, SO_ERROR, &err, &optlen), + SyscallSucceeds()); + ASSERT_EQ(err, ECONNRESET); + ASSERT_EQ(optlen, sizeof(err)); +} + // TODO(gvisor.dev/issue/1688): Partially completed passive endpoints are not // saved. Enable S/R once issue is fixed. TEST_P(SocketInetLoopbackTest, TCPDeferAccept_NoRandomSave) { |