add NetworkException (#40344)
authorGeoff Kizer <geoffrek@microsoft.com>
Fri, 7 Aug 2020 16:52:30 +0000 (09:52 -0700)
committerGitHub <noreply@github.com>
Fri, 7 Aug 2020 16:52:30 +0000 (09:52 -0700)
* add NetworkException

16 files changed:
src/libraries/Common/src/System/Net/NetworkErrorHelper.cs [new file with mode: 0644]
src/libraries/System.Net.Http/src/System.Net.Http.csproj
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionFactory.cs
src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs
src/libraries/System.Net.Primitives/src/Resources/Strings.resx
src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj
src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs [new file with mode: 0644]
src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs [new file with mode: 0644]
src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs [new file with mode: 0644]
src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj
src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj
src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs
src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs

diff --git a/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs
new file mode 100644 (file)
index 0000000..e305163
--- /dev/null
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Net.Sockets;
+
+namespace System.Net
+{
+    internal static class NetworkErrorHelper
+    {
+        internal static NetworkException MapSocketException(SocketException socketException)
+        {
+            NetworkError error = socketException.SocketErrorCode switch
+            {
+                SocketError.AddressAlreadyInUse => NetworkError.EndPointInUse,
+                SocketError.HostNotFound => NetworkError.HostNotFound,
+                SocketError.ConnectionRefused => NetworkError.ConnectionRefused,
+                SocketError.OperationAborted => NetworkError.OperationAborted,
+                SocketError.ConnectionAborted => NetworkError.ConnectionAborted,
+                SocketError.ConnectionReset => NetworkError.ConnectionReset,
+                _ => NetworkError.Unknown
+            };
+
+            return new NetworkException(error, socketException);
+        }
+    }
+}
index 1e2ceae..420af9b 100644 (file)
              Link="Common\System\IO\StreamHelpers.CopyValidation.cs" />
     <Compile Include="$(CommonPath)System\Net\Security\SslClientAuthenticationOptionsExtensions.cs"
              Link="Common\System\Net\Security\SslClientAuthenticationOptionsExtensions.cs" />
+    <Compile Include="$(CommonPath)System\Net\NetworkErrorHelper.cs"
+             Link="Common\System\Net\NetworkErrorHelper.cs" />
     <Compile Include="$(CommonPath)System\IO\DelegatingStream.cs"
              Link="Common\System\IO\DelegatingStream.cs" />
     <Compile Include="$(CommonPath)System\IO\ReadOnlyMemoryStream.cs"
index 37b6f83..130cf63 100644 (file)
@@ -3,7 +3,9 @@
 
 using System.Diagnostics.CodeAnalysis;
 using System.IO;
+using System.Net.Http;
 using System.Net.Sockets;
+using System.Runtime.ExceptionServices;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -11,7 +13,7 @@ namespace System.Net.Connections
 {
     internal sealed class SocketConnection : Connection, IConnectionProperties
     {
-        private readonly SocketConnectionNetworkStream _stream;
+        private readonly NetworkStream _stream;
 
         public override EndPoint? RemoteEndPoint => _stream.Socket.RemoteEndPoint;
         public override EndPoint? LocalEndPoint => _stream.Socket.LocalEndPoint;
@@ -19,7 +21,7 @@ namespace System.Net.Connections
 
         public SocketConnection(Socket socket)
         {
-            _stream = new SocketConnectionNetworkStream(socket, this);
+            _stream = new NetworkStream(socket, ownsSocket: true);
         }
 
         protected override ValueTask CloseAsyncCore(ConnectionCloseMethod method, CancellationToken cancellationToken)
@@ -38,7 +40,11 @@ namespace System.Net.Connections
                     _stream.Socket.Dispose();
                 }
 
-                _stream.DisposeWithoutClosingConnection();
+                _stream.Dispose();
+            }
+            catch (SocketException socketException)
+            {
+                return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(NetworkErrorHelper.MapSocketException(socketException)));
             }
             catch (Exception ex)
             {
@@ -61,41 +67,5 @@ namespace System.Net.Connections
             property = null;
             return false;
         }
