Skip to content

Commit 9e55787

Browse files
authored
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
1 parent b61e9b0 commit 9e55787

File tree

3 files changed

+41
-30
lines changed

3 files changed

+41
-30
lines changed

src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionListener.cs

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Buffers;
6-
using System.Diagnostics;
76
using System.IO.Pipelines;
87
using System.Net;
98
using System.Net.Sockets;
@@ -23,6 +22,7 @@ internal sealed class SocketConnectionListener : IConnectionListener
2322
private Socket _listenSocket;
2423
private int _schedulerIndex;
2524
private readonly SocketTransportOptions _options;
25+
private SafeSocketHandle _socketHandle;
2626

2727
public EndPoint EndPoint { get; private set; }
2828

@@ -62,33 +62,44 @@ internal void Bind()
6262
throw new InvalidOperationException(SocketsStrings.TransportAlreadyBound);
6363
}
6464

65-
// Check if EndPoint is a FileHandleEndpoint before attempting to access EndPoint.AddressFamily
66-
// since that will throw an NotImplementedException.
67-
if (EndPoint is FileHandleEndPoint)
68-
{
69-
throw new NotSupportedException(SocketsStrings.FileHandleEndPointNotSupported);
70-
}
71-
7265
Socket listenSocket;
7366

74-
// Unix domain sockets are unspecified
75-
var protocolType = EndPoint is UnixDomainSocketEndPoint ? ProtocolType.Unspecified : ProtocolType.Tcp;
76-
77-
listenSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, protocolType);
78-
79-
// Kestrel expects IPv6Any to bind to both IPv6 and IPv4
80-
if (EndPoint is IPEndPoint ip && ip.Address == IPAddress.IPv6Any)
67+
switch (EndPoint)
8168
{
82-
listenSocket.DualMode = true;
69+
case FileHandleEndPoint fileHandle:
70+
_socketHandle = new SafeSocketHandle((IntPtr)fileHandle.FileHandle, ownsHandle: true);
71+
listenSocket = new Socket(_socketHandle);
72+
break;
73+
case UnixDomainSocketEndPoint unix:
74+
listenSocket = new Socket(unix.AddressFamily, SocketType.Stream, ProtocolType.Unspecified);
75+
BindSocket();
76+
break;
77+
case IPEndPoint ip:
78+
listenSocket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
79+
80+
// Kestrel expects IPv6Any to bind to both IPv6 and IPv4
81+
if (ip.Address == IPAddress.IPv6Any)
82+
{
83+
listenSocket.DualMode = true;
84+
}
85+
BindSocket();
86+
break;
87+
default:
88+
listenSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
89+
BindSocket();
90+
break;
8391
}
8492

85-
try
86-
{
87-
listenSocket.Bind(EndPoint);
88-
}
89-
catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
93+
void BindSocket()
9094
{
91-
throw new AddressInUseException(e.Message, e);
95+
try
96+
{
97+
listenSocket.Bind(EndPoint);
98+
}
99+
catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
100+
{
101+
throw new AddressInUseException(e.Message, e);
102+
}
92103
}
93104

94105
EndPoint = listenSocket.LocalEndPoint;
@@ -142,12 +153,17 @@ public async ValueTask<ConnectionContext> AcceptAsync(CancellationToken cancella
142153
public ValueTask UnbindAsync(CancellationToken cancellationToken = default)
143154
{
144155
_listenSocket?.Dispose();
156+
157+
_socketHandle?.Dispose();
145158
return default;
146159
}
147160

148161
public ValueTask DisposeAsync()
149162
{
150163
_listenSocket?.Dispose();
164+
165+
_socketHandle?.Dispose();
166+
151167
// Dispose the memory pool
152168
_memoryPool.Dispose();
153169
return default;

src/Servers/Kestrel/test/Libuv.FunctionalTests/ListenHandleTests.cs renamed to src/Servers/Kestrel/test/FunctionalTests/ListenHandleTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Net;
56
using System.Net.Sockets;
67
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore.Connections;
79
using Microsoft.AspNetCore.Server.Kestrel.Core;
810
using Microsoft.AspNetCore.Testing;
9-
using Microsoft.Extensions.Logging.Testing;
11+
using Xunit;
1012

1113
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
1214
{

src/Servers/Kestrel/test/Sockets.BindTests/SocketTransportFactoryTests.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@ namespace Sockets.BindTests
1414
{
1515
public class SocketTransportFactoryTests
1616
{
17-
[Fact]
18-
public async Task ThrowsNotSupportedExceptionWhenBindingToFileHandleEndPoint()
19-
{
20-
var socketTransportFactory = new SocketTransportFactory(Options.Create(new SocketTransportOptions()), Mock.Of<ILoggerFactory>());
21-
await Assert.ThrowsAsync<NotSupportedException>(async () => await socketTransportFactory.BindAsync(new FileHandleEndPoint(0, FileHandleType.Auto)));
22-
}
23-
2417
[Fact]
2518
public async Task ThrowsNotImplementedExceptionWhenBindingToUriEndPoint()
2619
{

0 commit comments

Comments
 (0)