diff --git a/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt b/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt index 13add790593..cdb9b591509 100644 --- a/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt +++ b/src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt @@ -4758,6 +4758,7 @@ namespace Akka.Util public class static RuntimeDetector { public static readonly bool IsMono; + public static readonly bool IsWindows; } public class static StandardOutWriter { diff --git a/src/core/Akka.Remote.Tests/RemoteConfigSpec.cs b/src/core/Akka.Remote.Tests/RemoteConfigSpec.cs index 436c7b6b397..a6a088865ce 100644 --- a/src/core/Akka.Remote.Tests/RemoteConfigSpec.cs +++ b/src/core/Akka.Remote.Tests/RemoteConfigSpec.cs @@ -102,7 +102,7 @@ public void Remoting_should_contain_correct_heliosTCP_values_in_ReferenceConf() Assert.Equal(4096, s.Backlog); Assert.True(s.TcpNoDelay); Assert.True(s.TcpKeepAlive); - Assert.True(s.TcpReuseAddr); + Assert.Equal("off-for-windows", c.GetString("tcp-reuse-addr")); Assert.True(string.IsNullOrEmpty(c.GetString("hostname"))); Assert.Null(s.PublicPort); Assert.Equal(2, s.ServerSocketWorkerPoolSize); diff --git a/src/core/Akka.Remote/Configuration/Remote.conf b/src/core/Akka.Remote/Configuration/Remote.conf index e8c6255bd62..ff207b4e207 100644 --- a/src/core/Akka.Remote/Configuration/Remote.conf +++ b/src/core/Akka.Remote/Configuration/Remote.conf @@ -473,10 +473,10 @@ akka { # Enables SO_REUSEADDR, which determines when an ActorSystem can open # the specified listen port (the meaning differs between *nix and Windows) - # Valid values are "on", "off" and "off-for-windows" + # Valid values are "on", "off", and "off-for-windows" # due to the following Windows bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4476378 # "off-for-windows" of course means that it's "on" for all other platforms - tcp-reuse-addr = on + tcp-reuse-addr = off-for-windows # Used to configure the number of I/O worker threads on server sockets server-socket-worker-pool { diff --git a/src/core/Akka.Remote/Transport/DotNetty/DotNettyTransportSettings.cs b/src/core/Akka.Remote/Transport/DotNetty/DotNettyTransportSettings.cs index 3e8420a6f8a..8aaf23b4776 100644 --- a/src/core/Akka.Remote/Transport/DotNetty/DotNettyTransportSettings.cs +++ b/src/core/Akka.Remote/Transport/DotNetty/DotNettyTransportSettings.cs @@ -29,6 +29,27 @@ public static DotNettyTransportSettings Create(ActorSystem system) return Create(system.Settings.Config.GetConfig("akka.remote.dot-netty.tcp")); } + /// + /// Adds support for the "off-for-windows" option per https://github.com/akkadotnet/akka.net/issues/3293 + /// + /// The HOCON string for the akka.remote.dot-netty.tcp.reuse-addr option + /// true if we should enable REUSE_ADDR for tcp. false otherwise. + internal static bool ResolveTcpReuseAddrOption(string hoconTcpReuseAddr) + { + switch (hoconTcpReuseAddr.ToLowerInvariant()) + { + case "off-for-windows" when RuntimeDetector.IsWindows: + return false; + case "off-for-windows": + return true; + case "on": + return true; + case "off": + default: + return false; + } + } + public static DotNettyTransportSettings Create(Config config) { if (config == null) throw new ArgumentNullException(nameof(config), "DotNetty HOCON config was not found (default path: `akka.remote.dot-netty`)"); @@ -61,7 +82,7 @@ public static DotNettyTransportSettings Create(Config config) maxFrameSize: ToNullableInt(config.GetByteSize("maximum-frame-size")) ?? 128000, ssl: config.HasPath("ssl") ? SslSettings.Create(config.GetConfig("ssl")) : SslSettings.Empty, dnsUseIpv6: config.GetBoolean("dns-use-ipv6", false), - tcpReuseAddr: config.GetBoolean("tcp-reuse-addr", true), + tcpReuseAddr: ResolveTcpReuseAddrOption(config.GetString("tcp-reuse-addr", "off-for-windows")), tcpKeepAlive: config.GetBoolean("tcp-keepalive", true), tcpNoDelay: config.GetBoolean("tcp-nodelay", true), backlog: config.GetInt("backlog", 4096), diff --git a/src/core/Akka/Util/RuntimeDetector.cs b/src/core/Akka/Util/RuntimeDetector.cs index 2dfb06facdd..a5441b8a141 100644 --- a/src/core/Akka/Util/RuntimeDetector.cs +++ b/src/core/Akka/Util/RuntimeDetector.cs @@ -6,10 +6,7 @@ //----------------------------------------------------------------------- using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.InteropServices; namespace Akka.Util { @@ -28,6 +25,25 @@ public static class RuntimeDetector /// Is true if we're running on a Mono VM. false otherwise. /// public static readonly bool IsMono = Type.GetType("Mono.Runtime") != null; + + /// + /// Is true if we've detected Windows as a platform. + /// + public static readonly bool IsWindows = _IsWindows(); + + /// + /// Private implementation method not meant for public consumption + /// + /// true if the current runtime is Windows + private static bool _IsWindows() + { +#if CORECLR + return System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows); +#else + return System.Environment.OSVersion.Platform != PlatformID.MacOSX && + System.Environment.OSVersion.Platform != PlatformID.Unix; +#endif + } } }