Add support for listening to tcp handles to in the Sockets transport (#22618)
* Add support for listening to tcp handles to in the Sockets transport - Make ListenHandleTests shared across both transports Fixes #20842
This commit is contained in:
parent
b61e9b0125
commit
9e55787b84
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
@ -23,6 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
||||||
private Socket _listenSocket;
|
private Socket _listenSocket;
|
||||||
private int _schedulerIndex;
|
private int _schedulerIndex;
|
||||||
private readonly SocketTransportOptions _options;
|
private readonly SocketTransportOptions _options;
|
||||||
|
private SafeSocketHandle _socketHandle;
|
||||||
|
|
||||||
public EndPoint EndPoint { get; private set; }
|
public EndPoint EndPoint { get; private set; }
|
||||||
|
|
||||||
|
|
@ -62,33 +62,44 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
||||||
throw new InvalidOperationException(SocketsStrings.TransportAlreadyBound);
|
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;
|
Socket listenSocket;
|
||||||
|
|
||||||
// Unix domain sockets are unspecified
|
switch (EndPoint)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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);
|
try
|
||||||
}
|
{
|
||||||
catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
|
listenSocket.Bind(EndPoint);
|
||||||
{
|
}
|
||||||
throw new AddressInUseException(e.Message, e);
|
catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
|
||||||
|
{
|
||||||
|
throw new AddressInUseException(e.Message, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EndPoint = listenSocket.LocalEndPoint;
|
EndPoint = listenSocket.LocalEndPoint;
|
||||||
|
|
@ -142,12 +153,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
||||||
public ValueTask UnbindAsync(CancellationToken cancellationToken = default)
|
public ValueTask UnbindAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
_listenSocket?.Dispose();
|
_listenSocket?.Dispose();
|
||||||
|
|
||||||
|
_socketHandle?.Dispose();
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
_listenSocket?.Dispose();
|
_listenSocket?.Dispose();
|
||||||
|
|
||||||
|
_socketHandle?.Dispose();
|
||||||
|
|
||||||
// Dispose the memory pool
|
// Dispose the memory pool
|
||||||
_memoryPool.Dispose();
|
_memoryPool.Dispose();
|
||||||
return default;
|
return default;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
{
|
{
|
||||||
|
|
@ -14,13 +14,6 @@ namespace Sockets.BindTests
|
||||||
{
|
{
|
||||||
public class SocketTransportFactoryTests
|
public class SocketTransportFactoryTests
|
||||||
{
|
{
|
||||||
[Fact]
|
|
||||||
public async Task ThrowsNotSupportedExceptionWhenBindingToFileHandleEndPoint()
|
|
||||||
{
|
|
||||||
var socketTransportFactory = new SocketTransportFactory(Options.Create(new SocketTransportOptions()), Mock.Of<ILoggerFactory>());
|
|
||||||
await Assert.ThrowsAsync<NotSupportedException>(async () => await socketTransportFactory.BindAsync(new FileHandleEndPoint(0, FileHandleType.Auto)));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ThrowsNotImplementedExceptionWhenBindingToUriEndPoint()
|
public async Task ThrowsNotImplementedExceptionWhenBindingToUriEndPoint()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue