diff --git a/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs new file mode 100644 index 00000000000000..e305163ed8fe1d --- /dev/null +++ b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs @@ -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); + } + } +} diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 983e7f9eb96d98..4282d4872a2665 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -109,6 +109,8 @@ Link="Common\System\IO\StreamHelpers.CopyValidation.cs" /> + _stream.Socket.RemoteEndPoint; public override EndPoint? LocalEndPoint => _stream.Socket.LocalEndPoint; @@ -19,7 +21,7 @@ internal sealed class SocketConnection : Connection, IConnectionProperties 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 @@ protected override ValueTask CloseAsyncCore(ConnectionCloseMethod method, Cancel _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 @@ bool IConnectionProperties.TryGet(Type propertyKey, [NotNullWhen(true)] out obje 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; - } - } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionFactory.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionFactory.cs index e224616c9e3f04..34018a14170aca 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionFactory.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpConnectionFactory.cs @@ -79,6 +79,11 @@ public virtual async ValueTask EstablishConnectionAsync(HttpRequestM socket.NoDelay = true; return new SocketConnection(socket); } + catch (SocketException socketException) + { + socket.Dispose(); + throw NetworkErrorHelper.MapSocketException(socketException); + } catch { socket.Dispose(); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index 18b60363701099..f17f9a84418730 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -160,7 +160,9 @@ public async Task CustomConnectionFactory_SyncRequest_Fails() using HttpClient client = CreateHttpClient(handler); - await Assert.ThrowsAnyAsync(() => client.GetStringAsync($"http://{Guid.NewGuid():N}.com/foo")); + HttpRequestException e = await Assert.ThrowsAnyAsync(() => client.GetStringAsync($"http://{Guid.NewGuid():N}.com/foo")); + NetworkException networkException = Assert.IsType(e.InnerException); + Assert.Equal(NetworkError.HostNotFound, networkException.NetworkError); } } diff --git a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs index 979baf5e9f1e2a..1cd070f2d98346 100644 --- a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs +++ b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs @@ -323,6 +323,23 @@ public abstract partial class TransportContext 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 { diff --git a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx index d95ea7484aace1..d0dbe85701a4cd 100644 --- a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx @@ -114,4 +114,25 @@ An invalid IPEndPoint was specified. + + An unknown network error occurred. + + + The requested EndPoint is already in use. + + + No connection could be made because the remote host actively refused it. + + + No such host is known. + + + The operation was aborted by the user. + + + The connection was aborted by the local host. + + + The connection was forcibly closed by the remote host. + diff --git a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj index 07f176ab3ad641..413d76f6925cb6 100644 --- a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj +++ b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj @@ -34,6 +34,8 @@ + + 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 index 00000000000000..44bcac8678a289 --- /dev/null +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs @@ -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 +{ + /// Defines a set of error codes for use with . + public enum NetworkError : int + { + /// An unknown network error occurred. + Unknown = 0, + + /// The requested EndPoint is already in use. + EndPointInUse, + + /// No such host is known. + HostNotFound, + + /// No connection could be made because the remote host actively refused it. + ConnectionRefused, + + /// The operation was aborted by the user. + OperationAborted, + + /// The connection was aborted by the local host. + ConnectionAborted, + + /// The connection was forcibly closed by the remote host. + 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 index 00000000000000..7b1b48f9379142 --- /dev/null +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -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 +{ + /// Provides socket exceptions to the application. + [Serializable] + public class NetworkException : IOException + { + /// Creates a new instance of the class with the specified error code. + public NetworkException(NetworkError error, Exception? innerException = null) + : this(GetExceptionMessage(error), error, innerException) {} + + /// Creates a new instance of the class with the specified error code and message. + public NetworkException(string message, NetworkError error, Exception? innerException = null) + : base(message, innerException) + { + NetworkError = error; + } + + /// Creates a new instance of the from serialized data. + protected NetworkException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + NetworkError = (NetworkError)serializationInfo.GetInt32("NetworkError"); + } + + /// Populates the serialization data for this object. + public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext) + { + base.GetObjectData(serializationInfo, streamingContext); + serializationInfo.AddValue("NetworkError", (int)NetworkError); + } + + /// Returns the specific kind of error. + 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 index 00000000000000..a7f60c9de1624b --- /dev/null +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs @@ -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); + } + } +} diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj b/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj index 26cd2568e1570b..215b3411c287d8 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj @@ -20,6 +20,7 @@ + diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj index 3d4d3c791e27d2..a8e3908a2ff2f2 100644 --- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj +++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj @@ -93,6 +93,8 @@ Link="Common\System\Net\Sockets\ProtocolType.cs" /> + diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs index d6fa0458bdc579..e2a3ac6fff45d3 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs @@ -50,15 +50,15 @@ public NetworkStream(Socket socket, FileAccess access, bool ownsSocket) // 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 @@ public override int Read(byte[] buffer, int offset, int size) { 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 @@ public override int Read(Span buffer) 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 @@ public override void Write(byte[] buffer, int offset, int size) // 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 @@ public override void Write(ReadOnlySpan buffer) 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 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, Asyn 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 @@ public override int EndRead(IAsyncResult asyncResult) { 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 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, Asy 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 @@ public override void EndWrite(IAsyncResult asyncResult) { _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 @@ public override Task ReadAsync(byte[] buffer, int offset, int size, Cancell 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 @@ public override ValueTask ReadAsync(Memory buffer, CancellationToken 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 @@ public override Task WriteAsync(byte[] buffer, int offset, int size, Cancellatio 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 @@ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationTo 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 @@ private void ThrowIfDisposed() void ThrowObjectDisposedException() => throw new ObjectDisposedException(GetType().FullName); } + + private static NetworkException GetCustomNetworkException(string message, Exception? innerException = null) + { + return new NetworkException(message, NetworkError.Unknown, innerException); + } } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs index 7e995116b8779e..75a226949d933e 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs @@ -154,7 +154,7 @@ internal ValueTask ReceiveAsync(Memory buffer, SocketFlags socketFlag 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 @@ internal ValueTask SendAsync(ReadOnlyMemory buffer, SocketFlags socke 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 @@ internal ValueTask SendAsyncForNetworkStream(ReadOnlyMemory buffer, Socket 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 @@ public AwaitableSocketAsyncEventArgs(Socket owner, bool isReceiveForCaching) : _isReadForCaching = isReceiveForCaching; } - public bool WrapExceptionsInIOExceptions { get; set; } + public bool WrapExceptionsInNetworkExceptions { get; set; } private void Release() { @@ -885,8 +885,8 @@ private Exception CreateException(SocketError error, bool forAsyncThrow = true) e = ExceptionDispatchInfo.SetCurrentStackTrace(e); } - return WrapExceptionsInIOExceptions ? - new IOException(SR.Format(SR.net_io_readfailure, e.Message), e) : + return WrapExceptionsInNetworkExceptions ? + NetworkErrorHelper.MapSocketException((SocketException)e) : e; } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs index f7b0e83e44a762..fb293859854186 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs @@ -25,25 +25,25 @@ public void Ctor_NullSocket_ThrowsArgumentNullExceptions() } [Fact] - public void Ctor_NotConnected_ThrowsIOException() + public void Ctor_NotConnected_ThrowsNetworkException() { - Assert.Throws(() => new NetworkStream(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))); + Assert.Throws(() => 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(() => new NetworkStream(client)); + Assert.Throws(() => 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 @@ public async Task Ctor_NonBlockingSocket_ThrowsIOException() using (Socket server = await acceptTask) { server.Blocking = false; - Assert.Throws(() => new NetworkStream(server)); + Assert.Throws(() => new NetworkStream(server)); } } } @@ -186,7 +186,7 @@ public async Task Ctor_SocketBool_CanReadAndWrite(bool ownsSocket) } else if (ownsSocket) { - Assert.IsType(e); + Assert.IsType(e); } else { @@ -302,7 +302,7 @@ await RunWithConnectedNetworkStreamsAsync((server, _) => } [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 @@ public async Task DisposeSocketDirectly_ReadWriteThrowIOException() { serverSocket.Dispose(); - Assert.Throws(() => server.Read(new byte[1], 0, 1)); - Assert.Throws(() => server.Write(new byte[1], 0, 1)); + Assert.Throws(() => server.Read(new byte[1], 0, 1)); + Assert.Throws(() => server.Write(new byte[1], 0, 1)); - Assert.Throws(() => server.BeginRead(new byte[1], 0, 1, null, null)); - Assert.Throws(() => server.BeginWrite(new byte[1], 0, 1, null, null)); + Assert.Throws(() => server.BeginRead(new byte[1], 0, 1, null, null)); + Assert.Throws(() => server.BeginWrite(new byte[1], 0, 1, null, null)); - Assert.Throws(() => { server.ReadAsync(new byte[1], 0, 1); }); - Assert.Throws(() => { server.WriteAsync(new byte[1], 0, 1); }); + Assert.Throws(() => { server.ReadAsync(new byte[1], 0, 1); }); + Assert.Throws(() => { server.WriteAsync(new byte[1], 0, 1); }); } } } @@ -334,8 +334,8 @@ public async Task InvalidIAsyncResult_EndReadWriteThrows() { await RunWithConnectedNetworkStreamsAsync((server, _) => { - Assert.Throws(() => server.EndRead(Task.CompletedTask)); - Assert.Throws(() => server.EndWrite(Task.CompletedTask)); + Assert.Throws(() => server.EndRead(Task.CompletedTask)); + Assert.Throws(() => server.EndWrite(Task.CompletedTask)); return Task.CompletedTask; }); } @@ -586,7 +586,7 @@ await RunWithConnectedNetworkStreamsAsync((server, client) => Assert.Equal(-1, server.ReadTimeout); server.ReadTimeout = 1; - Assert.ThrowsAny(() => server.Read(new byte[1], 0, 1)); + Assert.ThrowsAny(() => server.Read(new byte[1], 0, 1)); return Task.CompletedTask; }); @@ -713,8 +713,8 @@ await RunWithConnectedNetworkStreamsAsync(async (stream, _) => // 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