From 8cfc543a3f22e30af7b1aafc26f268236bc77b40 Mon Sep 17 00:00:00 2001 From: Nayana Bidari Date: Mon, 13 Nov 2023 10:21:42 -0800 Subject: [PATCH] Fix reconnect of UDP socket. The reconnect for UDP sockets was failing because we were not removing the old registration before attempting to register again. Fix this issue by removing the old registration and then registering the endpoint. Updates #8998 PiperOrigin-RevId: 582007411 --- pkg/tcpip/transport/udp/endpoint.go | 10 ++++----- test/syscalls/linux/udp_socket.cc | 35 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go index e873e31df..5472c1b25 100644 --- a/pkg/tcpip/transport/udp/endpoint.go +++ b/pkg/tcpip/transport/udp/endpoint.go @@ -679,11 +679,6 @@ func (e *endpoint) Connect(addr tcpip.FullAddress) tcpip.Error { oldPortFlags := e.boundPortFlags - nextID, btd, err := e.registerWithStack(netProtos, nextID) - if err != nil { - return err - } - // Remove the old registration. if e.localPort != 0 { previousID.LocalPort = e.localPort @@ -691,6 +686,11 @@ func (e *endpoint) Connect(addr tcpip.FullAddress) tcpip.Error { e.stack.UnregisterTransportEndpoint(e.effectiveNetProtos, ProtocolNumber, previousID, e, oldPortFlags, e.boundBindToDevice) } + nextID, btd, err := e.registerWithStack(netProtos, nextID) + if err != nil { + return err + } + e.localPort = nextID.LocalPort e.remotePort = nextID.RemotePort e.boundBindToDevice = btd diff --git a/test/syscalls/linux/udp_socket.cc b/test/syscalls/linux/udp_socket.cc index 1c48e0d9e..542c155c4 100644 --- a/test/syscalls/linux/udp_socket.cc +++ b/test/syscalls/linux/udp_socket.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -2447,6 +2448,40 @@ TEST_P(UdpSocketTest, ReadShutdownOnBoundSocket) { } } +TEST_P(UdpSocketTest, ReconnectDoesNotClearReadShutdown) { + // TODO(gvisor.dev/issue/1202): Reconnecting the UDP socket after shutdown + // fails on hostinet. + SKIP_IF(IsRunningWithHostinet()); + ASSERT_NO_ERRNO(BindLoopback()); + ASSERT_THAT(connect(sock_.get(), bind_addr_, addrlen_), SyscallSucceeds()); + ASSERT_THAT(shutdown(sock_.get(), SHUT_RD), SyscallSucceeds()); + + char received[512]; + EXPECT_THAT(recv(sock_.get(), received, sizeof(received), 0), + SyscallSucceedsWithValue(0)); + + EXPECT_THAT(connect(sock_.get(), bind_addr_, addrlen_), SyscallSucceeds()); + EXPECT_THAT(recv(sock_.get(), received, sizeof(received), 0), + SyscallSucceedsWithValue(0)); +} + +TEST_P(UdpSocketTest, ReconnectDoesNotClearWriteShutdown) { + // TODO(gvisor.dev/issue/1202): Reconnecting the UDP socket after shutdown + // fails on hostinet. + SKIP_IF(IsRunningWithHostinet()); + ASSERT_NO_ERRNO(BindLoopback()); + ASSERT_THAT(connect(sock_.get(), bind_addr_, addrlen_), SyscallSucceeds()); + + const char buf = 'A'; + ASSERT_THAT(send(sock_.get(), &buf, 1, 0), SyscallSucceeds()); + + ASSERT_THAT(shutdown(sock_.get(), SHUT_WR), SyscallSucceeds()); + EXPECT_THAT(send(sock_.get(), &buf, 1, 0), SyscallFailsWithErrno(EPIPE)); + + EXPECT_THAT(connect(sock_.get(), bind_addr_, addrlen_), SyscallSucceeds()); + EXPECT_THAT(send(sock_.get(), &buf, 1, 0), SyscallFailsWithErrno(EPIPE)); +} + INSTANTIATE_TEST_SUITE_P(AllInetTests, UdpSocketControlMessagesTest, ::testing::Values(AddressFamily::kIpv4, AddressFamily::kIpv6,