-
-        // This is done to couple disposal of the SocketConnection and the NetworkStream.
-        private sealed class SocketConnectionNetworkStream : NetworkStream
-        {
-            private readonly SocketConnection _connection;
-
-            public SocketConnectionNetworkStream(Socket socket, SocketConnection connection) : base(socket, ownsSocket: true)
-            {
-                _connection = connection;
-            }
-
-            public void DisposeWithoutClosingConnection()
-            {
-                base.Dispose(true);
-            }
-
-            protected override void Dispose(bool disposing)
-            {
-                if (disposing)
-                {
-                    // This will call base.Dispose().
-                    _connection.Dispose();
-                }
-                else
-                {
-                    base.Dispose(disposing);
-                }
-            }
-
-            public override ValueTask DisposeAsync()
-            {
-                // This will call base.Dispose().
-                Dispose(true);
-                return default;
-            }
-        }
     }
 }
index e224616..34018a1 100644 (file)
@@ -79,6 +79,11 @@ namespace System.Net.Http
                 socket.NoDelay = true;
                 return new SocketConnection(socket);
             }
+            catch (SocketException socketException)
+            {
+                socket.Dispose();
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch
             {
                 socket.Dispose();
index 71c9e27..551ce4e 100644 (file)
@@ -160,7 +160,9 @@ namespace System.Net.Http.Functional.Tests
 
             using HttpClient client = CreateHttpClient(handler);
 
-            await Assert.ThrowsAnyAsync<HttpRequestException>(() => client.GetStringAsync($"http://{Guid.NewGuid():N}.com/foo"));
+            HttpRequestException e = await Assert.ThrowsAnyAsync<HttpRequestException>(() => client.GetStringAsync($"http://{Guid.NewGuid():N}.com/foo"));
+            NetworkException networkException = Assert.IsType<NetworkException>(e.InnerException);
+            Assert.Equal(NetworkError.HostNotFound, networkException.NetworkError);
         }
     }
 
index 899fa7d..9127d1b 100644 (file)
@@ -322,6 +322,23 @@ namespace System.Net
         protected TransportContext() { }
         public abstract System.Security.Authentication.ExtendedProtection.ChannelBinding? GetChannelBinding(System.Security.Authentication.ExtendedProtection.ChannelBindingKind kind);
     }
+    public enum NetworkError : int
+    {
+        Unknown = 0,
+        EndPointInUse,
+        HostNotFound,
+        ConnectionRefused,
+        OperationAborted,
+        ConnectionAborted,
+        ConnectionReset,
+    }
+    public class NetworkException : System.IO.IOException
+    {
+        public NetworkException(NetworkError error, Exception? innerException = null) { }
+        public NetworkException(string message, NetworkError error, Exception? innerException = null) { }
+        protected NetworkException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { }
+        public NetworkError NetworkError { get { throw null; } }
+    }
 }
 namespace System.Net.Cache
 {
index d95ea74..d0dbe85 100644 (file)
   <data name="bad_endpoint_string" xml:space="preserve">
     <value>An invalid IPEndPoint was specified.</value>
   </data>
+  <data name="networkerror_unknown" xml:space="preserve">
+    <value>An unknown network error occurred.</value>
+  </data>
+  <data name="networkerror_addressinuse" xml:space="preserve">
+    <value>The requested EndPoint is already in use.</value>
+  </data>
+  <data name="networkerror_connectionrefused" xml:space="preserve">
+    <value>No connection could be made because the remote host actively refused it.</value>
+  </data>
+  <data name="networkerror_hostnotfound" xml:space="preserve">
+    <value>No such host is known.</value>
+  </data>
+  <data name="networkerror_operationaborted" xml:space="preserve">
+    <value>The operation was aborted by the user.</value>
+  </data>
+  <data name="networkerror_connectionaborted" xml:space="preserve">
+    <value>The connection was aborted by the local host.</value>
+  </data>
+  <data name="networkerror_connectionreset" xml:space="preserve">
+    <value>The connection was forcibly closed by the remote host.</value>
+  </data>
 </root>
index 07f176a..413d76f 100644 (file)
@@ -34,6 +34,8 @@
     <Compile Include="System\Net\IWebProxy.cs" />
     <Compile Include="System\Net\NetEventSource.Primitives.cs" />
     <Compile Include="System\Net\NetworkCredential.cs" />
+    <Compile Include="System\Net\NetworkException.cs" />
+    <Compile Include="System\Net\NetworkError.cs" />
     <Compile Include="System\Net\TransportContext.cs" />
     <Compile Include="System\Net\SocketException.cs" />
     <Compile Include="System\Net\SecureProtocols\NegotiateEnumTypes.cs" />
diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs
new file mode 100644 (file)
index 0000000..44bcac8
--- /dev/null
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Net
+{
+    /// <summary>Defines a set of error codes for use with <see cref='System.Net.NetworkException'/>.</summary>
+    public enum NetworkError : int
+    {
+        /// <summary>An unknown network error occurred.</summary>
+        Unknown = 0,
+
+        /// <summary>The requested EndPoint is already in use.</summary>
+        EndPointInUse,
+
+        /// <summary>No such host is known.</summary>
+        HostNotFound,
+
+        /// <summary>No connection could be made because the remote host actively refused it.</summary>
+        ConnectionRefused,
+
+        /// <summary>The operation was aborted by the user.</summary>
+        OperationAborted,
+
+        /// <summary>The connection was aborted by the local host.</summary>
+        ConnectionAborted,
+
+        /// <summary>The connection was forcibly closed by the remote host.</summary>
+        ConnectionReset,
+    }
+}
diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs
new file mode 100644 (file)
index 0000000..7b1b48f
--- /dev/null
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.IO;
+using System.Runtime.Serialization;
+
+namespace System.Net
+{
+    /// <summary>Provides socket exceptions to the application.</summary>
+    [Serializable]
+    public class NetworkException : IOException
+    {
+        /// <summary>Creates a new instance of the <see cref='System.Net.NetworkException'/> class with the specified error code.</summary>
+        public NetworkException(NetworkError error, Exception? innerException = null)
+            : this(GetExceptionMessage(error), error, innerException) {}
+
+        /// <summary>Creates a new instance of the <see cref='System.Net.NetworkException'/> class with the specified error code and message.</summary>
+        public NetworkException(string message, NetworkError error, Exception? innerException = null)
+            : base(message, innerException)
+        {
+            NetworkError = error;
+        }
+
+        /// <summary>Creates a new instance of the <see cref='System.Net.NetworkException'/> from serialized data.</summary>
+        protected NetworkException(SerializationInfo serializationInfo, StreamingContext streamingContext)
+            : base(serializationInfo, streamingContext)
+        {
+            NetworkError = (NetworkError)serializationInfo.GetInt32("NetworkError");
+        }
+
+        /// <summary>Populates the serialization data for this object.</summary>
+        public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
+        {
+            base.GetObjectData(serializationInfo, streamingContext);
+            serializationInfo.AddValue("NetworkError", (int)NetworkError);
+        }
+
+        /// <summary>Returns the specific kind of error.</summary>
+        public NetworkError NetworkError { get; }
+
+        private static string GetExceptionMessage(NetworkError error) => error switch
+        {
+            NetworkError.EndPointInUse => SR.networkerror_addressinuse,
+            NetworkError.HostNotFound => SR.networkerror_hostnotfound,
+            NetworkError.ConnectionRefused => SR.networkerror_connectionrefused,
+            NetworkError.ConnectionAborted => SR.networkerror_connectionaborted,
+            NetworkError.ConnectionReset => SR.networkerror_connectionreset,
+            NetworkError.OperationAborted => SR.networkerror_operationaborted,
+            _ => SR.networkerror_unknown
+        };
+    }
+}
diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs
new file mode 100644 (file)
index 0000000..a7f60c9
--- /dev/null
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+
+namespace System.Net.Primitives.Functional.Tests
+{
+    public static class NetworkExceptionTest
+    {
+        [Fact]
+        public static void Create_AllErrorCodes_Success()
+        {
+            foreach (NetworkError error in Enum.GetValues(typeof(NetworkError)))
+            {
+                NetworkException e = new NetworkException(error);
+                Assert.Equal(error, e.NetworkError);
+                Assert.Null(e.InnerException);
+                Assert.NotNull(e.Message);
+            }
+        }
+
+        [Fact]
+        public static void Create_InnerExceptionAndMessage_Success()
+        {
+            const string Message = "Hello";
+            Exception inner = new Exception();
+
+            NetworkException e = new NetworkException(Message, NetworkError.Unknown, inner);
+
+            Assert.Equal(inner, e.InnerException);
+            Assert.Equal(Message, e.Message);
+        }
+    }
+}
index 26cd256..215b341 100644 (file)
@@ -20,6 +20,7 @@
     <Compile Include="IPEndPointParsing.cs" />
     <Compile Include="IPEndPointTest.cs" />
     <Compile Include="NetworkCredentialTest.cs" />
+    <Compile Include="NetworkExceptionTest.cs" />
     <Compile Include="SocketAddressTest.cs" />
     <Compile Include="LoggingTest.cs" />
     <Compile Include="RequestCachePolicyTest.cs" />
index ae0f96d..4d39c2d 100644 (file)
@@ -95,6 +95,8 @@
              Link="Common\System\Net\Sockets\ProtocolType.cs" />
     <Compile Include="$(CommonPath)System\Net\Sockets\SocketType.cs"
              Link="Common\System\Net\Sockets\SocketType.cs" />
+    <Compile Include="$(CommonPath)System\Net\NetworkErrorHelper.cs"
+             Link="Common\System\Net\NetworkErrorHelper.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
     <!-- Windows: CoreCLR -->
index d6fa045..e2a3ac6 100644 (file)
@@ -50,15 +50,15 @@ namespace System.Net.Sockets
                 // allowing non-blocking sockets could result in non-deterministic failures from those
                 // operations. A developer that requires using NetworkStream with a non-blocking socket can
                 // temporarily flip Socket.Blocking as a workaround.
-                throw new IOException(SR.net_sockets_blocking);
+                throw GetCustomNetworkException(SR.net_sockets_blocking);
             }
             if (!socket.Connected)
             {
-                throw new IOException(SR.net_notconnected);
+                throw GetCustomNetworkException(SR.net_notconnected);
             }
             if (socket.SocketType != SocketType.Stream)
             {
-                throw new IOException(SR.net_notstream);
+                throw GetCustomNetworkException(SR.net_notstream);
             }
 
             _streamSocket = socket;
