using System; using System.Collections; using System.Collections.Generic; using System.Net; using System.Reflection; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using SocketHttpListener.Primitives; namespace SocketHttpListener.Net { sealed class EndPointManager { // Dictionary> static Dictionary> ip_to_endpoints = new Dictionary>(); private EndPointManager() { } public static void AddListener(ILogger logger, HttpListener listener) { List added = new List(); try { lock (ip_to_endpoints) { foreach (string prefix in listener.Prefixes) { AddPrefixInternal(logger, prefix, listener); added.Add(prefix); } } } catch { foreach (string prefix in added) { RemovePrefix(logger, prefix, listener); } throw; } } public static void AddPrefix(ILogger logger, string prefix, HttpListener listener) { lock (ip_to_endpoints) { AddPrefixInternal(logger, prefix, listener); } } static void AddPrefixInternal(ILogger logger, string p, HttpListener listener) { ListenerPrefix lp = new ListenerPrefix(p); if (lp.Path.IndexOf('%') != -1) throw new HttpListenerException(400, "Invalid path."); if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) // TODO: Code? throw new HttpListenerException(400, "Invalid path."); // listens on all the interfaces if host name cannot be parsed by IPAddress. EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result; epl.AddPrefix(lp, listener); } private static IPAddress GetIpAnyAddress(HttpListener listener) { return listener.EnableDualMode ? IPAddress.IPv6Any : IPAddress.Any; } static async Task GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure) { var networkManager = listener.NetworkManager; IPAddress addr; if (host == "*" || host == "+") addr = GetIpAnyAddress(listener); else if (IPAddress.TryParse(host, out addr) == false) { try { var all = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false)); addr = (all.Length == 0 ? null : IPAddress.Parse(all[0].Address)) ?? GetIpAnyAddress(listener); } catch { addr = GetIpAnyAddress(listener); } } Dictionary p = null; // Dictionary if (!ip_to_endpoints.TryGetValue(addr.ToString(), out p)) { p = new Dictionary(); ip_to_endpoints[addr.ToString()] = p; } EndPointListener epl = null; if (p.ContainsKey(port)) { epl = (EndPointListener)p[port]; } else { epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo); p[port] = epl; } return epl; } public static void RemoveEndPoint(EndPointListener epl, IPEndPoint ep) { lock (ip_to_endpoints) { // Dictionary p Dictionary p; if (ip_to_endpoints.TryGetValue(ep.Address.ToString(), out p)) { p.Remove(ep.Port); if (p.Count == 0) { ip_to_endpoints.Remove(ep.Address.ToString()); } } epl.Close(); } } public static void RemoveListener(ILogger logger, HttpListener listener) { lock (ip_to_endpoints) { foreach (string prefix in listener.Prefixes) { RemovePrefixInternal(logger, prefix, listener); } } } public static void RemovePrefix(ILogger logger, string prefix, HttpListener listener) { lock (ip_to_endpoints) { RemovePrefixInternal(logger, prefix, listener); } } static void RemovePrefixInternal(ILogger logger, string prefix, HttpListener listener) { ListenerPrefix lp = new ListenerPrefix(prefix); if (lp.Path.IndexOf('%') != -1) return; if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) return; EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result; epl.RemovePrefix(lp, listener); } } }