Port back to Mono.Nat and make discovery async.

This commit is contained in:
Matthias Mailänder
2021-03-23 19:24:51 +01:00
committed by Paul Chote
parent 3f510b6d93
commit d15e7f76fc
13 changed files with 134 additions and 128 deletions

View File

@@ -56,7 +56,6 @@ namespace OpenRA
public static string EngineVersion { get; private set; }
public static LocalPlayerProfile LocalPlayerProfile;
static Task discoverNat;
static bool takeScreenshot = false;
static Benchmark benchmark = null;
@@ -360,8 +359,7 @@ namespace OpenRA
}
}
if (Settings.Server.DiscoverNatDevices)
discoverNat = UPnP.DiscoverNatDevices(Settings.Server.NatDiscoveryTimeout);
Nat.Initialize();
var modSearchArg = args.GetValue("Engine.ModSearchPaths", null);
var modSearchPaths = modSearchArg != null ?
@@ -472,16 +470,6 @@ namespace OpenRA
JoinLocal();
try
{
discoverNat?.Wait();
}
catch (Exception e)
{
Console.WriteLine("NAT discovery failed: {0}", e.Message);
Log.Write("nat", e.ToString());
}
ChromeMetrics.TryGet("ChatMessageColor", out chatMessageColor);
ChromeMetrics.TryGet("SystemMessageColor", out systemMessageColor);
if (!ChromeMetrics.TryGet("SystemMessageLabel", out systemMessageLabel))

101
OpenRA.Game/Network/Nat.cs Normal file
View File

@@ -0,0 +1,101 @@
#region Copyright & License Information
/*
* Copyright 2007-2021 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Threading;
using Mono.Nat;
namespace OpenRA.Network
{
public enum NatStatus { Enabled, Disabled, NotSupported }
public class Nat
{
public static NatStatus Status => NatUtility.IsSearching ? natDevice != null ? NatStatus.Enabled : NatStatus.NotSupported : NatStatus.Disabled;
static Mapping mapping;
static INatDevice natDevice;
static bool initialized;
public static void Initialize()
{
if (initialized)
return;
if (Game.Settings.Server.DiscoverNatDevices)
{
NatUtility.DeviceFound += DeviceFound;
NatUtility.StartDiscovery();
}
initialized = true;
}
static readonly SemaphoreSlim Locker = new SemaphoreSlim(1, 1);
static async void DeviceFound(object sender, DeviceEventArgs args)
{
await Locker.WaitAsync();
try
{
// Only interact with one at a time. Some support both UPnP and NAT-PMP.
natDevice = args.Device;
Log.Write("nat", "Device found: {0}", natDevice.DeviceEndpoint);
Log.Write("nat", "Type: {0}", natDevice.NatProtocol);
}
finally
{
Locker.Release();
}
}
public static bool TryForwardPort(int listen, int external)
{
if (natDevice == null)
return false;
var lifetime = Game.Settings.Server.NatPortMappingLifetime;
mapping = new Mapping(Protocol.Tcp, listen, external, lifetime, "OpenRA");
try
{
natDevice.CreatePortMap(mapping);
}
catch (Exception e)
{
Console.WriteLine("Port forwarding failed: {0}", e.Message);
Log.Write("nat", e.StackTrace);
return false;
}
return true;
}
public static bool TryRemovePortForward()
{
if (natDevice == null)
return false;
try
{
natDevice.DeletePortMap(mapping);
}
catch (Exception e)
{
Console.WriteLine("Port removal failed: {0}", e.Message);
Log.Write("nat", e.StackTrace);
return false;
}
return true;
}
}
}

View File

@@ -1,84 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Open.Nat;
namespace OpenRA.Network
{
public enum UPnPStatus { Enabled, Disabled, NotSupported }
public class UPnP
{
static NatDevice natDevice;
static Mapping mapping;
static bool initialized;
public static IPAddress ExternalIP { get; private set; }
public static UPnPStatus Status =>
initialized ? natDevice != null ?
UPnPStatus.Enabled : UPnPStatus.NotSupported : UPnPStatus.Disabled;
public static async Task DiscoverNatDevices(int timeout)
{
initialized = true;
NatDiscoverer.TraceSource.Switch.Level = SourceLevels.Verbose;
var logChannel = Log.Channel("nat");
NatDiscoverer.TraceSource.Listeners.Add(new TextWriterTraceListener(logChannel.Writer));
var natDiscoverer = new NatDiscoverer();
var token = new CancellationTokenSource(timeout);
natDevice = await natDiscoverer.DiscoverDeviceAsync(PortMapper.Upnp, token);
try
{
ExternalIP = await natDevice.GetExternalIPAsync();
}
catch (Exception e)
{
Console.WriteLine("Getting the external IP from NAT device failed: {0}", e.Message);
Log.Write("nat", e.StackTrace);
}
}
public static async Task ForwardPort(int listen, int external)
{
mapping = new Mapping(Protocol.Tcp, listen, external, "OpenRA");
try
{
await natDevice.CreatePortMapAsync(mapping);
}
catch (Exception e)
{
Console.WriteLine("Port forwarding failed: {0}", e.Message);
Log.Write("nat", e.StackTrace);
}
}
public static async Task RemovePortForward()
{
try
{
await natDevice.DeletePortMapAsync(mapping);
}
catch (Exception e)
{
Console.WriteLine("Port removal failed: {0}", e.Message);
Log.Write("nat", e.StackTrace);
}
}
}
}

View File

@@ -37,7 +37,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenRA-Eluant" Version="1.0.18" />
<PackageReference Include="OpenRA-Open.NAT" Version="1.0.0" />
<PackageReference Include="Mono.NAT" Version="3.0.1" />
<PackageReference Include="SharpZipLib" Version="1.3.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />

View File

@@ -221,8 +221,8 @@ namespace OpenRA.Server
if (type != ServerType.Local && settings.EnableGeoIP)
GeoIP.Initialize();
if (type != ServerType.Local && UPnP.Status == UPnPStatus.Enabled)
UPnP.ForwardPort(Settings.ListenPort, Settings.ListenPort).Wait();
if (type != ServerType.Local)
Nat.TryForwardPort(Settings.ListenPort, Settings.ListenPort);
foreach (var trait in modData.Manifest.ServerTraits)
serverTraits.Add(modData.ObjectCreator.CreateObject<ServerTrait>(trait));
@@ -310,8 +310,8 @@ namespace OpenRA.Server
if (State == ServerState.ShuttingDown)
{
EndGame();
if (type != ServerType.Local && UPnP.Status == UPnPStatus.Enabled)
UPnP.RemovePortForward().Wait();
if (type != ServerType.Local)
Nat.TryRemovePortForward();
break;
}
}

View File

@@ -49,11 +49,11 @@ namespace OpenRA
[Desc("Locks the game with a password.")]
public string Password = "";
[Desc("Allow users to enable NAT discovery for external IP detection and automatic port forwarding.")]
[Desc("Allow users to search UPnP/NAT-PMP enabled devices for automatic port forwarding.")]
public bool DiscoverNatDevices = false;
[Desc("Time in milliseconds to search for UPnP enabled NAT devices.")]
public int NatDiscoveryTimeout = 5000;
[Desc("Time in seconds for UPnP/NAT-PMP mappings to last.")]
public int NatPortMappingLifetime = 36000;
[Desc("Starts the game with a default map. Input as hash that can be obtained by the utility.")]
public string Map = null;