diff --git a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionListener.cs b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionListener.cs index 4c49a90233..a98ec04363 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionListener.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionListener.cs @@ -3,7 +3,6 @@ using System; using System.Buffers; -using System.Diagnostics; using System.IO.Pipelines; using System.Net; using System.Net.Sockets; @@ -23,6 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets private Socket _listenSocket; private int _schedulerIndex; private readonly SocketTransportOptions _options; + private SafeSocketHandle _socketHandle; public EndPoint EndPoint { get; private set; } @@ -62,33 +62,44 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets throw new InvalidOperationException(SocketsStrings.TransportAlreadyBound); } - // Check if EndPoint is a FileHandleEndpoint before attempting to access EndPoint.AddressFamily - // since that will throw an NotImplementedException. - if (EndPoint is FileHandleEndPoint) - { - throw new NotSupportedException(SocketsStrings.FileHandleEndPointNotSupported); - } - Socket listenSocket; - // Unix domain sockets are unspecified - var protocolType = EndPoint is UnixDomainSocketEndPoint ? ProtocolType.Unspecified : ProtocolType.Tcp; - - listenSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, protocolType); - - // Kestrel expects IPv6Any to bind to both IPv6 and IPv4 - if (EndPoint is IPEndPoint ip && ip.Address == IPAddress.IPv6Any) + switch (EndPoint) { - listenSocket.DualMode = true; + case FileHandleEndPoint fileHandle: + _socketHandle = new SafeSocketHandle((IntPtr)fileHandle.FileHandle, ownsHandle: true); + listenSocket = new Socket(_socketHandle); + break; + case UnixDomainSocketEndPoint unix: + listenSocket = new Socket(unix.AddressFamily, SocketType.Stream, ProtocolType.Unspecified); + BindSocket(); + break; + case IPEndPoint ip: + listenSocket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + + // Kestrel expects IPv6Any to bind to both IPv6 and IPv4 + if (ip.Address == IPAddress.IPv6Any) + { + listenSocket.DualMode = true; + } + BindSocket(); + break; + default: + listenSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + BindSocket(); + break; } - try + void BindSocket() { - listenSocket.Bind(EndPoint); - } - catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse) - { - throw new AddressInUseException(e.Message, e); + try + { + listenSocket.Bind(EndPoint); + } + catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse) + { + throw new AddressInUseException(e.Message, e); + } } EndPoint = listenSocket.LocalEndPoint; @@ -142,12 +153,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets public ValueTask UnbindAsync(CancellationToken cancellationToken = default) { _listenSocket?.Dispose(); + + _socketHandle?.Dispose(); return default; } public ValueTask DisposeAsync() { _listenSocket?.Dispose(); + + _socketHandle?.Dispose(); + // Dispose the memory pool _memoryPool.Dispose(); return default; diff --git a/src/Servers/Kestrel/test/Libuv.FunctionalTests/ListenHandleTests.cs b/src/Servers/Kestrel/test/FunctionalTests/ListenHandleTests.cs similarity index 97% rename from src/Servers/Kestrel/test/Libuv.FunctionalTests/ListenHandleTests.cs rename to src/Servers/Kestrel/test/FunctionalTests/ListenHandleTests.cs index 672e55dc7d..a9cac6f788 100644 --- a/src/Servers/Kestrel/test/Libuv.FunctionalTests/ListenHandleTests.cs +++ b/src/Servers/Kestrel/test/FunctionalTests/ListenHandleTests.cs @@ -1,12 +1,14 @@ // 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.Net; using System.Net.Sockets; using System.Threading.Tasks; +using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Testing; -using Microsoft.Extensions.Logging.Testing; +using Xunit; namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { diff --git a/src/Servers/Kestrel/test/Sockets.BindTests/SocketTransportFactoryTests.cs b/src/Servers/Kestrel/test/Sockets.BindTests/SocketTransportFactoryTests.cs index b67e2dfcaa..77acddd957 100644 --- a/src/Servers/Kestrel/test/Sockets.BindTests/SocketTransportFactoryTests.cs +++ b/src/Servers/Kestrel/test/Sockets.BindTests/SocketTransportFactoryTests.cs @@ -14,13 +14,6 @@ namespace Sockets.BindTests { public class SocketTransportFactoryTests { - [Fact] - public async Task ThrowsNotSupportedExceptionWhenBindingToFileHandleEndPoint() - { - var socketTransportFactory = new SocketTransportFactory(Options.Create(new SocketTransportOptions()), Mock.Of()); - await Assert.ThrowsAsync(async () => await socketTransportFactory.BindAsync(new FileHandleEndPoint(0, FileHandleType.Auto))); - } - [Fact] public async Task ThrowsNotImplementedExceptionWhenBindingToUriEndPoint() {