@@ -241,11 +241,13 @@ namespace System.Net.Sockets
             {
                 return _streamSocket.Receive(buffer, offset, size, 0);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
             }
         }
 
@@ -266,7 +268,7 @@ namespace System.Net.Sockets
             if (errorCode != SocketError.Success)
             {
                 var exception = new SocketException((int)errorCode);
-                throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
+                throw NetworkErrorHelper.MapSocketException(exception);
             }
             return bytesRead;
         }
@@ -322,11 +324,13 @@ namespace System.Net.Sockets
                 // after ALL the requested number of bytes was transferred.
                 _streamSocket.Send(buffer, offset, size, SocketFlags.None);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
             }
         }
 
@@ -348,7 +352,7 @@ namespace System.Net.Sockets
             if (errorCode != SocketError.Success)
             {
                 var exception = new SocketException((int)errorCode);
-                throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
+                throw NetworkErrorHelper.MapSocketException(exception);
             }
         }
 
@@ -443,11 +447,13 @@ namespace System.Net.Sockets
                         callback,
                         state);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
             }
         }
 
@@ -473,11 +479,13 @@ namespace System.Net.Sockets
             {
                 return _streamSocket.EndReceive(asyncResult);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
             }
         }
 
@@ -529,11 +537,13 @@ namespace System.Net.Sockets
                         callback,
                         state);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
             }
         }
 
@@ -555,11 +565,13 @@ namespace System.Net.Sockets
             {
                 _streamSocket.EndSend(asyncResult);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
             }
         }
 
@@ -609,11 +621,13 @@ namespace System.Net.Sockets
                     fromNetworkStream: true,
                     cancellationToken).AsTask();
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
             }
         }
 
@@ -634,11 +648,13 @@ namespace System.Net.Sockets
                     fromNetworkStream: true,
                     cancellationToken: cancellationToken);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
             }
         }
 
