Cleanup uPnP a bit

This commit is contained in:
UnknownShadow200 2017-06-20 09:52:29 +10:00
parent ccd9c33d98
commit 40fde5c892

View File

@ -27,17 +27,18 @@ namespace MCGalaxy.Core {
public sealed class UPnP { public sealed class UPnP {
public static bool CanUseUpnp { get { return Discover(); } } public static bool CanUseUpnp { get { return Discover(); } }
public static TimeSpan Timeout = TimeSpan.FromSeconds(3);
private const 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";
static TimeSpan _timeout = new TimeSpan(0, 0, 0, 3);
public static TimeSpan TimeOut { get { return _timeout; } set { _timeout = value; } }
const 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";
static string _serviceUrl; static string _serviceUrl;
private static bool Discover() { private 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);
@ -75,7 +76,7 @@ namespace MCGalaxy.Core {
} }
} }
} while (length > 0); } while (length > 0);
} while (start.Subtract(DateTime.UtcNow) < _timeout); } while (start.Subtract(DateTime.UtcNow) < Timeout);
return false; return false;
} }
catch { catch {
@ -83,7 +84,7 @@ namespace MCGalaxy.Core {
} }
} }
private static string GetServiceUrl(string resp) { static string GetServiceUrl(string resp) {
#if !DEBUG #if !DEBUG
try { try {
#endif #endif
@ -98,83 +99,75 @@ namespace MCGalaxy.Core {
XmlNode node = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:controlURL/text()", nsMgr); XmlNode node = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:controlURL/text()", nsMgr);
if ( node == null ) if ( node == null )
return null; return null;
XmlNode eventnode = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:eventSubURL/text()", nsMgr);
return CombineUrls(resp, node.Value); return CombineUrls(resp, node.Value);
#if !DEBUG #if !DEBUG
} } catch { return null; }
catch { return null; }
#endif #endif
} }
private static string CombineUrls(string resp, string p) { static string CombineUrls(string resp, string p) {
int n = resp.IndexOf("://"); int n = resp.IndexOf("://");
n = resp.IndexOf('/', n + 3); n = resp.IndexOf('/', n + 3);
return resp.Substring(0, n) + p; return resp.Substring(0, n) + p;
} }
public static void ForwardPort(int port, ProtocolType protocol, string description) { public static void ForwardPort(int port, ProtocolType protocol, string description) {
if ( string.IsNullOrEmpty(_serviceUrl) ) if (String.IsNullOrEmpty(_serviceUrl) )
throw new InvalidOperationException("No UPnP service available or Discover() has not been called"); throw new InvalidOperationException("No UPnP service available or Discover() has not been called");
XmlDocument xdoc = SOAPRequest(_serviceUrl, "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + port.ToString() + "</NewExternalPort><NewProtocol>" + protocol.ToString().ToUpper() + "</NewProtocol>" + XmlDocument xdoc = SOAPRequest(_serviceUrl,
"<NewInternalPort>" + port.ToString() + "</NewInternalPort><NewInternalClient>" + GetLocalIP() + "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>" + description + "<NewRemoteHost></NewRemoteHost>" +
"</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping>", "AddPortMapping"); "<NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
"<NewProtocol>" + protocol.ToString().ToUpper() + "</NewProtocol>" +
"<NewInternalPort>" + port.ToString() + "</NewInternalPort>" +
"<NewInternalClient>" + GetLocalIP() + "</NewInternalClient>" +
"<NewEnabled>1</NewEnabled>" +
"<NewPortMappingDescription>" + description + "</NewPortMappingDescription>" +
"<NewLeaseDuration>0</NewLeaseDuration>" +
"</u:AddPortMapping>", "AddPortMapping");
} }
public static void DeleteForwardingRule(int port, ProtocolType protocol) { public static void DeleteForwardingRule(int port, ProtocolType protocol) {
if ( string.IsNullOrEmpty(_serviceUrl) ) if (String.IsNullOrEmpty(_serviceUrl) )
throw new InvalidOperationException("No UPnP service available or Discover() has not been called"); throw new InvalidOperationException("No UPnP service available or Discover() has not been called");
XmlDocument xdoc = SOAPRequest(_serviceUrl, XmlDocument xdoc = SOAPRequest(_serviceUrl,
"<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" + "<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"<NewRemoteHost>" + "<NewRemoteHost>"</NewRemoteHost>" +
"</NewRemoteHost>" +
"<NewExternalPort>" + port + "</NewExternalPort>" + "<NewExternalPort>" + port + "</NewExternalPort>" +
"<NewProtocol>" + protocol.ToString().ToUpper() + "</NewProtocol>" + "<NewProtocol>" + protocol.ToString().ToUpper() + "</NewProtocol>" +
"</u:DeletePortMapping>", "DeletePortMapping"); "</u:DeletePortMapping>", "DeletePortMapping");
} }
[DebuggerStepThrough]
public static IPAddress GetExternalIP() {
if ( string.IsNullOrEmpty(_serviceUrl) )
throw new InvalidOperationException("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);
}
[DebuggerStepThrough]
public static string GetLocalIP() { public static string GetLocalIP() {
IPHostEntry host;
string localIP = "?"; string localIP = "?";
host = Dns.GetHostEntry(Dns.GetHostName()); IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach ( IPAddress ip in host.AddressList ) {
if ( ip.AddressFamily == AddressFamily.InterNetwork ) { foreach (IPAddress ip in host.AddressList) {
if (ip.AddressFamily == AddressFamily.InterNetwork) {
localIP = ip.ToString(); localIP = ip.ToString();
} }
} }
return localIP; return localIP;
} }
private static XmlDocument SOAPRequest(string url, string soap, string function) { static XmlDocument SOAPRequest(string url, string soap, string function) {
string req = "<?xml version=\"1.0\"?>" + 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:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
"<s:Body>" + "<s:Body>" + soap + "</s:Body>" +
soap +
"</s:Body>" +
"</s:Envelope>"; "</s:Envelope>";
WebRequest r = HttpWebRequest.Create(url); WebRequest r = HttpWebRequest.Create(url);
r.Method = "POST"; r.Method = "POST";
byte[] b = Encoding.UTF8.GetBytes(req);
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\"";
byte[] b = Encoding.UTF8.GetBytes(req);
r.ContentLength = b.Length; r.ContentLength = b.Length;
r.GetRequestStream().Write(b, 0, b.Length); r.GetRequestStream().Write(b, 0, b.Length);
XmlDocument resp = new XmlDocument(); XmlDocument resp = new XmlDocument();
WebResponse wres = r.GetResponse(); WebResponse wres = r.GetResponse();
Stream ress = wres.GetResponseStream(); Stream ress = wres.GetResponseStream();