From 5dde242a839647c8f615e51bf58f0a58009fa71f Mon Sep 17 00:00:00 2001 From: Alex Konradi Date: Mon, 20 Mar 2023 14:19:52 -0700 Subject: [PATCH] Add test for poll(POLLIN) on TCP around accept Add a test that asserts that POLLIN is set on a TCP listener when a new connection is available to be accepted and is unset after the connection is actually accepted. PiperOrigin-RevId: 518075095 --- test/syscalls/linux/tcp_socket.cc | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc index 59549dddc..932f4d254 100644 --- a/test/syscalls/linux/tcp_socket.cc +++ b/test/syscalls/linux/tcp_socket.cc @@ -994,6 +994,55 @@ TEST_P(TcpSocketTest, PollAfterShutdown) { SyscallSucceedsWithValue(1)); } +TEST_P(SimpleTcpSocketTest, PollAroundAccept) { + const FileDescriptor listener = + ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP)); + sockaddr_storage addr = + ASSERT_NO_ERRNO_AND_VALUE(InetLoopbackAddr(GetParam())); + socklen_t addrlen = sizeof(addr); + + // Bind to some port. + ASSERT_THAT(bind(listener.get(), AsSockAddr(&addr), addrlen), + SyscallSucceeds()); + ASSERT_THAT(listen(listener.get(), SOMAXCONN), SyscallSucceeds()); + + // Get the address we're bound to. We need to do this because we're allowing + // the stack to pick a port for us. + ASSERT_THAT(getsockname(listener.get(), AsSockAddr(&addr), &addrlen), + SyscallSucceeds()); + switch (GetParam()) { + case AF_INET: + ASSERT_EQ(addrlen, sizeof(sockaddr_in)); + break; + case AF_INET6: + ASSERT_EQ(addrlen, sizeof(sockaddr_in6)); + break; + } + + // Before the listener socket receives a connection, it should not be eligible + // for reading. + struct pollfd poll_fd = {listener.get(), POLLIN, 0}; + EXPECT_THAT(RetryEINTR(poll)(&poll_fd, /* nfds */ 1, /* timeout */ 0), + SyscallSucceedsWithValue(0)); + + FileDescriptor connector = + ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP)); + ASSERT_THAT(RetryEINTR(connect)(connector.get(), AsSockAddr(&addr), addrlen), + SyscallSucceeds()); + + // Now that a connection is pending, the listener is ready for a read. + ASSERT_THAT( + RetryEINTR(poll)(&poll_fd, /* nfds */ 1, /* infinite timeout */ -1), + SyscallSucceedsWithValue(1)); + + // Accept the connection. This should make the listener no longer ready for a + // read. + const FileDescriptor accepted = + ASSERT_NO_ERRNO_AND_VALUE(Accept(listener.get(), nullptr, nullptr)); + EXPECT_THAT(RetryEINTR(poll)(&poll_fd, /* nfds*/ 1, /* timeout */ 0), + SyscallSucceedsWithValue(0)); +} + TEST_P(SimpleTcpSocketTest, NonBlockingConnectRetry) { const FileDescriptor listener = ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));