123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- //
- // Authors:
- // Ben Motmans <ben.motmans@gmail.com>
- // Nicholas Terry <nick.i.terry@gmail.com>
- //
- // Copyright (C) 2007 Ben Motmans
- // Copyright (C) 2014 Nicholas Terry
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Net;
- using System.Net.Sockets;
- using System.Threading;
- using System.Linq;
- using System.Collections.Generic;
- using System.IO;
- using System.Net.NetworkInformation;
- using MediaBrowser.Controller.Dlna;
- using MediaBrowser.Model.Logging;
- using Mono.Nat.Pmp.Mappers;
- using Mono.Nat.Upnp.Mappers;
- namespace Mono.Nat
- {
- public static class NatUtility
- {
- private static ManualResetEvent searching;
- public static event EventHandler<DeviceEventArgs> DeviceFound;
- public static event EventHandler<DeviceEventArgs> DeviceLost;
-
- public static event EventHandler<UnhandledExceptionEventArgs> UnhandledException;
- private static List<ISearcher> controllers;
- private static bool verbose;
- public static List<NatProtocol> EnabledProtocols { get; set; }
- public static ILogger Logger { get; set; }
- public static bool Verbose
- {
- get { return verbose; }
- set { verbose = value; }
- }
-
- static NatUtility()
- {
- EnabledProtocols = new List<NatProtocol>
- {
- NatProtocol.Upnp,
- NatProtocol.Pmp
- };
- searching = new ManualResetEvent(false);
- controllers = new List<ISearcher>();
- controllers.Add(UpnpSearcher.Instance);
- controllers.Add(PmpSearcher.Instance);
- controllers.ForEach(searcher =>
- {
- searcher.DeviceFound += (sender, args) =>
- {
- if (DeviceFound != null)
- DeviceFound(sender, args);
- };
- searcher.DeviceLost += (sender, args) =>
- {
- if (DeviceLost != null)
- DeviceLost(sender, args);
- };
- });
- Thread t = new Thread(SearchAndListen);
- t.IsBackground = true;
- t.Start();
- }
- internal static void Log(string format, params object[] args)
- {
- var logger = Logger;
- if (logger != null)
- logger.Debug(format, args);
- }
- private static void SearchAndListen()
- {
- while (true)
- {
- searching.WaitOne();
- try
- {
- 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);
- }
- foreach (ISearcher s in controllers)
- if (s.NextSearch < DateTime.Now && enabledProtocols.Contains(s.Protocol))
- {
- Log("Searching for: {0}", s.GetType().Name);
- s.Search();
- }
- }
- catch (Exception e)
- {
- if (UnhandledException != null)
- UnhandledException(typeof(NatUtility), new UnhandledExceptionEventArgs(e, false));
- }
- Thread.Sleep(10);
- }
- }
- static void Receive (ISearcher searcher, List<UdpClient> 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);
- searcher.Handle(localAddress, data, received);
- }
- }
- }
- static void Receive(IMapper mapper, List<UdpClient> 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 ()
- {
- searching.Set();
- }
- public static void StopDiscovery ()
- {
- searching.Reset();
- }
- //This is for when you know the Gateway IP and want to skip the costly search...
- public static void DirectMap(IPAddress gatewayAddress, MapperType type)
- {
- IMapper mapper;
- switch (type)
- {
- case MapperType.Pmp:
- mapper = new PmpMapper();
- break;
- case MapperType.Upnp:
- mapper = new UpnpMapper();
- mapper.DeviceFound += (sender, args) =>
- {
- if (DeviceFound != null)
- DeviceFound(sender, args);
- };
- mapper.Map(gatewayAddress);
- break;
- default:
- throw new InvalidOperationException("Unsuported type given");
- }
- 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<IPAddress> addresses = new List<IPAddress> ();
- 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)
- {
- byte[] ba = address.GetAddressBytes ();
- switch ((int)ba[0]) {
- case 10:
- return true; //10.x.x.x
- case 172:
- return ((int)ba[1] & 16) != 0; //172.16-31.x.x
- case 192:
- return (int)ba[1] == 168; //192.168.x.x
- default:
- return false;
- }
- }
- public static void Handle(IPAddress localAddress, byte[] response, IPEndPoint endpoint, NatProtocol protocol)
- {
- switch (protocol)
- {
- case NatProtocol.Upnp:
- UpnpSearcher.Instance.Handle(localAddress, response, endpoint);
- break;
- case NatProtocol.Pmp:
- PmpSearcher.Instance.Handle(localAddress, response, endpoint);
- break;
- default:
- throw new ArgumentException("Unexpected protocol: " + protocol);
- }
- }
- public static void Handle(IPAddress localAddress, UpnpDeviceInfo deviceInfo, IPEndPoint endpoint, NatProtocol protocol)
- {
- switch (protocol)
- {
- case NatProtocol.Upnp:
- UpnpSearcher.Instance.Handle(localAddress, deviceInfo, endpoint);
- break;
- default:
- throw new ArgumentException("Unexpected protocol: " + protocol);
- }
- }
- }
- }
|