From 7bc9f9b47f61faa21c6504cde215ece5e07a9f5e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 28 Aug 2020 05:31:46 -0700 Subject: Add test demonstrating accept bug Updates #3780. PiperOrigin-RevId: 328922573 --- test/syscalls/linux/socket_inet_loopback.cc | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'test/syscalls/linux') 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(&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(&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(&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(&accept_addr), &addrlen), + SyscallFailsWithErrno(ENOTCONN)); + return; + } + + conn_fd = ASSERT_NO_ERRNO_AND_VALUE(Accept( + listen_fd.get(), reinterpret_cast(&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) { -- cgit v1.2.3