Port back to Mono.Nat and make discovery async.
This commit is contained in:
committed by
Paul Chote
parent
3f510b6d93
commit
d15e7f76fc
5
AUTHORS
5
AUTHORS
@@ -173,9 +173,8 @@ under the MIT license.
|
||||
Using FuzzyLogicLibrary (fuzzynet) by Dmitry
|
||||
Kaluzhny and released under the GNU GPL terms.
|
||||
|
||||
Using Open.Nat by Lucas Ontivero, based on the work
|
||||
of Alan McGovern and Ben Motmans and distributed
|
||||
under the MIT license.
|
||||
Using Mono.Nat by Alan McGovern, Ben Motmans,
|
||||
Nicholas Terry distributed under the MIT license.
|
||||
|
||||
Using ICSharpCode.SharpZipLib initially by Mike
|
||||
Krueger and distributed under the GNU GPL terms.
|
||||
|
||||
@@ -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
101
OpenRA.Game/Network/Nat.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -116,20 +116,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
if (noticesNoUPnP != null)
|
||||
{
|
||||
noticesNoUPnP.IsVisible = () => advertiseOnline &&
|
||||
(UPnP.Status == UPnPStatus.NotSupported || UPnP.Status == UPnPStatus.Disabled);
|
||||
(Nat.Status == NatStatus.NotSupported || Nat.Status == NatStatus.Disabled);
|
||||
|
||||
var settingsA = noticesNoUPnP.GetOrNull("SETTINGS_A");
|
||||
if (settingsA != null)
|
||||
settingsA.IsVisible = () => UPnP.Status == UPnPStatus.Disabled;
|
||||
settingsA.IsVisible = () => Nat.Status == NatStatus.Disabled;
|
||||
|
||||
var settingsB = noticesNoUPnP.GetOrNull("SETTINGS_B");
|
||||
if (settingsB != null)
|
||||
settingsB.IsVisible = () => UPnP.Status == UPnPStatus.Disabled;
|
||||
settingsB.IsVisible = () => Nat.Status == NatStatus.Disabled;
|
||||
}
|
||||
|
||||
var noticesUPnP = panel.GetOrNull("NOTICES_UPNP");
|
||||
if (noticesUPnP != null)
|
||||
noticesUPnP.IsVisible = () => advertiseOnline && UPnP.Status == UPnPStatus.Enabled;
|
||||
noticesUPnP.IsVisible = () => advertiseOnline && Nat.Status == NatStatus.Enabled;
|
||||
|
||||
var noticesLAN = panel.GetOrNull("NOTICES_LAN");
|
||||
if (noticesLAN != null)
|
||||
@@ -145,16 +145,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
if (advertiseOnline)
|
||||
{
|
||||
noticesLabelA.Text = "Internet Server (UPnP ";
|
||||
noticesLabelA.Text = "Internet Server (UPnP/NAT-PMP ";
|
||||
var aWidth = Game.Renderer.Fonts[noticesLabelA.Font].Measure(noticesLabelA.Text).X;
|
||||
noticesLabelA.Bounds.Width = aWidth;
|
||||
|
||||
var status = UPnP.Status;
|
||||
noticesLabelB.Text = status == UPnPStatus.Enabled ? "Enabled" :
|
||||
status == UPnPStatus.NotSupported ? "Not Supported" : "Disabled";
|
||||
noticesLabelB.Text = Nat.Status == NatStatus.Enabled ? "Enabled" :
|
||||
Nat.Status == NatStatus.NotSupported ? "Not Supported" : "Disabled";
|
||||
|
||||
noticesLabelB.TextColor = status == UPnPStatus.Enabled ? ChromeMetrics.Get<Color>("NoticeSuccessColor") :
|
||||
status == UPnPStatus.NotSupported ? ChromeMetrics.Get<Color>("NoticeErrorColor") :
|
||||
noticesLabelB.TextColor = Nat.Status == NatStatus.Enabled ? ChromeMetrics.Get<Color>("NoticeSuccessColor") :
|
||||
Nat.Status == NatStatus.NotSupported ? ChromeMetrics.Get<Color>("NoticeErrorColor") :
|
||||
ChromeMetrics.Get<Color>("NoticeInfoColor");
|
||||
|
||||
var bWidth = Game.Renderer.Fonts[noticesLabelB.Font].Measure(noticesLabelB.Text).X;
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Server
|
||||
@@ -56,6 +57,8 @@ namespace OpenRA.Server
|
||||
Game.InitializeSettings(arguments);
|
||||
var settings = Game.Settings.Server;
|
||||
|
||||
Nat.Initialize();
|
||||
|
||||
var envModSearchPaths = Environment.GetEnvironmentVariable("MOD_SEARCH_PATHS");
|
||||
var modSearchPaths = !string.IsNullOrWhiteSpace(envModSearchPaths) ?
|
||||
FieldLoader.GetValue<string[]>("MOD_SEARCH_PATHS", envModSearchPaths) :
|
||||
|
||||
@@ -162,7 +162,7 @@ Container@MULTIPLAYER_CREATESERVER_PANEL:
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: - You can enable UPnP (if supported by your router) in the
|
||||
Text: - You can enable UPnP/NAT-PMP (if supported by your router)
|
||||
Label@SETTINGS_B:
|
||||
X: 7
|
||||
Y: 60
|
||||
@@ -170,7 +170,7 @@ Container@MULTIPLAYER_CREATESERVER_PANEL:
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: Advanced tab of the OpenRA settings menu.
|
||||
Text: in the Advanced tab of the settings menu.
|
||||
Container@NOTICES_UPNP:
|
||||
X: 20
|
||||
Y: 145
|
||||
@@ -196,14 +196,14 @@ Container@MULTIPLAYER_CREATESERVER_PANEL:
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: - OpenRA will use UPnP to automaticaly configure port forwarding.
|
||||
Text: - Game will automatically configure port forwarding.
|
||||
Label@SETTINGS_A:
|
||||
Y: 36
|
||||
Width: 305
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: - You can disable UPnP in the OpenRA settings menu.
|
||||
Text: - You can disable UPnP/NAT-PMP in the settings menu.
|
||||
Background@MAP_BG:
|
||||
X: PARENT_RIGHT - 189
|
||||
Y: 15
|
||||
|
||||
@@ -15,7 +15,7 @@ Container@ADVANCED_PANEL:
|
||||
Width: 200
|
||||
Height: 20
|
||||
Font: Regular
|
||||
Text: Enable Network Discovery (UPnP)
|
||||
Text: Enable UPnP/NAT-PMP Discovery
|
||||
Checkbox@PERFTEXT_CHECKBOX:
|
||||
X: 15
|
||||
Y: 73
|
||||
|
||||
@@ -157,7 +157,7 @@ Background@MULTIPLAYER_CREATESERVER_PANEL:
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: - You can enable UPnP (if supported by your router) in the
|
||||
Text: - You can enable UPnP/NAT-PMP (if supported by your router)
|
||||
Label@SETTINGS_B:
|
||||
X: 7
|
||||
Y: 60
|
||||
@@ -165,7 +165,7 @@ Background@MULTIPLAYER_CREATESERVER_PANEL:
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: Advanced tab of the OpenRA settings menu.
|
||||
Text: in the Advanced tab of the settings menu.
|
||||
Container@NOTICES_UPNP:
|
||||
X: 25
|
||||
Y: 176
|
||||
@@ -191,14 +191,14 @@ Background@MULTIPLAYER_CREATESERVER_PANEL:
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: - OpenRA will use UPnP to automaticaly configure port forwarding.
|
||||
Text: - Game will automatically configure port forwarding.
|
||||
Label@SETTINGS_A:
|
||||
Y: 36
|
||||
Width: 305
|
||||
Height: 25
|
||||
Font: Tiny
|
||||
Align: Left
|
||||
Text: - You can disable UPnP in the OpenRA settings menu.
|
||||
Text: - You can disable UPnP/NAT-PMP in the settings menu.
|
||||
Background@MAP_BG:
|
||||
X: PARENT_RIGHT - 194
|
||||
Y: 45
|
||||
|
||||
@@ -9,7 +9,7 @@ Container@ADVANCED_PANEL:
|
||||
Width: 200
|
||||
Height: 20
|
||||
Font: Regular
|
||||
Text: Enable Network Discovery (UPnP)
|
||||
Text: Enable UPnP/NAT-PMP Discovery
|
||||
Checkbox@PERFTEXT_CHECKBOX:
|
||||
X: 15
|
||||
Y: 73
|
||||
|
||||
Reference in New Issue
Block a user