From 8e57296f6986f13578f37647640fcaf49c9981f1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 27 Oct 2016 19:53:57 -0400 Subject: [PATCH] lighten up nat project --- Mono.Nat/Exceptions/MappingException.cs | 19 -- Mono.Nat/NatUtility.cs | 43 +---- Mono.Nat/Upnp/Mappers/UpnpMapper.cs | 10 +- Mono.Nat/Upnp/Messages/GetServicesMessage.cs | 9 +- Mono.Nat/Upnp/Searchers/UpnpSearcher.cs | 193 +------------------ Mono.Nat/Upnp/Upnp.cs | 10 +- Mono.Nat/Upnp/UpnpNatDevice.cs | 19 +- 7 files changed, 41 insertions(+), 262 deletions(-) diff --git a/Mono.Nat/Exceptions/MappingException.cs b/Mono.Nat/Exceptions/MappingException.cs index bb2e6a69d3..9c0c4f1225 100644 --- a/Mono.Nat/Exceptions/MappingException.cs +++ b/Mono.Nat/Exceptions/MappingException.cs @@ -25,11 +25,9 @@ // using System; -using System.Security.Permissions; namespace Mono.Nat { - [Serializable] public class MappingException : Exception { private int errorCode; @@ -45,7 +43,6 @@ namespace Mono.Nat get { return this.errorText; } } - #region Constructors public MappingException() : base() { @@ -67,21 +64,5 @@ namespace Mono.Nat : base(message, innerException) { } - - protected MappingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) - : base(info, context) - { - } - #endregion - - [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] - public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) - { - if(info==null) throw new ArgumentNullException("info"); - - this.errorCode = info.GetInt32("errorCode"); - this.errorText = info.GetString("errorText"); - base.GetObjectData(info, context); - } } } diff --git a/Mono.Nat/NatUtility.cs b/Mono.Nat/NatUtility.cs index 6d91d25137..b886b87cfd 100644 --- a/Mono.Nat/NatUtility.cs +++ b/Mono.Nat/NatUtility.cs @@ -66,14 +66,12 @@ namespace Mono.Nat { EnabledProtocols = new List { - NatProtocol.Upnp, NatProtocol.Pmp }; searching = new ManualResetEvent(false); controllers = new List(); - controllers.Add(UpnpSearcher.Instance); controllers.Add(PmpSearcher.Instance); controllers.ForEach(searcher => @@ -111,10 +109,6 @@ namespace Mono.Nat { var enabledProtocols = EnabledProtocols.ToList(); - if (enabledProtocols.Contains(UpnpSearcher.Instance.Protocol)) - { - Receive(UpnpSearcher.Instance, UpnpSearcher.sockets); - } if (enabledProtocols.Contains(PmpSearcher.Instance.Protocol)) { Receive(PmpSearcher.Instance, PmpSearcher.sockets); @@ -149,20 +143,6 @@ namespace Mono.Nat } } } - - static void Receive(IMapper mapper, List clients) - { - IPEndPoint received = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 5351); - foreach (UdpClient client in clients) - { - if (client.Available > 0) - { - IPAddress localAddress = ((IPEndPoint)client.Client.LocalEndPoint).Address; - byte[] data = client.Receive(ref received); - mapper.Handle(localAddress, data); - } - } - } public static void StartDiscovery () { @@ -184,7 +164,7 @@ namespace Mono.Nat mapper = new PmpMapper(); break; case MapperType.Upnp: - mapper = new UpnpMapper(); + mapper = new UpnpMapper(Logger); mapper.DeviceFound += (sender, args) => { if (DeviceFound != null) @@ -199,23 +179,6 @@ namespace Mono.Nat searching.Reset(); } - - //So then why is it here? -Nick - [Obsolete ("This method serves no purpose and shouldn't be used")] - public static IPAddress[] GetLocalAddresses (bool includeIPv6) - { - List addresses = new List (); - - IPHostEntry hostInfo = Dns.GetHostEntry (Dns.GetHostName ()); - foreach (IPAddress address in hostInfo.AddressList) { - if (address.AddressFamily == AddressFamily.InterNetwork || - (includeIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)) { - addresses.Add (address); - } - } - - return addresses.ToArray (); - } //checks if an IP address is a private address space as defined by RFC 1918 public static bool IsPrivateAddressSpace (IPAddress address) @@ -239,7 +202,7 @@ namespace Mono.Nat switch (protocol) { case NatProtocol.Upnp: - UpnpSearcher.Instance.Handle(localAddress, response, endpoint); + //UpnpSearcher.Instance.Handle(localAddress, response, endpoint); break; case NatProtocol.Pmp: PmpSearcher.Instance.Handle(localAddress, response, endpoint); @@ -254,7 +217,7 @@ namespace Mono.Nat switch (protocol) { case NatProtocol.Upnp: - UpnpSearcher.Instance.Handle(localAddress, deviceInfo, endpoint); + new UpnpSearcher(Logger).Handle(localAddress, deviceInfo, endpoint); break; default: throw new ArgumentException("Unexpected protocol: " + protocol); diff --git a/Mono.Nat/Upnp/Mappers/UpnpMapper.cs b/Mono.Nat/Upnp/Mappers/UpnpMapper.cs index 6f27168055..9169d3f409 100644 --- a/Mono.Nat/Upnp/Mappers/UpnpMapper.cs +++ b/Mono.Nat/Upnp/Mappers/UpnpMapper.cs @@ -32,6 +32,7 @@ using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; +using MediaBrowser.Model.Logging; namespace Mono.Nat.Upnp.Mappers { @@ -42,7 +43,8 @@ namespace Mono.Nat.Upnp.Mappers public UdpClient Client { get; set; } - public UpnpMapper() + public UpnpMapper(ILogger logger) + : base(logger) { //Bind to local port 1900 for ssdp responses Client = new UdpClient(1900); @@ -88,11 +90,7 @@ namespace Mono.Nat.Upnp.Mappers } catch (Exception ex) { - Trace.WriteLine("Unhandled exception when trying to decode a device's response Send me the following data: "); - Trace.WriteLine("ErrorMessage:"); - Trace.WriteLine(ex.Message); - Trace.WriteLine("Data string:"); - Trace.WriteLine(Encoding.UTF8.GetString(response)); + Logger.ErrorException("Error mapping port. Data string: {0}", ex, Encoding.UTF8.GetString(response)); } } diff --git a/Mono.Nat/Upnp/Messages/GetServicesMessage.cs b/Mono.Nat/Upnp/Messages/GetServicesMessage.cs index c5d7bce70c..8cc0221be5 100644 --- a/Mono.Nat/Upnp/Messages/GetServicesMessage.cs +++ b/Mono.Nat/Upnp/Messages/GetServicesMessage.cs @@ -27,6 +27,7 @@ using System; using System.Diagnostics; using System.Net; +using MediaBrowser.Model.Logging; namespace Mono.Nat.Upnp { @@ -34,18 +35,20 @@ namespace Mono.Nat.Upnp { private string servicesDescriptionUrl; private EndPoint hostAddress; + private readonly ILogger _logger; - public GetServicesMessage(string description, EndPoint hostAddress) + public GetServicesMessage(string description, EndPoint hostAddress, ILogger logger) :base(null) { if (string.IsNullOrEmpty(description)) - Trace.WriteLine("Description is null"); + _logger.Warn("Description is null"); if (hostAddress == null) - Trace.WriteLine("hostaddress is null"); + _logger.Warn("hostaddress is null"); this.servicesDescriptionUrl = description; this.hostAddress = hostAddress; + _logger = logger; } diff --git a/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs b/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs index edc5a5d76a..3d9df012a1 100644 --- a/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs +++ b/Mono.Nat/Upnp/Searchers/UpnpSearcher.cs @@ -37,96 +37,27 @@ using System.Diagnostics; using System.Net.Sockets; using System.Net.NetworkInformation; using MediaBrowser.Controller.Dlna; +using MediaBrowser.Model.Logging; namespace Mono.Nat { internal class UpnpSearcher : ISearcher { - private const int SearchPeriod = 5 * 60; // The time in seconds between each search - static UpnpSearcher instance = new UpnpSearcher(); - public static List sockets = CreateSockets(); - - public static UpnpSearcher Instance - { - get { return instance; } - } - public event EventHandler DeviceFound; public event EventHandler DeviceLost; - private List devices; - private Dictionary lastFetched; private DateTime nextSearch; - private IPEndPoint searchEndpoint; + private readonly ILogger _logger; - UpnpSearcher() + public UpnpSearcher(ILogger logger) { - devices = new List(); - lastFetched = new Dictionary(); - //searchEndpoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900); - searchEndpoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900); + _logger = logger; } - static List CreateSockets() - { - List clients = new List(); - try - { - foreach (NetworkInterface n in NetworkInterface.GetAllNetworkInterfaces()) - { - foreach (UnicastIPAddressInformation address in n.GetIPProperties().UnicastAddresses) - { - if (address.Address.AddressFamily == AddressFamily.InterNetwork) - { - try - { - clients.Add(new UdpClient(new IPEndPoint(address.Address, 0))); - } - catch - { - continue; // Move on to the next address. - } - } - } - } - } - catch (Exception) - { - clients.Add(new UdpClient(0)); - } - return clients; - } - public void Search() { - foreach (UdpClient s in sockets) - { - try - { - Search(s); - } - catch - { - // Ignore any search errors - } - } } - void Search(UdpClient client) - { - nextSearch = DateTime.Now.AddSeconds(SearchPeriod); - byte[] data = DiscoverDeviceMessage.EncodeSSDP(); - - // UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2) - for (int i = 0; i < 3; i++) - client.Send(data, data.Length, searchEndpoint); - } - - public IPEndPoint SearchEndpoint - { - get { return searchEndpoint; } - } - public void Handle(IPAddress localAddress, UpnpDeviceInfo deviceInfo, IPEndPoint endpoint) { // No matter what, this method should never throw an exception. If something goes wrong @@ -145,113 +76,19 @@ namespace Mono.Nat prefix. */ // We have an internet gateway device now - UpnpNatDevice d = new UpnpNatDevice(localAddress, deviceInfo, endpoint, string.Empty); + UpnpNatDevice d = new UpnpNatDevice(localAddress, deviceInfo, endpoint, string.Empty, _logger); - if (devices.Contains(d)) - { - // We already have found this device, so we just refresh it to let people know it's - // Still alive. If a device doesn't respond to a search, we dump it. - devices[devices.IndexOf(d)].LastSeen = DateTime.Now; - } - else - { - - // If we send 3 requests at a time, ensure we only fetch the services list once - // even if three responses are received - if (lastFetched.ContainsKey(endpoint.Address)) - { - DateTime last = lastFetched[endpoint.Address]; - if ((DateTime.Now - last) < TimeSpan.FromSeconds(20)) - return; - } - lastFetched[endpoint.Address] = DateTime.Now; - - // Once we've parsed the information we need, we tell the device to retrieve it's service list - // Once we successfully receive the service list, the callback provided will be invoked. - NatUtility.Log("Fetching service list: {0}", d.HostEndPoint); - d.GetServicesList(DeviceSetupComplete); - } + NatUtility.Log("Fetching service list: {0}", d.HostEndPoint); + OnDeviceFound(new DeviceEventArgs(d)); } catch (Exception ex) { - NatUtility.Log("Unhandled exception when trying to decode a device's response Send me the following data: "); - NatUtility.Log("ErrorMessage:"); - NatUtility.Log(ex.Message); + _logger.ErrorException("Error decoding device response", ex); } } public void Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint) { - // Convert it to a string for easy parsing - string dataString = null; - - // No matter what, this method should never throw an exception. If something goes wrong - // we should still be in a position to handle the next reply correctly. - try { - string urn; - dataString = Encoding.UTF8.GetString(response); - - if (NatUtility.Verbose) - NatUtility.Log("UPnP Response: {0}", dataString); - - /* For UPnP Port Mapping we need ot find either WANPPPConnection or WANIPConnection. - Any other device type is no good to us for this purpose. See the IGP overview paper - page 5 for an overview of device types and their hierarchy. - http://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf */ - - /* TODO: Currently we are assuming version 1 of the protocol. We should figure out which - version it is and apply the correct URN. */ - - /* Some routers don't correctly implement the version ID on the URN, so we only search for the type - prefix. */ - - string log = "UPnP Response: Router advertised a '{0}' service"; - StringComparison c = StringComparison.OrdinalIgnoreCase; - if (dataString.IndexOf("urn:schemas-upnp-org:service:WANIPConnection:", c) != -1) { - urn = "urn:schemas-upnp-org:service:WANIPConnection:1"; - NatUtility.Log(log, "urn:schemas-upnp-org:service:WANIPConnection:1"); - } else if (dataString.IndexOf("urn:schemas-upnp-org:service:WANPPPConnection:", c) != -1) { - urn = "urn:schemas-upnp-org:service:WANPPPConnection:1"; - NatUtility.Log(log, "urn:schemas-upnp-org:service:WANPPPConnection:"); - } else - return; - - // We have an internet gateway device now - UpnpNatDevice d = new UpnpNatDevice(localAddress, dataString, urn); - - if (devices.Contains(d)) - { - // We already have found this device, so we just refresh it to let people know it's - // Still alive. If a device doesn't respond to a search, we dump it. - devices[devices.IndexOf(d)].LastSeen = DateTime.Now; - } - else - { - - // If we send 3 requests at a time, ensure we only fetch the services list once - // even if three responses are received - if (lastFetched.ContainsKey(endpoint.Address)) - { - DateTime last = lastFetched[endpoint.Address]; - if ((DateTime.Now - last) < TimeSpan.FromSeconds(20)) - return; - } - lastFetched[endpoint.Address] = DateTime.Now; - - // Once we've parsed the information we need, we tell the device to retrieve it's service list - // Once we successfully receive the service list, the callback provided will be invoked. - NatUtility.Log("Fetching service list: {0}", d.HostEndPoint); - d.GetServicesList(DeviceSetupComplete); - } - } - catch (Exception ex) - { - Trace.WriteLine("Unhandled exception when trying to decode a device's response Send me the following data: "); - Trace.WriteLine("ErrorMessage:"); - Trace.WriteLine(ex.Message); - Trace.WriteLine("Data string:"); - Trace.WriteLine(dataString); - } } public DateTime NextSearch @@ -259,20 +96,6 @@ namespace Mono.Nat get { return nextSearch; } } - private void DeviceSetupComplete(INatDevice device) - { - lock (this.devices) - { - // We don't want the same device in there twice - if (devices.Contains(device)) - return; - - devices.Add(device); - } - - OnDeviceFound(new DeviceEventArgs(device)); - } - private void OnDeviceFound(DeviceEventArgs args) { if (DeviceFound != null) diff --git a/Mono.Nat/Upnp/Upnp.cs b/Mono.Nat/Upnp/Upnp.cs index e44a51c24d..75e2ade8b3 100644 --- a/Mono.Nat/Upnp/Upnp.cs +++ b/Mono.Nat/Upnp/Upnp.cs @@ -33,11 +33,19 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; +using MediaBrowser.Model.Logging; namespace Mono.Nat.Upnp { internal class Upnp { + protected readonly ILogger Logger; + + public Upnp(ILogger logger) + { + Logger = logger; + } + public UpnpNatDevice Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint) { // Convert it to a string for easy parsing @@ -77,7 +85,7 @@ namespace Mono.Nat.Upnp throw new NotSupportedException("Received non-supported device type"); // We have an internet gateway device now - return new UpnpNatDevice(localAddress, dataString, urn); + return new UpnpNatDevice(localAddress, dataString, urn, Logger); } } } diff --git a/Mono.Nat/Upnp/UpnpNatDevice.cs b/Mono.Nat/Upnp/UpnpNatDevice.cs index 1160d3ac22..b7d779994b 100644 --- a/Mono.Nat/Upnp/UpnpNatDevice.cs +++ b/Mono.Nat/Upnp/UpnpNatDevice.cs @@ -33,6 +33,7 @@ using System.Xml; using System.Text; using System.Diagnostics; using MediaBrowser.Controller.Dlna; +using MediaBrowser.Model.Logging; namespace Mono.Nat.Upnp { @@ -43,8 +44,9 @@ namespace Mono.Nat.Upnp private string serviceDescriptionUrl; private string controlUrl; private string serviceType; + private readonly ILogger _logger; - public override IPAddress LocalAddress + public override IPAddress LocalAddress { get { return localAddress; } } @@ -54,7 +56,7 @@ namespace Mono.Nat.Upnp /// private NatDeviceCallback callback; - internal UpnpNatDevice(IPAddress localAddress, UpnpDeviceInfo deviceInfo, IPEndPoint hostEndPoint, string serviceType) + internal UpnpNatDevice(IPAddress localAddress, UpnpDeviceInfo deviceInfo, IPEndPoint hostEndPoint, string serviceType, ILogger logger) { this.LastSeen = DateTime.Now; this.localAddress = localAddress; @@ -62,6 +64,7 @@ namespace Mono.Nat.Upnp // Split the string at the "location" section so i can extract the ipaddress and service description url string locationDetails = deviceInfo.Location.ToString(); this.serviceType = serviceType; + _logger = logger; // Make sure we have no excess whitespace locationDetails = locationDetails.Trim(); @@ -88,16 +91,17 @@ namespace Mono.Nat.Upnp } } - internal UpnpNatDevice (IPAddress localAddress, string deviceDetails, string serviceType) + internal UpnpNatDevice (IPAddress localAddress, string deviceDetails, string serviceType, ILogger logger) { - this.LastSeen = DateTime.Now; + _logger = logger; + this.LastSeen = DateTime.Now; this.localAddress = localAddress; // Split the string at the "location" section so i can extract the ipaddress and service description url string locationDetails = deviceDetails.Substring(deviceDetails.IndexOf("Location", StringComparison.InvariantCultureIgnoreCase) + 9).Split('\r')[0]; this.serviceType = serviceType; - // Make sure we have no excess whitespace + // Make sure we have no excess whitespace locationDetails = locationDetails.Trim(); // FIXME: Is this reliable enough. What if we get a hostname as opposed to a proper http address @@ -131,8 +135,7 @@ namespace Mono.Nat.Upnp } else { - Trace.WriteLine("Couldn't decode address. Please send following string to the developer: "); - Trace.WriteLine(deviceDetails); + logger.Warn("Couldn't decode address: " + deviceDetails); } } @@ -527,7 +530,7 @@ namespace Mono.Nat.Upnp // Create a HTTPWebRequest to download the list of services the device offers byte[] body; - WebRequest request = new GetServicesMessage(this.serviceDescriptionUrl, this.hostEndPoint).Encode(out body); + WebRequest request = new GetServicesMessage(this.serviceDescriptionUrl, this.hostEndPoint, _logger).Encode(out body); if (body.Length > 0) NatUtility.Log("Error: Services Message contained a body"); request.BeginGetResponse(this.ServicesReceived, request);