UPnP source code fixes
as suggested by Chris Forbes
This commit is contained in:
committed by
Chris Forbes
parent
a831e72fa2
commit
aa36a56b27
@@ -29,6 +29,7 @@ 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 = true;
|
||||||
public bool AllowCheats = false;
|
public bool AllowCheats = false;
|
||||||
public string Map = null;
|
public string Map = null;
|
||||||
public string[] Ban = null;
|
public string[] Ban = null;
|
||||||
@@ -42,6 +43,7 @@ namespace OpenRA.GameRules
|
|||||||
ExternalPort = other.ExternalPort;
|
ExternalPort = other.ExternalPort;
|
||||||
AdvertiseOnline = other.AdvertiseOnline;
|
AdvertiseOnline = other.AdvertiseOnline;
|
||||||
MasterServer = other.MasterServer;
|
MasterServer = other.MasterServer;
|
||||||
|
AllowUPnP = other.AllowUPnP;
|
||||||
AllowCheats = other.AllowCheats;
|
AllowCheats = other.AllowCheats;
|
||||||
Map = other.Map;
|
Map = other.Map;
|
||||||
Ban = other.Ban;
|
Ban = other.Ban;
|
||||||
|
|||||||
@@ -142,6 +142,7 @@
|
|||||||
<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" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#region Copyright & License Information
|
#region Copyright & License Information
|
||||||
/*
|
/*
|
||||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||||
* This file is part of OpenRA, which is free software. It is made
|
* 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
|
* available to you under the terms of the GNU General Public License
|
||||||
* as published by the Free Software Foundation. For more information,
|
* as published by the Free Software Foundation. For more information,
|
||||||
@@ -13,9 +13,13 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using UPnP;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Xml;
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.GameRules;
|
using OpenRA.GameRules;
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
@@ -64,6 +68,9 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
randomSeed = (int)DateTime.Now.ToBinary();
|
randomSeed = (int)DateTime.Now.ToBinary();
|
||||||
|
|
||||||
|
if (settings.AllowUPnP)
|
||||||
|
PortForward();
|
||||||
|
|
||||||
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) );
|
||||||
|
|
||||||
@@ -123,6 +130,20 @@ namespace OpenRA.Server
|
|||||||
} ) { IsBackground = true }.Start();
|
} ) { IsBackground = true }.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PortForward()
|
||||||
|
{
|
||||||
|
if (UPnP.NAT.Discover())
|
||||||
|
{
|
||||||
|
Log.Write("server", "UPnP-enabled router discovered.");
|
||||||
|
UPnP.NAT.ForwardPort(Port, ProtocolType.Tcp, "OpenRA"); //might timeout after second try
|
||||||
|
Log.Write("server", "Port {0} (TCP) has been forwarded.", Port);
|
||||||
|
Log.Write("server", "Your IP is: {0}", UPnP.NAT.GetExternalIP() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log.Write("server", "No UPnP-enabled router detected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* lobby rework todo:
|
/* lobby rework todo:
|
||||||
* - "teams together" option for team games -- will eliminate most need
|
* - "teams together" option for team games -- will eliminate most need
|
||||||
* for manual spawnpoint choosing.
|
* for manual spawnpoint choosing.
|
||||||
|
|||||||
139
OpenRA.Game/Server/UPnP.cs
Normal file
139
OpenRA.Game/Server/UPnP.cs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
#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
|
||||||
|
{
|
||||||
|
public static TimeSpan _timeout = new TimeSpan(0, 0, 0, 3);
|
||||||
|
static string _serviceUrl;
|
||||||
|
|
||||||
|
public static bool Discover()
|
||||||
|
{
|
||||||
|
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
||||||
|
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];
|
||||||
|
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
s.SendTo(data, ipe);
|
||||||
|
s.SendTo(data, ipe);
|
||||||
|
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)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (length > 0);
|
||||||
|
} while ((start - DateTime.Now) < _timeout);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String GetServiceUrl(string resp)
|
||||||
|
{
|
||||||
|
XmlDocument desc = new XmlDocument();
|
||||||
|
desc.Load(WebRequest.Create(resp).GetResponse().GetResponseStream());
|
||||||
|
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 void 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);
|
||||||
|
SOAPRequest(_serviceUrl, body, "AddPortMapping");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void 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() );
|
||||||
|
SOAPRequest(_serviceUrl, body, "DeletePortMapping");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 req = "<?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>";
|
||||||
|
WebRequest r = HttpWebRequest.Create(url);
|
||||||
|
r.Method = "POST";
|
||||||
|
byte[] b = Encoding.UTF8.GetBytes(req);
|
||||||
|
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
|
||||||
|
r.ContentType = "text/xml; charset=\"utf-8\"";
|
||||||
|
r.ContentLength = b.Length;
|
||||||
|
r.GetRequestStream().Write(b, 0, b.Length);
|
||||||
|
XmlDocument resp = new XmlDocument();
|
||||||
|
WebResponse wres = r.GetResponse();
|
||||||
|
Stream ress = wres.GetResponseStream();
|
||||||
|
resp.Load(ress);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#region Copyright & License Information
|
#region Copyright & License Information
|
||||||
/*
|
/*
|
||||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||||
* This file is part of OpenRA, which is free software. It is made
|
* 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
|
* available to you under the terms of the GNU General Public License
|
||||||
* as published by the Free Software Foundation. For more information,
|
* as published by the Free Software Foundation. For more information,
|
||||||
@@ -22,6 +22,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
Action onExit;
|
Action onExit;
|
||||||
Map map;
|
Map map;
|
||||||
bool advertiseOnline;
|
bool advertiseOnline;
|
||||||
|
bool allowUPnP;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ServerCreationLogic(Widget widget, Action onExit, Action openLobby)
|
public ServerCreationLogic(Widget widget, Action onExit, Action openLobby)
|
||||||
@@ -64,6 +65,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
var advertiseCheckbox = panel.Get<CheckboxWidget>("ADVERTISE_CHECKBOX");
|
var advertiseCheckbox = panel.Get<CheckboxWidget>("ADVERTISE_CHECKBOX");
|
||||||
advertiseCheckbox.IsChecked = () => advertiseOnline;
|
advertiseCheckbox.IsChecked = () => advertiseOnline;
|
||||||
advertiseCheckbox.OnClick = () => advertiseOnline ^= true;
|
advertiseCheckbox.OnClick = () => advertiseOnline ^= true;
|
||||||
|
|
||||||
|
var UPnPCheckbox = panel.Get<CheckboxWidget>("UPNP_CHECKBOX");
|
||||||
|
UPnPCheckbox.IsChecked = () => allowUPnP;
|
||||||
|
UPnPCheckbox.OnClick = () => allowUPnP ^= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateAndJoin()
|
void CreateAndJoin()
|
||||||
@@ -81,6 +86,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
Game.Settings.Server.ListenPort = listenPort;
|
Game.Settings.Server.ListenPort = listenPort;
|
||||||
Game.Settings.Server.ExternalPort = externalPort;
|
Game.Settings.Server.ExternalPort = externalPort;
|
||||||
Game.Settings.Server.AdvertiseOnline = advertiseOnline;
|
Game.Settings.Server.AdvertiseOnline = advertiseOnline;
|
||||||
|
Game.Settings.Server.AllowUPnP = allowUPnP;
|
||||||
Game.Settings.Server.Map = map.Uid;
|
Game.Settings.Server.Map = map.Uid;
|
||||||
Game.Settings.Save();
|
Game.Settings.Save();
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ Background@CREATESERVER_BG:
|
|||||||
Width:300
|
Width:300
|
||||||
Height:20
|
Height:20
|
||||||
Text:Advertise game Online
|
Text:Advertise game Online
|
||||||
|
Checkbox@UPNP_CHECKBOX:
|
||||||
|
X:165
|
||||||
|
Y:165
|
||||||
|
Width:300
|
||||||
|
Height:20
|
||||||
|
Text:Allow UPnP port forwarding
|
||||||
Button@CREATE_BUTTON:
|
Button@CREATE_BUTTON:
|
||||||
X:130
|
X:130
|
||||||
Y:PARENT_BOTTOM - 45
|
Y:PARENT_BOTTOM - 45
|
||||||
|
|||||||
Reference in New Issue
Block a user