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,