From 9b84cf73bfd3ad2bf2e749690b8e878c56b4aafd Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Tue, 4 Aug 2020 15:42:58 -0700 Subject: [PATCH 01/17] add NetworkException --- .../ref/System.Net.Primitives.cs | 17 +++++++ .../src/Resources/Strings.resx | 21 +++++++++ .../src/System.Net.Primitives.csproj | 2 + .../src/System/Net/NetworkError.cs | 20 +++++++++ .../src/System/Net/NetworkException.cs | 45 +++++++++++++++++++ .../FunctionalTests/NetworkExceptionTest.cs | 34 ++++++++++++++ ...tem.Net.Primitives.Functional.Tests.csproj | 1 + 7 files changed, 140 insertions(+) create mode 100644 src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs create mode 100644 src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs create mode 100644 src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs 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..5e7bd24bd2fae7 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, + AddressInUse, + InvalidAddress, + HostNotFound, + ConnectionRefused, + ConnectionAborted, + ConnectionReset, + } + public class NetworkException : System.IO.IOException + { + protected NetworkException(NetworkError error, Exception? innerException = null, string? message = null) { } + protected NetworkException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } + public NetworkError NetworkError { get { throw null; } } + public static NetworkException Create(NetworkError error, Exception? innerException = null, string? message = null) { 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..96ecc4ad5424ef 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 connection error occurred. + + + The requested address is already in use. + + + The requested address is invalid. + + + No connection could be made because the target machine actively refused it. + + + No such host is known. + + + An established connection was aborted. + + + An existing 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..a56b439f7a6ee2 --- /dev/null +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs @@ -0,0 +1,20 @@ +// 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 +{ + public enum NetworkError : int + { + Unknown = 0, + + // Errors from connection establishment + AddressInUse, + InvalidAddress, + HostNotFound, + ConnectionRefused, + + // Errors from connection use (e.g NetworkStream.Read/Write) + ConnectionAborted, + 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..5b7fb9369e7cdd --- /dev/null +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -0,0 +1,45 @@ +// 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. + protected NetworkException(NetworkError error, Exception? innerException = null, string? message = null) + : base(message ?? GetExceptionMessage(error), innerException) + { + NetworkError = error; + } + + protected NetworkException(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) + { + } + + /// Returns the specific kind of error. + public NetworkError NetworkError { get; } + + /// Creates a new instance of the class with the specified error code. + public static NetworkException Create(NetworkError error, Exception? innerException = null, string? message = null) + { + return new NetworkException(error, innerException, message); + } + + private static string GetExceptionMessage(NetworkError error) => error switch + { + NetworkError.AddressInUse => SR.networkerror_addressinuse, + NetworkError.InvalidAddress => SR.networkerror_invalidaddress, + NetworkError.HostNotFound => SR.networkerror_hostnotfound, + NetworkError.ConnectionRefused => SR.networkerror_connectionrefused, + NetworkError.ConnectionAborted => SR.networkerror_connectionaborted, + NetworkError.ConnectionReset => SR.networkerror_connectionreset, + _ => 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..86855770d76ed8 --- /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 = NetworkException.Create(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 = NetworkException.Create(NetworkError.Unknown, inner, message); + + 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 @@ + From 5b5779d3e422d8d8211afa57a4c1b0933cebb48c Mon Sep 17 00:00:00 2001 From: Geoff Kizer Date: Tue, 4 Aug 2020 17:20:30 -0700 Subject: [PATCH 02/17] Update src/libraries/System.Net.Primitives/src/Resources/Strings.resx Co-authored-by: Cory Nelson --- src/libraries/System.Net.Primitives/src/Resources/Strings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx index 96ecc4ad5424ef..8f1a2b2db84fce 100644 --- a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx @@ -115,7 +115,7 @@ An invalid IPEndPoint was specified. - An unknown connection error occurred. + An unknown network error occurred. The requested address is already in use. From 78b6b4df32800c373fa6c55dc769ba9d003a82af Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Tue, 4 Aug 2020 18:57:36 -0700 Subject: [PATCH 03/17] add proper serialization logic --- .../src/System/Net/NetworkException.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs index 5b7fb9369e7cdd..2e06f439b640e0 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -20,6 +20,13 @@ protected NetworkException(NetworkError error, Exception? innerException = null, protected NetworkException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) { + NetworkError = (NetworkError)serializationInfo.GetInt32("NetworkError"); + } + + public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext) + { + base.GetObjectData(serializationInfo, streamingContext); + serializationInfo.AddValue("NetworkError", (int)NetworkError); } /// Returns the specific kind of error. From 6b83c4e0922a5abb0b92d46046c5077a52255ab2 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Tue, 4 Aug 2020 19:14:41 -0700 Subject: [PATCH 04/17] add OperationAborted and better XML comments and error strings --- .../ref/System.Net.Primitives.cs | 1 + .../src/Resources/Strings.resx | 9 ++++++--- .../src/System/Net/NetworkError.cs | 17 +++++++++++++++-- .../src/System/Net/NetworkException.cs | 2 ++ 4 files changed, 24 insertions(+), 5 deletions(-) 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 5e7bd24bd2fae7..1dbb1c3de18ac7 100644 --- a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs +++ b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs @@ -330,6 +330,7 @@ public enum NetworkError : int InvalidAddress, HostNotFound, ConnectionRefused, + OperationAborted, ConnectionAborted, ConnectionReset, } diff --git a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx index 8f1a2b2db84fce..bcf6c91a5930a4 100644 --- a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx @@ -124,15 +124,18 @@ The requested address is invalid. - No connection could be made because the target machine actively refused it. + No connection could be made because the remote host actively refused it. No such host is known. + + The operation was aborted by the user. + - An established connection was aborted. + The connection was aborted by the local host. - An existing connection was forcibly closed by the remote host. + The connection was forcibly closed by the remote host. diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs index a56b439f7a6ee2..aba20278bcdd54 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs @@ -3,18 +3,31 @@ namespace System.Net { + /// Defines a set of error codes for use with . public enum NetworkError : int { + /// An unknown network error occurred. Unknown = 0, - // Errors from connection establishment + /// The requested address is already in use. AddressInUse, + + /// The requested address is invalid. InvalidAddress, + + /// No such host is known. HostNotFound, + + /// No connection could be made because the remote host actively refused it. ConnectionRefused, - // Errors from connection use (e.g NetworkStream.Read/Write) + /// 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 index 2e06f439b640e0..a3abe422e21d78 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -17,12 +17,14 @@ protected NetworkException(NetworkError error, Exception? innerException = null, 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); From 298f96d0aef3b9607d02c168bcc32ec6aac5b185 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Tue, 4 Aug 2020 20:21:49 -0700 Subject: [PATCH 05/17] use NetworkException in SocketsHttpConnectionFactory --- .../Connections/SocketConnection.cs | 5 ++++ .../SocketsHttpConnectionFactory.cs | 23 +++++++++++++++++++ .../FunctionalTests/SocketsHttpHandlerTest.cs | 4 +++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs index 37b6f8361d98d6..ef51d3abc0fe40 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Net.Http; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -40,6 +41,10 @@ protected override ValueTask CloseAsyncCore(ConnectionCloseMethod method, Cancel _stream.DisposeWithoutClosingConnection(); } + catch (SocketException socketException) + { + return ValueTask.FromException(SocketsHttpConnectionFactory.MapSocketException(socketException)); + } catch (Exception ex) { return ValueTask.FromException(ex); 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..b2f3c8f1e5e543 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,11 +79,34 @@ public virtual async ValueTask EstablishConnectionAsync(HttpRequestM socket.NoDelay = true; return new SocketConnection(socket); } + catch (SocketException socketException) + { + socket.Dispose(); + throw MapSocketException(socketException); + } catch { socket.Dispose(); throw; } } + + internal static NetworkException MapSocketException(SocketException socketException) + { + NetworkError error = socketException.SocketErrorCode switch + { + SocketError.AddressAlreadyInUse => NetworkError.AddressInUse, + SocketError.AddressFamilyNotSupported => NetworkError.InvalidAddress, + SocketError.AddressNotAvailable => NetworkError.InvalidAddress, + SocketError.HostNotFound => NetworkError.HostNotFound, + SocketError.ConnectionRefused => NetworkError.ConnectionRefused, + SocketError.OperationAborted => NetworkError.OperationAborted, + SocketError.ConnectionAborted => NetworkError.ConnectionAborted, + SocketError.ConnectionReset => NetworkError.ConnectionReset, + _ => NetworkError.Unknown + }; + + return NetworkException.Create(error, socketException); + } } } 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); } } From bffcabb0e0e4041ae9dc48d1ea742420f4ece8e8 Mon Sep 17 00:00:00 2001 From: Geoff Kizer Date: Thu, 6 Aug 2020 00:36:06 -0700 Subject: [PATCH 06/17] Update src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs add ExceptionDispatchInfo handling Co-authored-by: Cory Nelson --- .../Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs index ef51d3abc0fe40..3e58b5402447c2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs @@ -43,7 +43,7 @@ protected override ValueTask CloseAsyncCore(ConnectionCloseMethod method, Cancel } catch (SocketException socketException) { - return ValueTask.FromException(SocketsHttpConnectionFactory.MapSocketException(socketException)); + return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(SocketsHttpConnectionFactory.MapSocketException(socketException))); } catch (Exception ex) { From b3cfa89a9368bdde3553665172eb957561dac2cb Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 00:39:55 -0700 Subject: [PATCH 07/17] fix casing of constant in test --- .../tests/FunctionalTests/NetworkExceptionTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs index 86855770d76ed8..c1aee9f77c5e77 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs @@ -22,13 +22,13 @@ public static void Create_AllErrorCodes_Success() [Fact] public static void Create_InnerExceptionAndMessage_Success() { - const string message = "Hello"; + const string Message = "Hello"; Exception inner = new Exception(); - NetworkException e = NetworkException.Create(NetworkError.Unknown, inner, message); + NetworkException e = NetworkException.Create(NetworkError.Unknown, inner, Message); Assert.Equal(inner, e.InnerException); - Assert.Equal(message, e.Message); + Assert.Equal(Message, e.Message); } } } From 563f86af4196a6ded2ed4f3be37472f142b8dfa7 Mon Sep 17 00:00:00 2001 From: Geoff Kizer Date: Thu, 6 Aug 2020 00:50:55 -0700 Subject: [PATCH 08/17] Update src/libraries/System.Net.Primitives/src/Resources/Strings.resx address -> EndPoint in error messages Co-authored-by: Cory Nelson --- src/libraries/System.Net.Primitives/src/Resources/Strings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx index bcf6c91a5930a4..e8af1a497d5a5f 100644 --- a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx @@ -118,7 +118,7 @@ An unknown network error occurred. - The requested address is already in use. + The requested EndPoint is already in use. The requested address is invalid. From 11fc432e338b7eae53ea67aaf78e33f31ec16f90 Mon Sep 17 00:00:00 2001 From: Geoff Kizer Date: Thu, 6 Aug 2020 00:51:10 -0700 Subject: [PATCH 09/17] Update src/libraries/System.Net.Primitives/src/Resources/Strings.resx address -> EndPoint in error messages Co-authored-by: Cory Nelson --- src/libraries/System.Net.Primitives/src/Resources/Strings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx index e8af1a497d5a5f..c3963a610442c0 100644 --- a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx @@ -121,7 +121,7 @@ The requested EndPoint is already in use. - The requested address is invalid. + The requested EndPoint is invalid. No connection could be made because the remote host actively refused it. From 1f8d94bb1426ce25670732671f2fbb05e9f37ae0 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 01:29:57 -0700 Subject: [PATCH 10/17] Address -> EndPoint in enum values --- .../System.Net.Primitives/ref/System.Net.Primitives.cs | 4 ++-- .../System.Net.Primitives/src/System/Net/NetworkError.cs | 8 ++++---- .../src/System/Net/NetworkException.cs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) 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 1dbb1c3de18ac7..4c5068f5b267cc 100644 --- a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs +++ b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs @@ -326,8 +326,8 @@ protected TransportContext() { } public enum NetworkError : int { Unknown = 0, - AddressInUse, - InvalidAddress, + EndPointInUse, + InvalidEndPoint, HostNotFound, ConnectionRefused, OperationAborted, diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs index aba20278bcdd54..f4932f6818384d 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs @@ -9,11 +9,11 @@ public enum NetworkError : int /// An unknown network error occurred. Unknown = 0, - /// The requested address is already in use. - AddressInUse, + /// The requested EndPoint is already in use. + EndPointInUse, - /// The requested address is invalid. - InvalidAddress, + /// The requested EndPoint is invalid. + InvalidEndPoint, /// No such host is known. HostNotFound, diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs index a3abe422e21d78..76108e67295c78 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -42,8 +42,8 @@ public static NetworkException Create(NetworkError error, Exception? innerExcept private static string GetExceptionMessage(NetworkError error) => error switch { - NetworkError.AddressInUse => SR.networkerror_addressinuse, - NetworkError.InvalidAddress => SR.networkerror_invalidaddress, + NetworkError.EndPointInUse => SR.networkerror_addressinuse, + NetworkError.InvalidEndPoint => SR.networkerror_invalidaddress, NetworkError.HostNotFound => SR.networkerror_hostnotfound, NetworkError.ConnectionRefused => SR.networkerror_connectionrefused, NetworkError.ConnectionAborted => SR.networkerror_connectionaborted, From 6d7872a72de79cd8185fe7f7d6b1af36c4513301 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 06:46:17 -0700 Subject: [PATCH 11/17] move MapSocketError to a common file and fix some review issues --- .../src/System/Net/NetworkErrorHelper.cs | 28 +++++++++++++++++++ .../src/System.Net.Http.csproj | 2 ++ .../Connections/SocketConnection.cs | 3 +- .../SocketsHttpConnectionFactory.cs | 20 +------------ 4 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 src/libraries/Common/src/System/Net/NetworkErrorHelper.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 index 00000000000000..67550160602b87 --- /dev/null +++ b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs @@ -0,0 +1,28 @@ +// 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.AddressFamilyNotSupported => NetworkError.InvalidEndPoint, + SocketError.AddressNotAvailable => NetworkError.InvalidEndPoint, + SocketError.HostNotFound => NetworkError.HostNotFound, + SocketError.ConnectionRefused => NetworkError.ConnectionRefused, + SocketError.OperationAborted => NetworkError.OperationAborted, + SocketError.ConnectionAborted => NetworkError.ConnectionAborted, + SocketError.ConnectionReset => NetworkError.ConnectionReset, + _ => NetworkError.Unknown + }; + + return NetworkException.Create(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" /> + EstablishConnectionAsync(HttpRequestM catch (SocketException socketException) { socket.Dispose(); - throw MapSocketException(socketException); + throw NetworkErrorHelper.MapSocketException(socketException); } catch { @@ -90,23 +90,5 @@ public virtual async ValueTask EstablishConnectionAsync(HttpRequestM throw; } } - - internal static NetworkException MapSocketException(SocketException socketException) - { - NetworkError error = socketException.SocketErrorCode switch - { - SocketError.AddressAlreadyInUse => NetworkError.AddressInUse, - SocketError.AddressFamilyNotSupported => NetworkError.InvalidAddress, - SocketError.AddressNotAvailable => NetworkError.InvalidAddress, - SocketError.HostNotFound => NetworkError.HostNotFound, - SocketError.ConnectionRefused => NetworkError.ConnectionRefused, - SocketError.OperationAborted => NetworkError.OperationAborted, - SocketError.ConnectionAborted => NetworkError.ConnectionAborted, - SocketError.ConnectionReset => NetworkError.ConnectionReset, - _ => NetworkError.Unknown - }; - - return NetworkException.Create(error, socketException); - } } } From 2185ee56a66d000d5e6af683f9f400a293c41768 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 07:18:10 -0700 Subject: [PATCH 12/17] update NetworkStream to use NetworkException --- .../src/System.Net.Sockets.csproj | 2 + .../src/System/Net/Sockets/NetworkStream.cs | 95 ++++++++++++------- .../src/System/Net/Sockets/Socket.Tasks.cs | 12 +-- .../FunctionalTests/NetworkStreamTest.cs | 38 ++++---- 4 files changed, 87 insertions(+), 60 deletions(-) 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..9e3c5c19e52822 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 NetworkException.Create(NetworkError.Unknown, innerException, message); + } } } 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 From a120d0705fed8ef72e7df9b4f67e8ee365496509 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 08:04:10 -0700 Subject: [PATCH 13/17] remove SocketConnectionNetworkStream and use NetworkStream directly --- .../Connections/SocketConnection.cs | 42 ++----------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs index 18e45ea9ded8ac..130cf634ec2990 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Connections/SocketConnection.cs @@ -13,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; @@ -21,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) @@ -40,7 +40,7 @@ protected override ValueTask CloseAsyncCore(ConnectionCloseMethod method, Cancel _stream.Socket.Dispose(); } - _stream.DisposeWithoutClosingConnection(); + _stream.Dispose(); } catch (SocketException socketException) { @@ -67,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; - } - } } } From 7785efeec3f82946b371c71df26c494583f11b38 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 11:49:02 -0700 Subject: [PATCH 14/17] remove InvalidEndPoint --- src/libraries/Common/src/System/Net/NetworkErrorHelper.cs | 2 -- .../System.Net.Primitives/ref/System.Net.Primitives.cs | 1 - src/libraries/System.Net.Primitives/src/Resources/Strings.resx | 3 --- .../System.Net.Primitives/src/System/Net/NetworkError.cs | 3 --- .../System.Net.Primitives/src/System/Net/NetworkException.cs | 1 - 5 files changed, 10 deletions(-) diff --git a/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs index 67550160602b87..b182ebe1b4d0c7 100644 --- a/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs +++ b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs @@ -12,8 +12,6 @@ internal static NetworkException MapSocketException(SocketException socketExcept NetworkError error = socketException.SocketErrorCode switch { SocketError.AddressAlreadyInUse => NetworkError.EndPointInUse, - SocketError.AddressFamilyNotSupported => NetworkError.InvalidEndPoint, - SocketError.AddressNotAvailable => NetworkError.InvalidEndPoint, SocketError.HostNotFound => NetworkError.HostNotFound, SocketError.ConnectionRefused => NetworkError.ConnectionRefused, SocketError.OperationAborted => NetworkError.OperationAborted, 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 4c5068f5b267cc..278144b9db52fb 100644 --- a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs +++ b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs @@ -327,7 +327,6 @@ public enum NetworkError : int { Unknown = 0, EndPointInUse, - InvalidEndPoint, HostNotFound, ConnectionRefused, OperationAborted, diff --git a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx index c3963a610442c0..d0dbe85701a4cd 100644 --- a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx @@ -120,9 +120,6 @@ The requested EndPoint is already in use. - - The requested EndPoint is invalid. - No connection could be made because the remote host actively refused it. diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs index f4932f6818384d..44bcac8678a289 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkError.cs @@ -12,9 +12,6 @@ public enum NetworkError : int /// The requested EndPoint is already in use. EndPointInUse, - /// The requested EndPoint is invalid. - InvalidEndPoint, - /// No such host is known. HostNotFound, diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs index 76108e67295c78..94665b8742fcbc 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -43,7 +43,6 @@ public static NetworkException Create(NetworkError error, Exception? innerExcept private static string GetExceptionMessage(NetworkError error) => error switch { NetworkError.EndPointInUse => SR.networkerror_addressinuse, - NetworkError.InvalidEndPoint => SR.networkerror_invalidaddress, NetworkError.HostNotFound => SR.networkerror_hostnotfound, NetworkError.ConnectionRefused => SR.networkerror_connectionrefused, NetworkError.ConnectionAborted => SR.networkerror_connectionaborted, From 9a17607a09dc5f28b575614b4414ba8bada95a24 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 12:01:54 -0700 Subject: [PATCH 15/17] remove factory method and update constructor arguments --- .../Common/src/System/Net/NetworkErrorHelper.cs | 2 +- .../ref/System.Net.Primitives.cs | 4 ++-- .../src/System/Net/NetworkException.cs | 17 +++++++++-------- .../FunctionalTests/NetworkExceptionTest.cs | 4 ++-- .../src/System/Net/Sockets/NetworkStream.cs | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs index b182ebe1b4d0c7..e305163ed8fe1d 100644 --- a/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs +++ b/src/libraries/Common/src/System/Net/NetworkErrorHelper.cs @@ -20,7 +20,7 @@ internal static NetworkException MapSocketException(SocketException socketExcept _ => NetworkError.Unknown }; - return NetworkException.Create(error, socketException); + return new NetworkException(error, socketException); } } } 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 278144b9db52fb..1cd070f2d98346 100644 --- a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs +++ b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs @@ -335,10 +335,10 @@ public enum NetworkError : int } public class NetworkException : System.IO.IOException { - protected NetworkException(NetworkError error, Exception? innerException = null, string? message = null) { } + 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; } } - public static NetworkException Create(NetworkError error, Exception? innerException = null, string? message = null) { throw null; } } } namespace System.Net.Cache diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs index 94665b8742fcbc..5f536bdd6b8cbf 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -11,8 +11,15 @@ namespace System.Net public class NetworkException : IOException { /// Creates a new instance of the class with the specified error code. - protected NetworkException(NetworkError error, Exception? innerException = null, string? message = null) - : base(message ?? GetExceptionMessage(error), innerException) + public NetworkException(NetworkError error, Exception? innerException = null) + : base(GetExceptionMessage(error), innerException) + { + NetworkError = error; + } + + /// 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; } @@ -34,12 +41,6 @@ public override void GetObjectData(SerializationInfo serializationInfo, Streamin /// Returns the specific kind of error. public NetworkError NetworkError { get; } - /// Creates a new instance of the class with the specified error code. - public static NetworkException Create(NetworkError error, Exception? innerException = null, string? message = null) - { - return new NetworkException(error, innerException, message); - } - private static string GetExceptionMessage(NetworkError error) => error switch { NetworkError.EndPointInUse => SR.networkerror_addressinuse, diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs index c1aee9f77c5e77..a7f60c9de1624b 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/NetworkExceptionTest.cs @@ -12,7 +12,7 @@ public static void Create_AllErrorCodes_Success() { foreach (NetworkError error in Enum.GetValues(typeof(NetworkError))) { - NetworkException e = NetworkException.Create(error); + NetworkException e = new NetworkException(error); Assert.Equal(error, e.NetworkError); Assert.Null(e.InnerException); Assert.NotNull(e.Message); @@ -25,7 +25,7 @@ public static void Create_InnerExceptionAndMessage_Success() const string Message = "Hello"; Exception inner = new Exception(); - NetworkException e = NetworkException.Create(NetworkError.Unknown, inner, Message); + 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.Sockets/src/System/Net/Sockets/NetworkStream.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs index 9e3c5c19e52822..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 @@ -795,7 +795,7 @@ private void ThrowIfDisposed() private static NetworkException GetCustomNetworkException(string message, Exception? innerException = null) { - return NetworkException.Create(NetworkError.Unknown, innerException, message); + return new NetworkException(message, NetworkError.Unknown, innerException); } } } From db769f57ad006139d58db7ac139d76b03e40b65b Mon Sep 17 00:00:00 2001 From: Geoff Kizer Date: Thu, 6 Aug 2020 12:11:31 -0700 Subject: [PATCH 16/17] Update src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs Co-authored-by: Cory Nelson --- .../System.Net.Primitives/src/System/Net/NetworkException.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs index 5f536bdd6b8cbf..267380426a92d3 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -12,10 +12,7 @@ public class NetworkException : IOException { /// Creates a new instance of the class with the specified error code. public NetworkException(NetworkError error, Exception? innerException = null) - : base(GetExceptionMessage(error), innerException) - { - NetworkError = error; - } + : 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) From c266425acda373bafd1111190682930e7d662df2 Mon Sep 17 00:00:00 2001 From: Geoffrey Kizer Date: Thu, 6 Aug 2020 12:21:15 -0700 Subject: [PATCH 17/17] add OperationAborted to GetExceptionMessage --- .../System.Net.Primitives/src/System/Net/NetworkException.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs index 267380426a92d3..7b1b48f9379142 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/NetworkException.cs @@ -45,6 +45,7 @@ public override void GetObjectData(SerializationInfo serializationInfo, Streamin NetworkError.ConnectionRefused => SR.networkerror_connectionrefused, NetworkError.ConnectionAborted => SR.networkerror_connectionaborted, NetworkError.ConnectionReset => SR.networkerror_connectionreset, + NetworkError.OperationAborted => SR.networkerror_operationaborted, _ => SR.networkerror_unknown }; }