Set SO_REUSEADDR on managed listen sockets on Unix (#2111)
- https://github.com/dotnet/corefx/issues/24562
This commit is contained in:
parent
deed6c9780
commit
66a3c9496a
|
|
@ -6,10 +6,12 @@ using System.Diagnostics;
|
|||
using System.IO.Pipelines;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Protocols;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
||||
{
|
||||
|
|
@ -51,6 +53,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
|||
|
||||
var listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
|
||||
EnableRebinding(listenSocket);
|
||||
|
||||
// Kestrel expects IPv6Any to bind to both IPv6 and IPv4
|
||||
if (endPoint.Address == IPAddress.IPv6Any)
|
||||
{
|
||||
|
|
@ -128,5 +132,37 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("libc", SetLastError = true)]
|
||||
private static extern int setsockopt(IntPtr socket, int level, int option_name, IntPtr option_value, uint option_len);
|
||||
|
||||
private const int SOL_SOCKET_OSX = 0xffff;
|
||||
private const int SO_REUSEADDR_OSX = 0x0004;
|
||||
private const int SOL_SOCKET_LINUX = 0x0001;
|
||||
private const int SO_REUSEADDR_LINUX = 0x0002;
|
||||
|
||||
// Without setting SO_REUSEADDR on macOS and Linux, binding to a recently used endpoint can fail.
|
||||
// https://github.com/dotnet/corefx/issues/24562
|
||||
private unsafe void EnableRebinding(Socket listenSocket)
|
||||
{
|
||||
var optionValue = 1;
|
||||
var setsockoptStatus = 0;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
setsockoptStatus = setsockopt(listenSocket.Handle, SOL_SOCKET_LINUX, SO_REUSEADDR_LINUX,
|
||||
(IntPtr)(&optionValue), sizeof(int));
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
setsockoptStatus = setsockopt(listenSocket.Handle, SOL_SOCKET_OSX, SO_REUSEADDR_OSX,
|
||||
(IntPtr)(&optionValue), sizeof(int));
|
||||
}
|
||||
|
||||
if (setsockoptStatus != 0)
|
||||
{
|
||||
_trace.LogInformation("Setting SO_REUSEADDR failed with errno '{errno}'.", Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -526,10 +526,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
// https://github.com/dotnet/corefx/issues/24562
|
||||
[ConditionalFact]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Sockets transport fails to rebind on macOS.")]
|
||||
[OSSkipCondition(OperatingSystems.Linux, SkipReason = "Sockets transport fails to rebind on Linux.")]
|
||||
[Fact]
|
||||
public async Task CanRebindToEndPoint()
|
||||
{
|
||||
var port = GetNextPort();
|
||||
|
|
@ -566,10 +563,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
// https://github.com/dotnet/corefx/issues/24562
|
||||
[ConditionalFact]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Sockets transport fails to rebind on macOS.")]
|
||||
[OSSkipCondition(OperatingSystems.Linux, SkipReason = "Sockets transport fails to rebind on Linux.")]
|
||||
[IPv6SupportedCondition]
|
||||
public async Task CanRebindToMultipleEndPoints()
|
||||
{
|
||||
var port = GetNextPort();
|
||||
|
|
@ -892,12 +887,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
|
||||
private bool CanBindToPort()
|
||||
{
|
||||
#if MACOS && SOCKETS
|
||||
// Binding to a port with a Socket, disposing the Socket, and rebinding often fails with
|
||||
// SocketError.AddressAlreadyInUse on macOS. This isn't an issue if binding with libuv second.
|
||||
// https://github.com/dotnet/corefx/issues/24562
|
||||
return false;
|
||||
#else
|
||||
try
|
||||
{
|
||||
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
|
|
@ -910,7 +899,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue