| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 | 
							- using System;
 
- using System.Collections;
 
- using System.Collections.Generic;
 
- using System.IO;
 
- using System.Net;
 
- using System.Threading;
 
- using MediaBrowser.Model.Cryptography;
 
- using MediaBrowser.Model.IO;
 
- using MediaBrowser.Model.Logging;
 
- using MediaBrowser.Model.Net;
 
- using MediaBrowser.Model.System;
 
- using MediaBrowser.Model.Text;
 
- using SocketHttpListener.Primitives;
 
- namespace SocketHttpListener.Net
 
- {
 
-     sealed class EndPointListener
 
-     {
 
-         HttpListener listener;
 
-         IpEndPointInfo endpoint;
 
-         IAcceptSocket sock;
 
-         Dictionary<ListenerPrefix,HttpListener> prefixes;  // Dictionary <ListenerPrefix, HttpListener>
 
-         List<ListenerPrefix> unhandled; // List<ListenerPrefix> unhandled; host = '*'
 
-         List<ListenerPrefix> all;       // List<ListenerPrefix> all;  host = '+'
 
-         ICertificate cert;
 
-         bool secure;
 
-         Dictionary<HttpConnection, HttpConnection> unregistered;
 
-         private readonly ILogger _logger;
 
-         private bool _closed;
 
-         private bool _enableDualMode;
 
-         private readonly ICryptoProvider _cryptoProvider;
 
-         private readonly IStreamFactory _streamFactory;
 
-         private readonly ISocketFactory _socketFactory;
 
-         private readonly ITextEncoding _textEncoding;
 
-         private readonly IMemoryStreamFactory _memoryStreamFactory;
 
-         private readonly IFileSystem _fileSystem;
 
-         private readonly IEnvironmentInfo _environment;
 
-         public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
 
-         {
 
-             this.listener = listener;
 
-             _logger = logger;
 
-             _cryptoProvider = cryptoProvider;
 
-             _streamFactory = streamFactory;
 
-             _socketFactory = socketFactory;
 
-             _memoryStreamFactory = memoryStreamFactory;
 
-             _textEncoding = textEncoding;
 
-             _fileSystem = fileSystem;
 
-             _environment = environment;
 
-             this.secure = secure;
 
-             this.cert = cert;
 
-             _enableDualMode = addr.Equals(IpAddressInfo.IPv6Any);
 
-             endpoint = new IpEndPointInfo(addr, port);
 
-             prefixes = new Dictionary<ListenerPrefix, HttpListener>();
 
-             unregistered = new Dictionary<HttpConnection, HttpConnection>();
 
-             CreateSocket();
 
-         }
 
-         internal HttpListener Listener
 
-         {
 
-             get
 
-             {
 
-                 return listener;
 
-             }
 
-         }
 
-         private void CreateSocket()
 
-         {
 
-             try
 
-             {
 
-                 sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
 
-             }
 
-             catch (SocketCreateException ex)
 
-             {
 
-                 if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) && 
 
-                     (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) || 
 
-                     // mono on bsd is throwing this
 
-                     string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase)))
 
-                 {
 
-                     endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
 
-                     _enableDualMode = false;
 
-                     sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
 
-                 }
 
-                 else
 
-                 {
 
-                     throw;
 
-                 }
 
-             }
 
-             sock.Bind(endpoint);
 
-             // This is the number TcpListener uses.
 
-             sock.Listen(2147483647);
 
-             sock.StartAccept(ProcessAccept, () => _closed);
 
-             _closed = false;
 
-         }
 
-         private async void ProcessAccept(IAcceptSocket accepted)
 
-         {
 
-             try
 
-             {
 
-                 var listener = this;
 
-                 if (listener.secure && listener.cert == null)
 
-                 {
 
-                     accepted.Close();
 
-                     return;
 
-                 }
 
-                 HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
 
-                 //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
 
-                 lock (listener.unregistered)
 
-                 {
 
-                     listener.unregistered[conn] = conn;
 
-                 }
 
-                 conn.BeginReadRequest();
 
-             }
 
-             catch (Exception ex)
 
-             {
 
-                 _logger.ErrorException("Error in ProcessAccept", ex);
 
-             }
 
-         }
 
-         internal void RemoveConnection(HttpConnection conn)
 
-         {
 
-             lock (unregistered)
 
-             {
 
-                 unregistered.Remove(conn);
 
-             }
 
-         }
 
-         public bool BindContext(HttpListenerContext context)
 
-         {
 
-             HttpListenerRequest req = context.Request;
 
-             ListenerPrefix prefix;
 
-             HttpListener listener = SearchListener(req.Url, out prefix);
 
-             if (listener == null)
 
-                 return false;
 
-             context.Connection.Prefix = prefix;
 
-             return true;
 
-         }
 
-         public void UnbindContext(HttpListenerContext context)
 
-         {
 
-             if (context == null || context.Request == null)
 
-                 return;
 
-             listener.UnregisterContext(context);
 
-         }
 
-         HttpListener SearchListener(Uri uri, out ListenerPrefix prefix)
 
-         {
 
-             prefix = null;
 
-             if (uri == null)
 
-                 return null;
 
-             string host = uri.Host;
 
-             int port = uri.Port;
 
-             string path = WebUtility.UrlDecode(uri.AbsolutePath);
 
-             string path_slash = path[path.Length - 1] == '/' ? path : path + "/";
 
-             HttpListener best_match = null;
 
-             int best_length = -1;
 
-             if (host != null && host != "")
 
-             {
 
-                 var p_ro = prefixes;
 
-                 foreach (ListenerPrefix p in p_ro.Keys)
 
-                 {
 
-                     string ppath = p.Path;
 
-                     if (ppath.Length < best_length)
 
-                         continue;
 
-                     if (p.Host != host || p.Port != port)
 
-                         continue;
 
-                     if (path.StartsWith(ppath) || path_slash.StartsWith(ppath))
 
-                     {
 
-                         best_length = ppath.Length;
 
-                         best_match = (HttpListener)p_ro[p];
 
-                         prefix = p;
 
-                     }
 
-                 }
 
-                 if (best_length != -1)
 
-                     return best_match;
 
-             }
 
-             List<ListenerPrefix> list = unhandled;
 
-             best_match = MatchFromList(host, path, list, out prefix);
 
-             if (path != path_slash && best_match == null)
 
-                 best_match = MatchFromList(host, path_slash, list, out prefix);
 
-             if (best_match != null)
 
-                 return best_match;
 
-             list = all;
 
-             best_match = MatchFromList(host, path, list, out prefix);
 
-             if (path != path_slash && best_match == null)
 
-                 best_match = MatchFromList(host, path_slash, list, out prefix);
 
-             if (best_match != null)
 
-                 return best_match;
 
-             return null;
 
-         }
 
-         HttpListener MatchFromList(string host, string path, List<ListenerPrefix> list, out ListenerPrefix prefix)
 
-         {
 
-             prefix = null;
 
-             if (list == null)
 
-                 return null;
 
-             HttpListener best_match = null;
 
-             int best_length = -1;
 
-             foreach (ListenerPrefix p in list)
 
-             {
 
-                 string ppath = p.Path;
 
-                 if (ppath.Length < best_length)
 
-                     continue;
 
-                 if (path.StartsWith(ppath))
 
-                 {
 
-                     best_length = ppath.Length;
 
-                     best_match = p.Listener;
 
-                     prefix = p;
 
-                 }
 
-             }
 
-             return best_match;
 
-         }
 
-         void AddSpecial(List<ListenerPrefix> coll, ListenerPrefix prefix)
 
-         {
 
-             if (coll == null)
 
-                 return;
 
-             foreach (ListenerPrefix p in coll)
 
-             {
 
-                 if (p.Path == prefix.Path) //TODO: code
 
-                     throw new HttpListenerException(400, "Prefix already in use.");
 
-             }
 
-             coll.Add(prefix);
 
-         }
 
-         bool RemoveSpecial(List<ListenerPrefix> coll, ListenerPrefix prefix)
 
-         {
 
-             if (coll == null)
 
-                 return false;
 
-             int c = coll.Count;
 
-             for (int i = 0; i < c; i++)
 
-             {
 
-                 ListenerPrefix p = (ListenerPrefix)coll[i];
 
-                 if (p.Path == prefix.Path)
 
-                 {
 
-                     coll.RemoveAt(i);
 
-                     return true;
 
-                 }
 
-             }
 
-             return false;
 
-         }
 
-         void CheckIfRemove()
 
-         {
 
-             if (prefixes.Count > 0)
 
-                 return;
 
-             List<ListenerPrefix> list = unhandled;
 
-             if (list != null && list.Count > 0)
 
-                 return;
 
-             list = all;
 
-             if (list != null && list.Count > 0)
 
-                 return;
 
-             EndPointManager.RemoveEndPoint(this, endpoint);
 
-         }
 
-         public void Close()
 
-         {
 
-             _closed = true;
 
-             sock.Close();
 
-             lock (unregistered)
 
-             {
 
-                 //
 
-                 // Clone the list because RemoveConnection can be called from Close
 
-                 //
 
-                 var connections = new List<HttpConnection>(unregistered.Keys);
 
-                 foreach (HttpConnection c in connections)
 
-                     c.Close(true);
 
-                 unregistered.Clear();
 
-             }
 
-         }
 
-         public void AddPrefix(ListenerPrefix prefix, HttpListener listener)
 
-         {
 
-             List<ListenerPrefix> current;
 
-             List<ListenerPrefix> future;
 
-             if (prefix.Host == "*")
 
-             {
 
-                 do
 
-                 {
 
-                     current = unhandled;
 
-                     future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
 
-                     prefix.Listener = listener;
 
-                     AddSpecial(future, prefix);
 
-                 } while (Interlocked.CompareExchange(ref unhandled, future, current) != current);
 
-                 return;
 
-             }
 
-             if (prefix.Host == "+")
 
-             {
 
-                 do
 
-                 {
 
-                     current = all;
 
-                     future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
 
-                     prefix.Listener = listener;
 
-                     AddSpecial(future, prefix);
 
-                 } while (Interlocked.CompareExchange(ref all, future, current) != current);
 
-                 return;
 
-             }
 
-             Dictionary<ListenerPrefix, HttpListener> prefs;
 
-             Dictionary<ListenerPrefix, HttpListener> p2;
 
-             do
 
-             {
 
-                 prefs = prefixes;
 
-                 if (prefs.ContainsKey(prefix))
 
-                 {
 
-                     HttpListener other = (HttpListener)prefs[prefix];
 
-                     if (other != listener) // TODO: code.
 
-                         throw new HttpListenerException(400, "There's another listener for " + prefix);
 
-                     return;
 
-                 }
 
-                 p2 = new Dictionary<ListenerPrefix, HttpListener>(prefs);
 
-                 p2[prefix] = listener;
 
-             } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs);
 
-         }
 
-         public void RemovePrefix(ListenerPrefix prefix, HttpListener listener)
 
-         {
 
-             List<ListenerPrefix> current;
 
-             List<ListenerPrefix> future;
 
-             if (prefix.Host == "*")
 
-             {
 
-                 do
 
-                 {
 
-                     current = unhandled;
 
-                     future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
 
-                     if (!RemoveSpecial(future, prefix))
 
-                         break; // Prefix not found
 
-                 } while (Interlocked.CompareExchange(ref unhandled, future, current) != current);
 
-                 CheckIfRemove();
 
-                 return;
 
-             }
 
-             if (prefix.Host == "+")
 
-             {
 
-                 do
 
-                 {
 
-                     current = all;
 
-                     future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
 
-                     if (!RemoveSpecial(future, prefix))
 
-                         break; // Prefix not found
 
-                 } while (Interlocked.CompareExchange(ref all, future, current) != current);
 
-                 CheckIfRemove();
 
-                 return;
 
-             }
 
-             Dictionary<ListenerPrefix, HttpListener> prefs;
 
-             Dictionary<ListenerPrefix, HttpListener> p2;
 
-             do
 
-             {
 
-                 prefs = prefixes;
 
-                 if (!prefs.ContainsKey(prefix))
 
-                     break;
 
-                 p2 = new Dictionary<ListenerPrefix, HttpListener>(prefs);
 
-                 p2.Remove(prefix);
 
-             } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs);
 
-             CheckIfRemove();
 
-         }
 
-     }
 
- }
 
 
  |