fixed UPnP more crashes
proper timeout: does not crash/lag if no UPnP devices are found close all ports, sockets, responses after they have been used so it does not crash when port forwarding for the 2nd time put all exceptions logs into OpenRA sourcecode
This commit is contained in:
@@ -29,7 +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 AllowUPnP = false;
|
||||||
public bool AllowCheats = false;
|
public bool AllowCheats = false;
|
||||||
public string Map = null;
|
public string Map = null;
|
||||||
public string[] Ban = null;
|
public string[] Ban = null;
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ namespace OpenRA.Server
|
|||||||
XTimer gameTimeout;
|
XTimer gameTimeout;
|
||||||
|
|
||||||
volatile bool shutdown = false;
|
volatile bool shutdown = false;
|
||||||
public void Shutdown() { shutdown = true; }
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
shutdown = true;
|
||||||
|
}
|
||||||
|
|
||||||
public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData)
|
public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData)
|
||||||
{
|
{
|
||||||
@@ -69,8 +72,43 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
randomSeed = (int)DateTime.Now.ToBinary();
|
randomSeed = (int)DateTime.Now.ToBinary();
|
||||||
|
|
||||||
if (settings.AllowUPnP)
|
if (Settings.AllowUPnP)
|
||||||
PortForward();
|
{
|
||||||
|
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) );
|
||||||
@@ -102,7 +140,11 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
Socket.Select( checkRead, null, null, timeout );
|
Socket.Select( checkRead, null, null, timeout );
|
||||||
if (shutdown)
|
if (shutdown)
|
||||||
|
{
|
||||||
|
if (Settings.AllowUPnP)
|
||||||
|
RemovePortforward();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
foreach( Socket s in checkRead )
|
foreach( Socket s in checkRead )
|
||||||
if( s == listener.Server ) AcceptConnection();
|
if( s == listener.Server ) AcceptConnection();
|
||||||
@@ -117,8 +159,12 @@ namespace OpenRA.Server
|
|||||||
t.Tick(this);
|
t.Tick(this);
|
||||||
|
|
||||||
if (shutdown)
|
if (shutdown)
|
||||||
|
{
|
||||||
|
if (Settings.AllowUPnP)
|
||||||
|
RemovePortforward();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameStarted = false;
|
GameStarted = false;
|
||||||
foreach (var t in ServerTraits.WithInterface<INotifyServerShutdown>())
|
foreach (var t in ServerTraits.WithInterface<INotifyServerShutdown>())
|
||||||
@@ -129,20 +175,20 @@ namespace OpenRA.Server
|
|||||||
try { listener.Stop(); }
|
try { listener.Stop(); }
|
||||||
catch { }
|
catch { }
|
||||||
} ) { IsBackground = true }.Start();
|
} ) { IsBackground = true }.Start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortForward()
|
void RemovePortforward()
|
||||||
{
|
{
|
||||||
if (UPnP.NAT.Discover())
|
try
|
||||||
{
|
{
|
||||||
Log.Write("server", "UPnP-enabled router discovered.");
|
if (UPnP.NAT.DeleteForwardingRule(Port, ProtocolType.Tcp))
|
||||||
UPnP.NAT.ForwardPort(Port, ProtocolType.Tcp, "OpenRA"); //might timeout after second try
|
Log.Write("server", "Port {0} (TCP) forwarding rules has been removed.", Port);
|
||||||
Log.Write("server", "Port {0} (TCP) has been forwarded.", Port);
|
}
|
||||||
Log.Write("server", "Your IP is: {0}", UPnP.NAT.GetExternalIP() );
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
OpenRA.Log.Write("server", "Can not remove UPnP portforwarding rules: {0}", e);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
Log.Write("server", "No UPnP-enabled router detected.");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lobby rework todo:
|
/* lobby rework todo:
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ namespace UPnP
|
|||||||
{
|
{
|
||||||
public class NAT
|
public class NAT
|
||||||
{
|
{
|
||||||
public static TimeSpan _timeout = new TimeSpan(0, 0, 0, 3);
|
|
||||||
static string _serviceUrl;
|
static string _serviceUrl;
|
||||||
|
|
||||||
public static bool Discover()
|
public static bool Discover()
|
||||||
{
|
{
|
||||||
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
||||||
|
s.ReceiveTimeout = 3000; //3 seconds
|
||||||
string req = "M-SEARCH * HTTP/1.1\r\n" +
|
string req = "M-SEARCH * HTTP/1.1\r\n" +
|
||||||
"HOST: 239.255.255.250:1900\r\n" +
|
"HOST: 239.255.255.250:1900\r\n" +
|
||||||
"ST:upnp:rootdevice\r\n" +
|
"ST:upnp:rootdevice\r\n" +
|
||||||
@@ -35,14 +35,9 @@ namespace UPnP
|
|||||||
IPEndPoint ipe = new IPEndPoint(IPAddress.Broadcast, 1900);
|
IPEndPoint ipe = new IPEndPoint(IPAddress.Broadcast, 1900);
|
||||||
byte[] buffer = new byte[0x1000];
|
byte[] buffer = new byte[0x1000];
|
||||||
|
|
||||||
DateTime start = DateTime.Now;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
s.SendTo(data, ipe);
|
s.SendTo(data, ipe);
|
||||||
|
|
||||||
int length = 0;
|
int length = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -54,23 +49,32 @@ namespace UPnP
|
|||||||
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
|
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
|
||||||
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
|
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
|
||||||
if (!string.IsNullOrEmpty(_serviceUrl = GetServiceUrl(resp)))
|
if (!string.IsNullOrEmpty(_serviceUrl = GetServiceUrl(resp)))
|
||||||
|
{
|
||||||
|
s.Close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} while (length > 0);
|
} while (length > 0);
|
||||||
} while ((start - DateTime.Now) < _timeout);
|
s.Close();
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
OpenRA.Log.Write("server", "UPNP discover failed: {0}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
s.Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String GetServiceUrl(string resp)
|
private static String GetServiceUrl(string resp)
|
||||||
{
|
{
|
||||||
XmlDocument desc = new XmlDocument();
|
XmlDocument desc = new XmlDocument();
|
||||||
desc.Load(WebRequest.Create(resp).GetResponse().GetResponseStream());
|
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);
|
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
|
||||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
||||||
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
|
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
|
||||||
@@ -83,8 +87,10 @@ namespace UPnP
|
|||||||
Uri combinedUri = new Uri(respUri, node.Value);
|
Uri combinedUri = new Uri(respUri, node.Value);
|
||||||
return combinedUri.AbsoluteUri;
|
return combinedUri.AbsoluteUri;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void ForwardPort(int port, ProtocolType protocol, string description)
|
public static bool ForwardPort(int port, ProtocolType protocol, string description)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_serviceUrl))
|
if (string.IsNullOrEmpty(_serviceUrl))
|
||||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
throw new Exception("No UPnP service available or Discover() has not been called");
|
||||||
@@ -95,17 +101,23 @@ namespace UPnP
|
|||||||
"<NewPortMappingDescription>{3}</NewPortMappingDescription>"+
|
"<NewPortMappingDescription>{3}</NewPortMappingDescription>"+
|
||||||
"<NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping>",
|
"<NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping>",
|
||||||
port, protocol.ToString().ToUpper(),Dns.GetHostAddresses(Dns.GetHostName())[0], description);
|
port, protocol.ToString().ToUpper(),Dns.GetHostAddresses(Dns.GetHostName())[0], description);
|
||||||
SOAPRequest(_serviceUrl, body, "AddPortMapping");
|
if (SOAPRequest(_serviceUrl, body, "AddPortMapping") != null)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeleteForwardingRule(int port, ProtocolType protocol)
|
public static bool DeleteForwardingRule(int port, ProtocolType protocol)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_serviceUrl))
|
if (string.IsNullOrEmpty(_serviceUrl))
|
||||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
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\">" +
|
string body = String.Format("<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
|
||||||
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
||||||
"<NewProtocol>{1}</NewProtocol></u:DeletePortMapping>", port, protocol.ToString().ToUpper() );
|
"<NewProtocol>{1}</NewProtocol></u:DeletePortMapping>", port, protocol.ToString().ToUpper() );
|
||||||
SOAPRequest(_serviceUrl, body, "DeletePortMapping");
|
if (SOAPRequest(_serviceUrl, body, "DeletePortMapping") != null)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IPAddress GetExternalIP()
|
public static IPAddress GetExternalIP()
|
||||||
@@ -122,24 +134,30 @@ namespace UPnP
|
|||||||
|
|
||||||
private static XmlDocument SOAPRequest(string url, string soap, string function)
|
private static XmlDocument SOAPRequest(string url, string soap, string function)
|
||||||
{
|
{
|
||||||
string req = "<?xml version=\"1.0\"?>" +
|
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:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
|
||||||
"<s:Body>" +
|
"<s:Body>" +
|
||||||
soap +
|
soap +
|
||||||
"</s:Body>" +
|
"</s:Body>" +
|
||||||
"</s:Envelope>";
|
"</s:Envelope>";
|
||||||
WebRequest r = HttpWebRequest.Create(url);
|
HttpWebRequest r = (HttpWebRequest)WebRequest.Create(url);
|
||||||
|
r.KeepAlive = false;
|
||||||
r.Method = "POST";
|
r.Method = "POST";
|
||||||
byte[] b = Encoding.UTF8.GetBytes(req);
|
byte[] b = Encoding.UTF8.GetBytes(body);
|
||||||
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
|
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
|
||||||
r.ContentType = "text/xml; charset=\"utf-8\"";
|
r.ContentType = "text/xml; charset=\"utf-8\"";
|
||||||
r.ContentLength = b.Length;
|
r.ContentLength = b.Length;
|
||||||
r.GetRequestStream().Write(b, 0, b.Length);
|
Stream newStream = r.GetRequestStream();
|
||||||
|
newStream.Write(b, 0, b.Length);
|
||||||
XmlDocument resp = new XmlDocument();
|
XmlDocument resp = new XmlDocument();
|
||||||
WebResponse wres = r.GetResponse();
|
using (WebResponse wres = r.GetResponse())
|
||||||
Stream ress = wres.GetResponseStream();
|
{
|
||||||
|
using (Stream ress = wres.GetResponseStream())
|
||||||
|
{
|
||||||
resp.Load(ress);
|
resp.Load(ress);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user