From fecdb7413df7d91a20260c6ce84a393a8c8ac00c Mon Sep 17 00:00:00 2001 From: Ahmet Ibrahim Aksoy Date: Mon, 17 Jul 2023 20:38:25 +0300 Subject: [PATCH] Relaxing IsConnected Check for Datagram Sockets (#87916) * Relaxing IsConnected Check for Datagram Sockets * Adding Listener inside Test * Add relaxing to every Connect Path and invert condition to SocketType.Stream * Make test theory and pass ipv4 ipv6 data * Add LoopbacksAndAny * Fix forgotten usage of parameter * Handle OSX case * Review feedback --- .../src/System/Net/Sockets/Socket.cs | 28 ++++++++----------- .../tests/FunctionalTests/Connect.cs | 15 ++++++++++ .../tests/FunctionalTests/SocketTestHelper.cs | 6 ++++ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 6b724c9a1709c..03b6a12b440e7 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -797,10 +797,7 @@ public void Connect(EndPoint remoteEP) throw new InvalidOperationException(SR.net_sockets_mustnotlisten); } - if (_isConnected) - { - throw new SocketException((int)SocketError.IsConnected); - } + ThrowIfConnectedStreamSocket(); ValidateBlockingMode(); @@ -839,10 +836,7 @@ public void Connect(IPAddress address, int port) throw new ArgumentOutOfRangeException(nameof(port)); } - if (_isConnected) - { - throw new SocketException((int)SocketError.IsConnected); - } + ThrowIfConnectedStreamSocket(); ValidateForMultiConnect(isMultiEndpoint: false); // needs to come before CanTryAddressFamily call @@ -902,10 +896,7 @@ public void Connect(IPAddress[] addresses, int port) throw new NotSupportedException(SR.net_invalidversion); } - if (_isConnected) - { - throw new SocketException((int)SocketError.IsConnected); - } + ThrowIfConnectedStreamSocket(); ValidateForMultiConnect(isMultiEndpoint: true); // needs to come before CanTryAddressFamily call @@ -2648,10 +2639,7 @@ internal bool ConnectAsync(SocketAsyncEventArgs e, bool userSocket, bool saeaCan throw new InvalidOperationException(SR.net_sockets_mustnotlisten); } - if (_isConnected) - { - throw new SocketException((int)SocketError.IsConnected); - } + ThrowIfConnectedStreamSocket(); // Prepare SocketAddress. EndPoint? endPointSnapshot = e.RemoteEndPoint; @@ -3736,6 +3724,14 @@ private void ThrowIfDisposed() ObjectDisposedException.ThrowIf(Disposed, this); } + private void ThrowIfConnectedStreamSocket() + { + if (_isConnected && _socketType == SocketType.Stream) + { + throw new SocketException((int)SocketError.IsConnected); + } + } + private bool IsConnectionOriented => _socketType == SocketType.Stream; internal static void SocketListDangerousReleaseRefs(IList? socketList, ref int refsAdded) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs index a85ababc59412..60711885153d2 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs @@ -217,6 +217,21 @@ public async Task Connect_WithoutListener_ThrowSocketExceptionWithAppropriateInf Assert.Contains(a.LocalEndPoint.ToString(), ex.Message); } } + + [Theory] + [MemberData(nameof(LoopbacksAndAny))] + public async Task Connect_DatagramSockets_DontThrowConnectedException_OnSecondAttempt(IPAddress listenAt, IPAddress secondConnection) + { + using Socket listener = new Socket(listenAt.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + using Socket s = new Socket(listenAt.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + listener.Bind(new IPEndPoint(listenAt, 0)); + + await ConnectAsync(s, new IPEndPoint(listenAt, ((IPEndPoint)listener.LocalEndPoint).Port)); + Assert.True(s.Connected); + // According to the OSX man page, it's enough connecting to an invalid address to dissolve the connection. (0 port connection returns error on OSX) + await ConnectAsync(s, new IPEndPoint(secondConnection, PlatformDetection.IsOSX ? 1 : 0)); + Assert.True(s.Connected); + } } public sealed class ConnectSync : Connect diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs index 92b3b260c28b2..b4ef4f2cefda9 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs @@ -598,6 +598,12 @@ public abstract class MemberDatas new object[] { IPAddress.Loopback, true }, new object[] { IPAddress.Loopback, false }, }; + + public static readonly object[][] LoopbacksAndAny = new object[][] + { + new object[] { IPAddress.IPv6Loopback, IPAddress.IPv6Any }, + new object[] { IPAddress.Loopback, IPAddress.Any }, + }; } //