@@ -687,11 +703,13 @@ namespace System.Net.Sockets
                     SocketFlags.None,
                     cancellationToken).AsTask();
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
             }
         }
 
@@ -711,11 +729,13 @@ namespace System.Net.Sockets
                     SocketFlags.None,
                     cancellationToken);
             }
+            catch (SocketException socketException)
+            {
+                throw NetworkErrorHelper.MapSocketException(socketException);
+            }
             catch (Exception exception) when (!(exception is OutOfMemoryException))
             {
-                // Some sort of error occurred on the socket call,
-                // set the SocketException as InnerException and throw.
-                throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
+                throw GetCustomNetworkException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
             }
         }
 
@@ -772,5 +792,10 @@ namespace System.Net.Sockets
 
             void ThrowObjectDisposedException() => throw new ObjectDisposedException(GetType().FullName);
         }
+
+        private static NetworkException GetCustomNetworkException(string message, Exception? innerException = null)
+        {
+            return new NetworkException(message, NetworkError.Unknown, innerException);
+        }
     }
 }
index 7e99511..75a2269 100644 (file)
@@ -154,7 +154,7 @@ namespace System.Net.Sockets
             Debug.Assert(saea.BufferList == null);
             saea.SetBuffer(buffer);
             saea.SocketFlags = socketFlags;
-            saea.WrapExceptionsInIOExceptions = fromNetworkStream;
+            saea.WrapExceptionsInNetworkExceptions = fromNetworkStream;
             return saea.ReceiveAsync(this, cancellationToken);
         }
 
@@ -237,7 +237,7 @@ namespace System.Net.Sockets
             Debug.Assert(saea.BufferList == null);
             saea.SetBuffer(MemoryMarshal.AsMemory(buffer));
             saea.SocketFlags = socketFlags;
-            saea.WrapExceptionsInIOExceptions = false;
+            saea.WrapExceptionsInNetworkExceptions = false;
             return saea.SendAsync(this, cancellationToken);
         }
 
@@ -255,7 +255,7 @@ namespace System.Net.Sockets
             Debug.Assert(saea.BufferList == null);
             saea.SetBuffer(MemoryMarshal.AsMemory(buffer));
             saea.SocketFlags = socketFlags;
-            saea.WrapExceptionsInIOExceptions = true;
+            saea.WrapExceptionsInNetworkExceptions = true;
             return saea.SendAsyncForNetworkStream(this, cancellationToken);
         }
 
@@ -577,7 +577,7 @@ namespace System.Net.Sockets
                 _isReadForCaching = isReceiveForCaching;
             }
 
-            public bool WrapExceptionsInIOExceptions { get; set; }
+            public bool WrapExceptionsInNetworkExceptions { get; set; }
 
             private void Release()
             {
@@ -885,8 +885,8 @@ namespace System.Net.Sockets
                     e = ExceptionDispatchInfo.SetCurrentStackTrace(e);
                 }
 
-                return WrapExceptionsInIOExceptions ?
-                    new IOException(SR.Format(SR.net_io_readfailure, e.Message), e) :
+                return WrapExceptionsInNetworkExceptions ?
+                    NetworkErrorHelper.MapSocketException((SocketException)e) :
                     e;
             }
         }
index f7b0e83..fb29385 100644 (file)
@@ -25,25 +25,25 @@ namespace System.Net.Sockets.Tests
         }
 
         [Fact]
-        public void Ctor_NotConnected_ThrowsIOException()
+        public void Ctor_NotConnected_ThrowsNetworkException()
         {
-            Assert.Throws<IOException>(() => new NetworkStream(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)));
+            Assert.Throws<NetworkException>(() => new NetworkStream(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)));
         }
 
         [Fact]
-        public async Task Ctor_NotStream_ThrowsIOException()
+        public async Task Ctor_NotStream_ThrowsNetworkException()
         {
             using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
             using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
             {
                 listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
                 await client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, ((IPEndPoint)listener.LocalEndPoint).Port));
-                Assert.Throws<IOException>(() => new NetworkStream(client));
+                Assert.Throws<NetworkException>(() => new NetworkStream(client));
             }
         }
 
         [Fact]
