| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 | using System;using System.Collections;using System.Collections.Generic;using System.IO;using System.Net;using System.Net.Sockets;using System.Security.Cryptography.X509Certificates;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;using ProtocolType = MediaBrowser.Model.Net.ProtocolType;using SocketType = MediaBrowser.Model.Net.SocketType;namespace SocketHttpListener.Net{    sealed class EndPointListener    {        HttpListener listener;        IPEndPoint endpoint;        Socket sock;        Dictionary<ListenerPrefix, HttpListener> prefixes;  // Dictionary <ListenerPrefix, HttpListener>        List<ListenerPrefix> unhandled; // List<ListenerPrefix> unhandled; host = '*'        List<ListenerPrefix> all;       // List<ListenerPrefix> all;  host = '+'        X509Certificate cert;        bool secure;        Dictionary<HttpConnection, HttpConnection> unregistered;        private readonly ILogger _logger;        private bool _closed;        private bool _enableDualMode;        private readonly ICryptoProvider _cryptoProvider;        private readonly ISocketFactory _socketFactory;        private readonly ITextEncoding _textEncoding;        private readonly IMemoryStreamFactory _memoryStreamFactory;        private readonly IFileSystem _fileSystem;        private readonly IEnvironmentInfo _environment;        public EndPointListener(HttpListener listener, IPAddress addr, int port, bool secure, X509Certificate cert, ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)        {            this.listener = listener;            _logger = logger;            _cryptoProvider = cryptoProvider;            _socketFactory = socketFactory;            _memoryStreamFactory = memoryStreamFactory;            _textEncoding = textEncoding;            _fileSystem = fileSystem;            _environment = environment;            this.secure = secure;            this.cert = cert;            _enableDualMode = addr.Equals(IPAddress.IPv6Any);            endpoint = new IPEndPoint(addr, port);            prefixes = new Dictionary<ListenerPrefix, HttpListener>();            unregistered = new Dictionary<HttpConnection, HttpConnection>();            CreateSocket();        }        internal HttpListener Listener        {            get            {                return listener;            }        }        private void CreateSocket()        {            try            {                sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);            }            catch (SocketCreateException ex)            {                if (_enableDualMode && endpoint.Address.Equals(IPAddress.IPv6Any) &&                    (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||                    // mono on bsd is throwing this                    string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase)))                {                    endpoint = new IPEndPoint(IPAddress.Any, endpoint.Port);                    _enableDualMode = false;                    sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);                }                else                {                    throw;                }            }            try            {                sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);            }            catch (SocketException)            {                // This is not supported on all operating systems (qnap)            }            sock.Bind(endpoint);            // This is the number TcpListener uses.            sock.Listen(2147483647);            new SocketAcceptor(_logger, sock, ProcessAccept, () => _closed).StartAccept();            _closed = false;        }        private Socket CreateSocket(AddressFamily addressFamily, bool dualMode)        {            try            {                var socket = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);                if (dualMode)                {                    socket.DualMode = true;                }                return socket;            }            catch (SocketException ex)            {                throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);            }            catch (ArgumentException ex)            {                if (dualMode)                {                    // Mono for BSD incorrectly throws ArgumentException instead of SocketException                    throw new SocketCreateException("AddressFamilyNotSupported", ex);                }                else                {                    throw;                }            }        }        private async void ProcessAccept(Socket 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, _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();        }    }}
 |