Merge pull request #2403 from Mailaender/mono-nat
Use Mono.Nat for UPnP port forwarding.
This commit is contained in:
3
Makefile
3
Makefile
@@ -1,7 +1,7 @@
|
|||||||
CSC = gmcs
|
CSC = gmcs
|
||||||
CSFLAGS = -nologo -warn:4 -debug:full -optimize- -codepage:utf8 -unsafe -warnaserror
|
CSFLAGS = -nologo -warn:4 -debug:full -optimize- -codepage:utf8 -unsafe -warnaserror
|
||||||
DEFINE = DEBUG;TRACE
|
DEFINE = DEBUG;TRACE
|
||||||
COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll thirdparty/ICSharpCode.SharpZipLib.dll thirdparty/FuzzyLogicLibrary.dll
|
COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll thirdparty/ICSharpCode.SharpZipLib.dll thirdparty/FuzzyLogicLibrary.dll thirdparty/Mono.Nat.dll
|
||||||
PHONY = core tools package all mods clean distclean dependencies
|
PHONY = core tools package all mods clean distclean dependencies
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
@@ -258,6 +258,7 @@ install: all
|
|||||||
@$(INSTALL_PROGRAM) thirdparty/FuzzyLogicLibrary.dll $(INSTALL_DIR)
|
@$(INSTALL_PROGRAM) thirdparty/FuzzyLogicLibrary.dll $(INSTALL_DIR)
|
||||||
@$(INSTALL_PROGRAM) thirdparty/SharpFont.dll $(INSTALL_DIR)
|
@$(INSTALL_PROGRAM) thirdparty/SharpFont.dll $(INSTALL_DIR)
|
||||||
@cp thirdparty/SharpFont.dll.config $(INSTALL_DIR)
|
@cp thirdparty/SharpFont.dll.config $(INSTALL_DIR)
|
||||||
|
@$(INSTALL_PROGRAM) thirdparty/Mono.Nat.dll $(INSTALL_DIR)
|
||||||
|
|
||||||
@echo "#!/bin/sh" > openra
|
@echo "#!/bin/sh" > openra
|
||||||
@echo 'BINDIR=$$(dirname $$(readlink -f $$0))' >> openra
|
@echo 'BINDIR=$$(dirname $$(readlink -f $$0))' >> openra
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace OpenRA
|
|||||||
public static class Log
|
public static class Log
|
||||||
{
|
{
|
||||||
static string LogPathPrefix = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar;
|
static string LogPathPrefix = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar;
|
||||||
static Dictionary<string, ChannelInfo> channels = new Dictionary<string,ChannelInfo>();
|
public static readonly Dictionary<string, ChannelInfo> Channels = new Dictionary<string, ChannelInfo>();
|
||||||
|
|
||||||
public static string LogPath
|
public static string LogPath
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
public static void AddChannel(string channelName, string baseFilename)
|
public static void AddChannel(string channelName, string baseFilename)
|
||||||
{
|
{
|
||||||
if (channels.ContainsKey(channelName)) return;
|
if (Channels.ContainsKey(channelName)) return;
|
||||||
|
|
||||||
foreach (var filename in FilenamesForChannel(channelName, baseFilename))
|
foreach (var filename in FilenamesForChannel(channelName, baseFilename))
|
||||||
try
|
try
|
||||||
@@ -55,7 +55,7 @@ namespace OpenRA
|
|||||||
var writer = File.CreateText(filename);
|
var writer = File.CreateText(filename);
|
||||||
writer.AutoFlush = true;
|
writer.AutoFlush = true;
|
||||||
|
|
||||||
channels.Add(channelName,
|
Channels.Add(channelName,
|
||||||
new ChannelInfo()
|
new ChannelInfo()
|
||||||
{
|
{
|
||||||
Filename = filename,
|
Filename = filename,
|
||||||
@@ -70,7 +70,7 @@ namespace OpenRA
|
|||||||
public static void Write(string channel, string format, params object[] args)
|
public static void Write(string channel, string format, params object[] args)
|
||||||
{
|
{
|
||||||
ChannelInfo info;
|
ChannelInfo info;
|
||||||
if (!channels.TryGetValue(channel, out info))
|
if (!Channels.TryGetValue(channel, out info))
|
||||||
throw new Exception("Tried logging to non-existant channel " + channel);
|
throw new Exception("Tried logging to non-existant channel " + channel);
|
||||||
|
|
||||||
info.Writer.WriteLine(format, args);
|
info.Writer.WriteLine(format, args);
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ using OpenRA.Network;
|
|||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
|
using Mono.Nat;
|
||||||
|
using Mono.Nat.Pmp;
|
||||||
|
using Mono.Nat.Upnp;
|
||||||
|
|
||||||
using XRandom = OpenRA.Thirdparty.Random;
|
using XRandom = OpenRA.Thirdparty.Random;
|
||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
@@ -34,6 +38,8 @@ namespace OpenRA
|
|||||||
public static ModData modData;
|
public static ModData modData;
|
||||||
static WorldRenderer worldRenderer;
|
static WorldRenderer worldRenderer;
|
||||||
|
|
||||||
|
public static INatDevice natDevice;
|
||||||
|
|
||||||
public static Viewport viewport;
|
public static Viewport viewport;
|
||||||
public static Settings Settings;
|
public static Settings Settings;
|
||||||
|
|
||||||
@@ -257,6 +263,24 @@ namespace OpenRA
|
|||||||
Log.AddChannel("perf", "perf.log");
|
Log.AddChannel("perf", "perf.log");
|
||||||
Log.AddChannel("debug", "debug.log");
|
Log.AddChannel("debug", "debug.log");
|
||||||
Log.AddChannel("sync", "syncreport.log");
|
Log.AddChannel("sync", "syncreport.log");
|
||||||
|
Log.AddChannel("server", "server.log");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NatUtility.Logger = Log.Channels["server"].Writer;
|
||||||
|
NatUtility.Verbose = Settings.Server.VerboseNatDiscovery;
|
||||||
|
NatUtility.DeviceFound += DeviceFound;
|
||||||
|
NatUtility.DeviceLost += DeviceLost;
|
||||||
|
Settings.Server.NatDeviceAvailable = false;
|
||||||
|
NatUtility.StartDiscovery();
|
||||||
|
Log.Write("server", "NAT discovery started.");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Write("server", "Can't discover UPnP-enabled device: {0}", e);
|
||||||
|
Settings.Server.NatDeviceAvailable = false;
|
||||||
|
Settings.Server.AllowUPnP = false;
|
||||||
|
}
|
||||||
|
|
||||||
FileSystem.Mount("."); // Needed to access shaders
|
FileSystem.Mount("."); // Needed to access shaders
|
||||||
Renderer.Initialize( Game.Settings.Graphics.Mode );
|
Renderer.Initialize( Game.Settings.Graphics.Mode );
|
||||||
@@ -268,6 +292,44 @@ namespace OpenRA
|
|||||||
|
|
||||||
Sound.Create(Settings.Sound.Engine);
|
Sound.Create(Settings.Sound.Engine);
|
||||||
InitializeWithMods(Settings.Game.Mods);
|
InitializeWithMods(Settings.Game.Mods);
|
||||||
|
|
||||||
|
RunAfterDelay(Settings.Server.NatDiscoveryTimeout, () =>
|
||||||
|
{
|
||||||
|
NatUtility.StopDiscovery();
|
||||||
|
Log.Write("server", "NAT discovery stopped.");
|
||||||
|
if (natDevice == null)
|
||||||
|
{
|
||||||
|
Log.Write("server", "No NAT devices with UPnP enabled found within {0} ms deadline. Disabling automatic port forwarding.".F(Settings.Server.NatDiscoveryTimeout));
|
||||||
|
Settings.Server.NatDeviceAvailable = false;
|
||||||
|
Settings.Server.AllowUPnP = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DeviceFound(object sender, DeviceEventArgs args)
|
||||||
|
{
|
||||||
|
natDevice = args.Device;
|
||||||
|
|
||||||
|
Log.Write("server", "NAT device discovered.");
|
||||||
|
Log.Write("server", "Type: {0}", natDevice.GetType());
|
||||||
|
Log.Write("server", "Your external IP is: {0}", natDevice.GetExternalIP());
|
||||||
|
|
||||||
|
foreach (var mp in natDevice.GetAllMappings())
|
||||||
|
Log.Write("server", "Existing port mapping: protocol={0}, public={1}, private={2}", mp.Protocol, mp.PublicPort, mp.PrivatePort);
|
||||||
|
|
||||||
|
Settings.Server.NatDeviceAvailable = true;
|
||||||
|
Settings.Server.AllowUPnP = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DeviceLost(object sender, DeviceEventArgs args)
|
||||||
|
{
|
||||||
|
natDevice = args.Device;
|
||||||
|
|
||||||
|
Log.Write("server", "NAT device lost.");
|
||||||
|
Log.Write("server", "Type: {0}", natDevice.GetType());
|
||||||
|
|
||||||
|
Settings.Server.NatDeviceAvailable = false;
|
||||||
|
Settings.Server.AllowUPnP = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InitializeWithMods(string[] mods)
|
public static void InitializeWithMods(string[] mods)
|
||||||
@@ -416,7 +478,7 @@ namespace OpenRA
|
|||||||
public static void CreateServer(ServerSettings settings)
|
public static void CreateServer(ServerSettings settings)
|
||||||
{
|
{
|
||||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort),
|
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort),
|
||||||
Game.Settings.Game.Mods, settings, modData);
|
Game.Settings.Game.Mods, settings, modData, natDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int CreateLocalServer(string map)
|
public static int CreateLocalServer(string map)
|
||||||
@@ -433,7 +495,7 @@ namespace OpenRA
|
|||||||
settings.AllowUPnP = false;
|
settings.AllowUPnP = false;
|
||||||
|
|
||||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0),
|
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0),
|
||||||
Game.Settings.Game.Mods, settings, modData);
|
Game.Settings.Game.Mods, settings, modData, natDevice);
|
||||||
|
|
||||||
return server.Port;
|
return server.Port;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ namespace OpenRA.GameRules
|
|||||||
public int ExternalPort = 1234;
|
public int ExternalPort = 1234;
|
||||||
public bool AdvertiseOnline = true;
|
public bool AdvertiseOnline = true;
|
||||||
public string MasterServer = "http://master.open-ra.org/";
|
public string MasterServer = "http://master.open-ra.org/";
|
||||||
public bool AllowUPnP = false;
|
public bool AllowUPnP = true; // let the user disable it
|
||||||
|
public bool NatDeviceAvailable = false; // internal check if discovery succeeded
|
||||||
|
public int NatDiscoveryTimeout = 1000; // ms to search for UPnP enabled NATs
|
||||||
|
public bool VerboseNatDiscovery = false; // print very detailed logs for debugging
|
||||||
public bool AllowCheats = false;
|
public bool AllowCheats = false;
|
||||||
public string Map = null;
|
public string Map = null;
|
||||||
public string[] Ban = null;
|
public string[] Ban = null;
|
||||||
@@ -49,6 +52,9 @@ namespace OpenRA.GameRules
|
|||||||
AdvertiseOnline = other.AdvertiseOnline;
|
AdvertiseOnline = other.AdvertiseOnline;
|
||||||
MasterServer = other.MasterServer;
|
MasterServer = other.MasterServer;
|
||||||
AllowUPnP = other.AllowUPnP;
|
AllowUPnP = other.AllowUPnP;
|
||||||
|
NatDeviceAvailable = other.NatDeviceAvailable;
|
||||||
|
NatDiscoveryTimeout = other.NatDiscoveryTimeout;
|
||||||
|
VerboseNatDiscovery = other.VerboseNatDiscovery;
|
||||||
AllowCheats = other.AllowCheats;
|
AllowCheats = other.AllowCheats;
|
||||||
Map = other.Map;
|
Map = other.Map;
|
||||||
Ban = other.Ban;
|
Ban = other.Ban;
|
||||||
|
|||||||
@@ -60,8 +60,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core">
|
<Reference Include="System.Core" />
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
@@ -70,6 +69,12 @@
|
|||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\thirdparty\SharpFont.dll</HintPath>
|
<HintPath>..\thirdparty\SharpFont.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Mono.Nat, Version=1.1.0.0, Culture=neutral">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<Private>False</Private>
|
||||||
|
<Package>mono.nat</Package>
|
||||||
|
<HintPath>..\thirdparty\Mono.Nat.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Tao.OpenAl, Version=1.1.0.1, Culture=neutral, PublicKeyToken=a7579dda88828311">
|
<Reference Include="Tao.OpenAl, Version=1.1.0.1, Culture=neutral, PublicKeyToken=a7579dda88828311">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\thirdparty\Tao\Tao.OpenAl.dll</HintPath>
|
<HintPath>..\thirdparty\Tao\Tao.OpenAl.dll</HintPath>
|
||||||
@@ -151,7 +156,6 @@
|
|||||||
<Compile Include="Server\Server.cs" />
|
<Compile Include="Server\Server.cs" />
|
||||||
<Compile Include="Server\ServerOrder.cs" />
|
<Compile Include="Server\ServerOrder.cs" />
|
||||||
<Compile Include="Server\TraitInterfaces.cs" />
|
<Compile Include="Server\TraitInterfaces.cs" />
|
||||||
<Compile Include="Server\UPnP.cs" />
|
|
||||||
<Compile Include="Sound.cs" />
|
<Compile Include="Sound.cs" />
|
||||||
<Compile Include="Support\Arguments.cs" />
|
<Compile Include="Support\Arguments.cs" />
|
||||||
<Compile Include="Support\PerfHistory.cs" />
|
<Compile Include="Support\PerfHistory.cs" />
|
||||||
|
|||||||
@@ -16,14 +16,18 @@ using System.Linq;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using UPnP;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.GameRules;
|
using OpenRA.GameRules;
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
|
|
||||||
using XTimer = System.Timers.Timer;
|
using XTimer = System.Timers.Timer;
|
||||||
|
|
||||||
|
using Mono.Nat;
|
||||||
|
using Mono.Nat.Pmp;
|
||||||
|
using Mono.Nat.Upnp;
|
||||||
|
|
||||||
namespace OpenRA.Server
|
namespace OpenRA.Server
|
||||||
{
|
{
|
||||||
public enum ServerState : int
|
public enum ServerState : int
|
||||||
@@ -50,6 +54,8 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
public readonly IPAddress Ip;
|
public readonly IPAddress Ip;
|
||||||
public readonly int Port;
|
public readonly int Port;
|
||||||
|
public INatDevice NatDevice;
|
||||||
|
|
||||||
int randomSeed;
|
int randomSeed;
|
||||||
public readonly Thirdparty.Random Random = new Thirdparty.Random();
|
public readonly Thirdparty.Random Random = new Thirdparty.Random();
|
||||||
|
|
||||||
@@ -74,11 +80,9 @@ namespace OpenRA.Server
|
|||||||
{
|
{
|
||||||
foreach (var t in ServerTraits.WithInterface<IEndGame>())
|
foreach (var t in ServerTraits.WithInterface<IEndGame>())
|
||||||
t.GameEnded(this);
|
t.GameEnded(this);
|
||||||
if (Settings.AllowUPnP)
|
|
||||||
RemovePortforward();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData)
|
public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData, INatDevice natDevice)
|
||||||
{
|
{
|
||||||
Log.AddChannel("server", "server.log");
|
Log.AddChannel("server", "server.log");
|
||||||
|
|
||||||
@@ -91,46 +95,12 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
ModData = modData;
|
ModData = modData;
|
||||||
|
NatDevice = natDevice;
|
||||||
|
|
||||||
randomSeed = (int)DateTime.Now.ToBinary();
|
randomSeed = (int)DateTime.Now.ToBinary();
|
||||||
|
|
||||||
if (Settings.AllowUPnP)
|
if (Settings.AllowUPnP)
|
||||||
{
|
ForwardPort();
|
||||||
try
|
|
||||||
{
|
|
||||||
if (UPnP.NAT.Discover())
|
|
||||||
{
|
|
||||||
Log.Write("server", "UPnP-enabled router discovered.");
|
|
||||||
Log.Write("server", "Your IP is: {0}", UPnP.NAT.GetExternalIP() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Write("server", "No UPnP-enabled router detected.");
|
|
||||||
Settings.AllowUPnP = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
OpenRA.Log.Write("server", "Can't discover UPnP-enabled routers: {0}", e);
|
|
||||||
Settings.AllowUPnP = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings.AllowUPnP)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (UPnP.NAT.ForwardPort(Port, ProtocolType.Tcp, "OpenRA"))
|
|
||||||
Log.Write("server", "Port {0} (TCP) has been forwarded.", Port);
|
|
||||||
else
|
|
||||||
Settings.AllowUPnP = false;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
OpenRA.Log.Write("server", "Can not forward ports via UPnP: {0}", e);
|
|
||||||
Settings.AllowUPnP = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var trait in modData.Manifest.ServerTraits)
|
foreach (var trait in modData.Manifest.ServerTraits)
|
||||||
ServerTraits.Add( modData.ObjectCreator.CreateObject<ServerTrait>(trait) );
|
ServerTraits.Add( modData.ObjectCreator.CreateObject<ServerTrait>(trait) );
|
||||||
@@ -156,7 +126,7 @@ namespace OpenRA.Server
|
|||||||
var timeout = ServerTraits.WithInterface<ITick>().Min(t => t.TickTimeout);
|
var timeout = ServerTraits.WithInterface<ITick>().Min(t => t.TickTimeout);
|
||||||
for( ; ; )
|
for( ; ; )
|
||||||
{
|
{
|
||||||
var checkRead = new ArrayList();
|
var checkRead = new List<Socket>();
|
||||||
checkRead.Add( listener.Server );
|
checkRead.Add( listener.Server );
|
||||||
foreach( var c in conns ) checkRead.Add( c.socket );
|
foreach( var c in conns ) checkRead.Add( c.socket );
|
||||||
foreach( var c in preConns ) checkRead.Add( c.socket );
|
foreach( var c in preConns ) checkRead.Add( c.socket );
|
||||||
@@ -168,7 +138,7 @@ namespace OpenRA.Server
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach( Socket s in checkRead )
|
foreach( var s in checkRead )
|
||||||
if( s == listener.Server ) AcceptConnection();
|
if( s == listener.Server ) AcceptConnection();
|
||||||
else if (preConns.Count > 0)
|
else if (preConns.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -187,6 +157,8 @@ namespace OpenRA.Server
|
|||||||
if (State == ServerState.ShuttingDown)
|
if (State == ServerState.ShuttingDown)
|
||||||
{
|
{
|
||||||
EndGame();
|
EndGame();
|
||||||
|
if (Settings.AllowUPnP)
|
||||||
|
RemovePortforward();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,16 +174,33 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForwardPort()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var mapping = new Mapping(Protocol.Tcp, Settings.ExternalPort, Settings.ListenPort);
|
||||||
|
NatDevice.CreatePortMap(mapping);
|
||||||
|
Log.Write("server", "Create port mapping: protocol={0}, public={1}, private={2}", mapping.Protocol, mapping.PublicPort, mapping.PrivatePort);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Write("server", "Can not forward ports via UPnP: {0}", e);
|
||||||
|
Settings.AllowUPnP = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RemovePortforward()
|
void RemovePortforward()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (UPnP.NAT.DeleteForwardingRule(Port, ProtocolType.Tcp))
|
var mapping = new Mapping(Protocol.Tcp, Settings.ExternalPort, Settings.ListenPort);
|
||||||
Log.Write("server", "Port {0} (TCP) forwarding rules has been removed.", Port);
|
NatDevice.DeletePortMap(mapping);
|
||||||
|
Log.Write("server", "Remove port mapping: protocol={0}, public={1}, private={2}", mapping.Protocol, mapping.PublicPort, mapping.PrivatePort);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
OpenRA.Log.Write("server", "Can not remove UPnP portforwarding rules: {0}", e);
|
Log.Write("server", "Can not remove UPnP portforwarding rules: {0}", e);
|
||||||
|
Settings.AllowUPnP = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2008-2009 http://www.codeproject.com/Members/Harold-Aptroot
|
|
||||||
* Source: http://www.codeproject.com/Articles/27992/NAT-Traversal-with-UPnP-in-C
|
|
||||||
* This file is licensed under A Public Domain dedication.
|
|
||||||
* For more information, see http://creativecommons.org/licenses/publicdomain/
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Net;
|
|
||||||
using System.Xml;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace UPnP
|
|
||||||
{
|
|
||||||
public class NAT
|
|
||||||
{
|
|
||||||
static string _serviceUrl;
|
|
||||||
|
|
||||||
public static bool Discover()
|
|
||||||
{
|
|
||||||
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
|
||||||
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
|
||||||
s.ReceiveTimeout = 3000; //3 seconds
|
|
||||||
string req = "M-SEARCH * HTTP/1.1\r\n" +
|
|
||||||
"HOST: 239.255.255.250:1900\r\n" +
|
|
||||||
"ST:upnp:rootdevice\r\n" +
|
|
||||||
"MAN:\"ssdp:discover\"\r\n" +
|
|
||||||
"MX:3\r\n\r\n";
|
|
||||||
byte[] data = Encoding.ASCII.GetBytes(req);
|
|
||||||
IPEndPoint ipe = new IPEndPoint(IPAddress.Broadcast, 1900);
|
|
||||||
byte[] buffer = new byte[0x1000];
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
s.SendTo(data, ipe);
|
|
||||||
int length = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
length = s.Receive(buffer);
|
|
||||||
|
|
||||||
string resp = Encoding.ASCII.GetString(buffer, 0, length).ToLower();
|
|
||||||
if (resp.Contains("upnp:rootdevice"))
|
|
||||||
{
|
|
||||||
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
|
|
||||||
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
|
|
||||||
if (!string.IsNullOrEmpty(_serviceUrl = GetServiceUrl(resp)))
|
|
||||||
{
|
|
||||||
s.Close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (length > 0);
|
|
||||||
s.Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
s.Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String GetServiceUrl(string resp)
|
|
||||||
{
|
|
||||||
XmlDocument desc = new XmlDocument();
|
|
||||||
HttpWebRequest r = (HttpWebRequest)WebRequest.Create(resp);
|
|
||||||
r.KeepAlive = false;
|
|
||||||
using (WebResponse wres = r.GetResponse())
|
|
||||||
{
|
|
||||||
using (Stream ress = wres.GetResponseStream())
|
|
||||||
{
|
|
||||||
desc.Load(ress);
|
|
||||||
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
|
|
||||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
|
||||||
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
|
|
||||||
if (!typen.Value.Contains("InternetGatewayDevice"))
|
|
||||||
return null;
|
|
||||||
XmlNode node = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:controlURL/text()", nsMgr);
|
|
||||||
if (node == null)
|
|
||||||
return null;
|
|
||||||
Uri respUri = new Uri(resp);
|
|
||||||
Uri combinedUri = new Uri(respUri, node.Value);
|
|
||||||
return combinedUri.AbsoluteUri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ForwardPort(int port, ProtocolType protocol, string description)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_serviceUrl))
|
|
||||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
|
||||||
string body = String.Format("<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"+
|
|
||||||
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
|
||||||
"<NewProtocol>{1}</NewProtocol><NewInternalPort>{0}</NewInternalPort>" +
|
|
||||||
"<NewInternalClient>{2}</NewInternalClient><NewEnabled>1</NewEnabled>" +
|
|
||||||
"<NewPortMappingDescription>{3}</NewPortMappingDescription>"+
|
|
||||||
"<NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping>",
|
|
||||||
port, protocol.ToString().ToUpper(),Dns.GetHostAddresses(Dns.GetHostName())[0], description);
|
|
||||||
if (SOAPRequest(_serviceUrl, body, "AddPortMapping") != null)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool DeleteForwardingRule(int port, ProtocolType protocol)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_serviceUrl))
|
|
||||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
|
||||||
string body = String.Format("<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
|
|
||||||
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
|
||||||
"<NewProtocol>{1}</NewProtocol></u:DeletePortMapping>", port, protocol.ToString().ToUpper() );
|
|
||||||
if (SOAPRequest(_serviceUrl, body, "DeletePortMapping") != null)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IPAddress GetExternalIP()
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_serviceUrl))
|
|
||||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
|
||||||
XmlDocument xdoc = SOAPRequest(_serviceUrl, "<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
|
|
||||||
"</u:GetExternalIPAddress>", "GetExternalIPAddress");
|
|
||||||
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
|
|
||||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
|
||||||
string IP = xdoc.SelectSingleNode("//NewExternalIPAddress/text()", nsMgr).Value;
|
|
||||||
return IPAddress.Parse(IP);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static XmlDocument SOAPRequest(string url, string soap, string function)
|
|
||||||
{
|
|
||||||
string body = "<?xml version=\"1.0\"?>" +
|
|
||||||
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
|
|
||||||
"<s:Body>" +
|
|
||||||
soap +
|
|
||||||
"</s:Body>" +
|
|
||||||
"</s:Envelope>";
|
|
||||||
HttpWebRequest r = (HttpWebRequest)WebRequest.Create(url);
|
|
||||||
r.KeepAlive = false;
|
|
||||||
r.Method = "POST";
|
|
||||||
byte[] b = Encoding.UTF8.GetBytes(body);
|
|
||||||
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
|
|
||||||
r.ContentType = "text/xml; charset=\"utf-8\"";
|
|
||||||
r.ContentLength = b.Length;
|
|
||||||
Stream newStream = r.GetRequestStream();
|
|
||||||
newStream.Write(b, 0, b.Length);
|
|
||||||
XmlDocument resp = new XmlDocument();
|
|
||||||
using (WebResponse wres = r.GetResponse())
|
|
||||||
{
|
|
||||||
using (Stream ress = wres.GetResponseStream())
|
|
||||||
{
|
|
||||||
resp.Load(ress);
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -69,6 +69,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var UPnPCheckbox = panel.Get<CheckboxWidget>("UPNP_CHECKBOX");
|
var UPnPCheckbox = panel.Get<CheckboxWidget>("UPNP_CHECKBOX");
|
||||||
UPnPCheckbox.IsChecked = () => allowUPnP;
|
UPnPCheckbox.IsChecked = () => allowUPnP;
|
||||||
UPnPCheckbox.OnClick = () => allowUPnP ^= true;
|
UPnPCheckbox.OnClick = () => allowUPnP ^= true;
|
||||||
|
UPnPCheckbox.IsDisabled = () => !Game.Settings.Server.NatDeviceAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateAndJoin()
|
void CreateAndJoin()
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ Container@CREATESERVER_PANEL:
|
|||||||
Y:180
|
Y:180
|
||||||
Width:300
|
Width:300
|
||||||
Height:20
|
Height:20
|
||||||
Text:Allow UPnP port forwarding
|
Text:Automatic port forwarding
|
||||||
Label@EXTERNAL_PORT_LABEL:
|
Label@EXTERNAL_PORT_LABEL:
|
||||||
X:15
|
X:15
|
||||||
Y:219
|
Y:219
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ Background@CREATESERVER_BG:
|
|||||||
Y:165
|
Y:165
|
||||||
Width:300
|
Width:300
|
||||||
Height:20
|
Height:20
|
||||||
Text:Allow UPnP port forwarding
|
Text:Automatic port forwarding
|
||||||
Button@CREATE_BUTTON:
|
Button@CREATE_BUTTON:
|
||||||
X:130
|
X:130
|
||||||
Y:PARENT_BOTTOM - 45
|
Y:PARENT_BOTTOM - 45
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ cp thirdparty/FuzzyLogicLibrary.dll packaging/built
|
|||||||
# SharpFont for FreeType support
|
# SharpFont for FreeType support
|
||||||
cp thirdparty/SharpFont* packaging/built
|
cp thirdparty/SharpFont* packaging/built
|
||||||
|
|
||||||
|
# Mono.NAT for UPnP support
|
||||||
|
cp thirdparty/Mono.Nat.dll packaging/built
|
||||||
|
|
||||||
# Copy game icon for windows package
|
# Copy game icon for windows package
|
||||||
cp OpenRA.Game/OpenRA.ico packaging/built
|
cp OpenRA.Game/OpenRA.ico packaging/built
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ Section "Client" Client
|
|||||||
File "${SRCDIR}\OpenRA.Renderer.Null.dll"
|
File "${SRCDIR}\OpenRA.Renderer.Null.dll"
|
||||||
File "${SRCDIR}\ICSharpCode.SharpZipLib.dll"
|
File "${SRCDIR}\ICSharpCode.SharpZipLib.dll"
|
||||||
File "${SRCDIR}\FuzzyLogicLibrary.dll"
|
File "${SRCDIR}\FuzzyLogicLibrary.dll"
|
||||||
|
File "${SRCDIR}\Mono.Nat.dll"
|
||||||
File "${SRCDIR}\COPYING"
|
File "${SRCDIR}\COPYING"
|
||||||
File "${SRCDIR}\HACKING"
|
File "${SRCDIR}\HACKING"
|
||||||
File "${SRCDIR}\INSTALL"
|
File "${SRCDIR}\INSTALL"
|
||||||
@@ -263,6 +264,7 @@ Function ${UN}Clean
|
|||||||
Delete $INSTDIR\OpenRA.Renderer.SdlCommon.dll
|
Delete $INSTDIR\OpenRA.Renderer.SdlCommon.dll
|
||||||
Delete $INSTDIR\ICSharpCode.SharpZipLib.dll
|
Delete $INSTDIR\ICSharpCode.SharpZipLib.dll
|
||||||
Delete $INSTDIR\FuzzyLogicLibrary.dll
|
Delete $INSTDIR\FuzzyLogicLibrary.dll
|
||||||
|
Delete $INSTDIR\Mono.Nat.dll
|
||||||
Delete $INSTDIR\Tao.*.dll
|
Delete $INSTDIR\Tao.*.dll
|
||||||
Delete $INSTDIR\SharpFont.*.dll
|
Delete $INSTDIR\SharpFont.*.dll
|
||||||
Delete $INSTDIR\COPYING
|
Delete $INSTDIR\COPYING
|
||||||
|
|||||||
BIN
thirdparty/Mono.Nat.dll
vendored
Normal file
BIN
thirdparty/Mono.Nat.dll
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user