diff --git a/src/Servers/Connections.Abstractions/src/Features/IConnectionSocketFeature.cs b/src/Servers/Connections.Abstractions/src/Features/IConnectionSocketFeature.cs new file mode 100644 index 000000000000..bef71a70b6ed --- /dev/null +++ b/src/Servers/Connections.Abstractions/src/Features/IConnectionSocketFeature.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Net.Sockets; + +namespace Microsoft.AspNetCore.Connections.Features +{ + /// + /// Provides access to the connection's underlying if any. + /// + public interface IConnectionSocketFeature + { + /// + /// Gets the underlying . + /// + Socket? Socket { get; } + } +} diff --git a/src/Servers/Connections.Abstractions/src/PublicAPI.Unshipped.txt b/src/Servers/Connections.Abstractions/src/PublicAPI.Unshipped.txt index 575c538f6a9b..f79889680abe 100644 --- a/src/Servers/Connections.Abstractions/src/PublicAPI.Unshipped.txt +++ b/src/Servers/Connections.Abstractions/src/PublicAPI.Unshipped.txt @@ -1,5 +1,7 @@ #nullable enable *REMOVED*Microsoft.AspNetCore.Connections.IConnectionListener.AcceptAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask +Microsoft.AspNetCore.Connections.Features.IConnectionSocketFeature +Microsoft.AspNetCore.Connections.Features.IConnectionSocketFeature.Socket.get -> System.Net.Sockets.Socket? Microsoft.AspNetCore.Connections.IConnectionListener.AcceptAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask Microsoft.AspNetCore.Connections.Experimental.IMultiplexedConnectionBuilder Microsoft.AspNetCore.Connections.Experimental.IMultiplexedConnectionBuilder.ApplicationServices.get -> System.IServiceProvider! diff --git a/src/Servers/Kestrel/Transport.Sockets/src/Internal/SocketConnection.cs b/src/Servers/Kestrel/Transport.Sockets/src/Internal/SocketConnection.cs index d72ccc50f7a2..3b4e0cd800ef 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/Internal/SocketConnection.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/Internal/SocketConnection.cs @@ -51,6 +51,7 @@ internal SocketConnection(Socket socket, MemoryPool = memoryPool; _trace = trace; _waitForData = waitForData; + Socket = socket; _socketSenderPool = socketSenderPool; LocalEndPoint = _socket.LocalEndPoint; diff --git a/src/Servers/Kestrel/shared/TransportConnection.FeatureCollection.cs b/src/Servers/Kestrel/shared/TransportConnection.FeatureCollection.cs index 757927e2f433..ce603419c949 100644 --- a/src/Servers/Kestrel/shared/TransportConnection.FeatureCollection.cs +++ b/src/Servers/Kestrel/shared/TransportConnection.FeatureCollection.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; +using System.Net.Sockets; using System.Threading; using Microsoft.AspNetCore.Connections.Features; @@ -38,6 +39,8 @@ CancellationToken IConnectionLifetimeFeature.ConnectionClosed set => ConnectionClosed = value; } + Socket? IConnectionSocketFeature.Socket => Socket; + void IConnectionLifetimeFeature.Abort() => Abort(new ConnectionAbortedException("The connection was aborted by the application via IConnectionLifetimeFeature.Abort().")); } } diff --git a/src/Servers/Kestrel/shared/TransportConnection.Generated.cs b/src/Servers/Kestrel/shared/TransportConnection.Generated.cs index 0f32b7d54549..ca396fbb182b 100644 --- a/src/Servers/Kestrel/shared/TransportConnection.Generated.cs +++ b/src/Servers/Kestrel/shared/TransportConnection.Generated.cs @@ -18,7 +18,8 @@ internal partial class TransportConnection : IFeatureCollection, IConnectionTransportFeature, IConnectionItemsFeature, IMemoryPoolFeature, - IConnectionLifetimeFeature + IConnectionLifetimeFeature, + IConnectionSocketFeature { // Implemented features internal protected IConnectionIdFeature? _currentIConnectionIdFeature; @@ -26,6 +27,7 @@ internal partial class TransportConnection : IFeatureCollection, internal protected IConnectionItemsFeature? _currentIConnectionItemsFeature; internal protected IMemoryPoolFeature? _currentIMemoryPoolFeature; internal protected IConnectionLifetimeFeature? _currentIConnectionLifetimeFeature; + internal protected IConnectionSocketFeature? _currentIConnectionSocketFeature; private int _featureRevision; @@ -38,6 +40,7 @@ private void FastReset() _currentIConnectionItemsFeature = this; _currentIMemoryPoolFeature = this; _currentIConnectionLifetimeFeature = this; + _currentIConnectionSocketFeature = this; } @@ -130,6 +133,10 @@ private void ExtraFeatureSet(Type key, object? value) { feature = _currentIConnectionLifetimeFeature; } + else if (key == typeof(IConnectionSocketFeature)) + { + feature = _currentIConnectionSocketFeature; + } else if (MaybeExtra != null) { feature = ExtraFeatureGet(key); @@ -162,6 +169,10 @@ private void ExtraFeatureSet(Type key, object? value) { _currentIConnectionLifetimeFeature = (IConnectionLifetimeFeature?)value; } + else if (key == typeof(IConnectionSocketFeature)) + { + _currentIConnectionSocketFeature = (IConnectionSocketFeature?)value; + } else { ExtraFeatureSet(key, value); @@ -196,6 +207,10 @@ private void ExtraFeatureSet(Type key, object? value) { feature = Unsafe.As(ref _currentIConnectionLifetimeFeature); } + else if (typeof(TFeature) == typeof(IConnectionSocketFeature)) + { + feature = Unsafe.As(ref _currentIConnectionSocketFeature); + } else if (MaybeExtra != null) { feature = (TFeature?)(ExtraFeatureGet(typeof(TFeature))); @@ -231,6 +246,10 @@ private void ExtraFeatureSet(Type key, object? value) { _currentIConnectionLifetimeFeature = Unsafe.As(ref feature); } + else if (typeof(TFeature) == typeof(IConnectionSocketFeature)) + { + _currentIConnectionSocketFeature = Unsafe.As(ref feature); + } else { ExtraFeatureSet(typeof(TFeature), feature); @@ -259,6 +278,10 @@ private IEnumerable> FastEnumerable() { yield return new KeyValuePair(typeof(IConnectionLifetimeFeature), _currentIConnectionLifetimeFeature); } + if (_currentIConnectionSocketFeature != null) + { + yield return new KeyValuePair(typeof(IConnectionSocketFeature), _currentIConnectionSocketFeature); + } if (MaybeExtra != null) { diff --git a/src/Servers/Kestrel/shared/TransportConnection.cs b/src/Servers/Kestrel/shared/TransportConnection.cs index 8a1d2b7f16bf..bef728ee83be 100644 --- a/src/Servers/Kestrel/shared/TransportConnection.cs +++ b/src/Servers/Kestrel/shared/TransportConnection.cs @@ -1,12 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO.Pipelines; using System.Net; +using System.Net.Sockets; using System.Threading; using Microsoft.AspNetCore.Http.Features; @@ -65,6 +65,8 @@ public override string ConnectionId } } + public Socket? Socket { get; protected set; } + public override CancellationToken ConnectionClosed { get; set; } // DO NOT remove this override to ConnectionContext.Abort. Doing so would cause diff --git a/src/Servers/Kestrel/tools/CodeGenerator/TransportConnectionFeatureCollection.cs b/src/Servers/Kestrel/tools/CodeGenerator/TransportConnectionFeatureCollection.cs index 60d00f404a2b..b6a762f34152 100644 --- a/src/Servers/Kestrel/tools/CodeGenerator/TransportConnectionFeatureCollection.cs +++ b/src/Servers/Kestrel/tools/CodeGenerator/TransportConnectionFeatureCollection.cs @@ -17,7 +17,8 @@ public static string GenerateFile() "IConnectionTransportFeature", "IConnectionItemsFeature", "IMemoryPoolFeature", - "IConnectionLifetimeFeature" + "IConnectionLifetimeFeature", + "IConnectionSocketFeature" }; var usings = $@"