Relaxing IsConnected Check for Datagram Sockets (#87916)
authorAhmet Ibrahim Aksoy <aaksoy@microsoft.com>
Mon, 17 Jul 2023 17:38:25 +0000 (20:38 +0300)
committerGitHub <noreply@github.com>
Mon, 17 Jul 2023 17:38:25 +0000 (20:38 +0300)
* 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/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs

index 6b724c9..03b6a12 100644 (file)
@@ -797,10 +797,7 @@ namespace System.Net.Sockets
                 throw new InvalidOperationException(SR.net_sockets_mustnotlisten);
             }
 
-            if (_isConnected)
-            {
-                throw new SocketException((int)SocketError.IsConnected);
-            }
+            ThrowIfConnectedStreamSocket();
 
             ValidateBlockingMode();
 
@@ -839,10 +836,7 @@ namespace System.Net.Sockets
                 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 @@ namespace System.Net.Sockets
                 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 @@ namespace System.Net.Sockets
                 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 @@ namespace System.Net.Sockets
             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)
index a85abab..6071188 100644 (file)
@@ -217,6 +217,21 @@ namespace System.Net.Sockets.Tests
                 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<SocketHelperArraySync>
index 92b3b26..b4ef4f2 100644 (file)
@@ -598,6 +598,12 @@ namespace System.Net.Sockets.Tests
             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 },
+        };
     }
 
     //