-        public async Task Ctor_NonBlockingSocket_ThrowsIOException()
+        public async Task Ctor_NonBlockingSocket_ThrowsNetworkException()
         {
             using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
             using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
@@ -56,7 +56,7 @@ namespace System.Net.Sockets.Tests
                 using (Socket server = await acceptTask)
                 {
                     server.Blocking = false;
-                    Assert.Throws<IOException>(() => new NetworkStream(server));
+                    Assert.Throws<NetworkException>(() => new NetworkStream(server));
                 }
             }
         }
@@ -186,7 +186,7 @@ namespace System.Net.Sockets.Tests
                         }
                         else if (ownsSocket)
                         {
-                            Assert.IsType<IOException>(e);
+                            Assert.IsType<NetworkException>(e);
                         }
                         else
                         {
@@ -302,7 +302,7 @@ namespace System.Net.Sockets.Tests
         }
 
         [Fact]
-        public async Task DisposeSocketDirectly_ReadWriteThrowIOException()
+        public async Task DisposeSocketDirectly_ReadWriteThrowNetworkException()
         {
             using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
             using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
@@ -317,14 +317,14 @@ namespace System.Net.Sockets.Tests
                 {
                     serverSocket.Dispose();
 
-                    Assert.Throws<IOException>(() => server.Read(new byte[1], 0, 1));
-                    Assert.Throws<IOException>(() => server.Write(new byte[1], 0, 1));
+                    Assert.Throws<NetworkException>(() => server.Read(new byte[1], 0, 1));
+                    Assert.Throws<NetworkException>(() => server.Write(new byte[1], 0, 1));
 
-                    Assert.Throws<IOException>(() => server.BeginRead(new byte[1], 0, 1, null, null));
-                    Assert.Throws<IOException>(() => server.BeginWrite(new byte[1], 0, 1, null, null));
+                    Assert.Throws<NetworkException>(() => server.BeginRead(new byte[1], 0, 1, null, null));
+                    Assert.Throws<NetworkException>(() => server.BeginWrite(new byte[1], 0, 1, null, null));
 
-                    Assert.Throws<IOException>(() => { server.ReadAsync(new byte[1], 0, 1); });
-                    Assert.Throws<IOException>(() => { server.WriteAsync(new byte[1], 0, 1); });
+                    Assert.Throws<NetworkException>(() => { server.ReadAsync(new byte[1], 0, 1); });
+                    Assert.Throws<NetworkException>(() => { server.WriteAsync(new byte[1], 0, 1); });
                 }
             }
         }
@@ -334,8 +334,8 @@ namespace System.Net.Sockets.Tests
         {
             await RunWithConnectedNetworkStreamsAsync((server, _) =>
             {
-                Assert.Throws<IOException>(() => server.EndRead(Task.CompletedTask));
-                Assert.Throws<IOException>(() => server.EndWrite(Task.CompletedTask));
+                Assert.Throws<NetworkException>(() => server.EndRead(Task.CompletedTask));
+                Assert.Throws<NetworkException>(() => server.EndWrite(Task.CompletedTask));
                 return Task.CompletedTask;
             });
         }
@@ -586,7 +586,7 @@ namespace System.Net.Sockets.Tests
                 Assert.Equal(-1, server.ReadTimeout);
 
                 server.ReadTimeout = 1;
-                Assert.ThrowsAny<IOException>(() => server.Read(new byte[1], 0, 1));
+                Assert.ThrowsAny<NetworkException>(() => server.Read(new byte[1], 0, 1));
 
                 return Task.CompletedTask;
             });
@@ -713,8 +713,8 @@ namespace System.Net.Sockets.Tests
                 // before that takes effect, it may also complete as aborted.
                 bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                 Assert.True(
-                    (isWindows && e is IOException) ||
-                    (!isWindows && (e == null || e is IOException)),
+                    (isWindows && e is NetworkException) ||
+                    (!isWindows && (e == null || e is NetworkException)),
                     $"Got unexpected exception: {e?.ToString() ?? "(null)"}");
 
                 // Copying after disposing the stream