diff options
| author | Luke <luke.pulverenti@gmail.com> | 2017-09-20 13:22:39 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-09-20 13:22:39 -0400 |
| commit | eb2a1330045d802bfe0366df7105c220a36f111f (patch) | |
| tree | 2c1638c424ee9c0837c5de6d6e08a2398da69cdb /SocketHttpListener/Net | |
| parent | ec426d5c92875639ceac64477ce10fab3e639335 (diff) | |
| parent | a015e1208885bc6a8788db683c4fe47e93dc26b7 (diff) | |
Merge pull request #2897 from MediaBrowser/beta
Beta
Diffstat (limited to 'SocketHttpListener/Net')
| -rw-r--r-- | SocketHttpListener/Net/EndPointListener.cs | 67 | ||||
| -rw-r--r-- | SocketHttpListener/Net/EndPointManager.cs | 22 | ||||
| -rw-r--r-- | SocketHttpListener/Net/HttpConnection.cs | 38 | ||||
| -rw-r--r-- | SocketHttpListener/Net/HttpListener.cs | 20 | ||||
| -rw-r--r-- | SocketHttpListener/Net/HttpListenerRequest.cs | 19 | ||||
| -rw-r--r-- | SocketHttpListener/Net/HttpResponseStream.Managed.cs | 24 | ||||
| -rw-r--r-- | SocketHttpListener/Net/ListenerPrefix.cs | 4 | ||||
| -rw-r--r-- | SocketHttpListener/Net/SocketAcceptor.cs | 124 | ||||
| -rw-r--r-- | SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs | 4 | ||||
| -rw-r--r-- | SocketHttpListener/Net/WebSockets/WebSocketContext.cs | 4 |
10 files changed, 243 insertions, 83 deletions
diff --git a/SocketHttpListener/Net/EndPointListener.cs b/SocketHttpListener/Net/EndPointListener.cs index 2106bbec5..2b1479e42 100644 --- a/SocketHttpListener/Net/EndPointListener.cs +++ b/SocketHttpListener/Net/EndPointListener.cs @@ -3,6 +3,8 @@ 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; @@ -11,37 +13,37 @@ 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; - IpEndPointInfo endpoint; - IAcceptSocket sock; - Dictionary<ListenerPrefix,HttpListener> prefixes; // Dictionary <ListenerPrefix, HttpListener> + 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 = '+' - ICertificate cert; + X509Certificate 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) + 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; - _streamFactory = streamFactory; _socketFactory = socketFactory; _memoryStreamFactory = memoryStreamFactory; _textEncoding = textEncoding; @@ -51,8 +53,8 @@ namespace SocketHttpListener.Net this.secure = secure; this.cert = cert; - _enableDualMode = addr.Equals(IpAddressInfo.IPv6Any); - endpoint = new IpEndPointInfo(addr, port); + _enableDualMode = addr.Equals(IPAddress.IPv6Any); + endpoint = new IPEndPoint(addr, port); prefixes = new Dictionary<ListenerPrefix, HttpListener>(); unregistered = new Dictionary<HttpConnection, HttpConnection>(); @@ -72,18 +74,18 @@ namespace SocketHttpListener.Net { try { - sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode); + sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode); } catch (SocketCreateException ex) { - if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) && - (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) || + 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 IpEndPointInfo(IpAddressInfo.Any, endpoint.Port); + endpoint = new IPEndPoint(IPAddress.Any, endpoint.Port); _enableDualMode = false; - sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode); + sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode); } else { @@ -96,11 +98,42 @@ namespace SocketHttpListener.Net // This is the number TcpListener uses. sock.Listen(2147483647); - sock.StartAccept(ProcessAccept, () => _closed); + new SocketAcceptor(_logger, sock, ProcessAccept, () => _closed).StartAccept(); _closed = false; } - private async void ProcessAccept(IAcceptSocket accepted) + 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 { @@ -112,7 +145,7 @@ namespace SocketHttpListener.Net return; } - HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false); + 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) diff --git a/SocketHttpListener/Net/EndPointManager.cs b/SocketHttpListener/Net/EndPointManager.cs index ddb110ec1..557caa59a 100644 --- a/SocketHttpListener/Net/EndPointManager.cs +++ b/SocketHttpListener/Net/EndPointManager.cs @@ -66,25 +66,25 @@ namespace SocketHttpListener.Net epl.AddPrefix(lp, listener); } - private static IpAddressInfo GetIpAnyAddress(HttpListener listener) + private static IPAddress GetIpAnyAddress(HttpListener listener) { - return listener.EnableDualMode ? IpAddressInfo.IPv6Any : IpAddressInfo.Any; + return listener.EnableDualMode ? IPAddress.IPv6Any : IPAddress.Any; } static async Task<EndPointListener> GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure) { var networkManager = listener.NetworkManager; - IpAddressInfo addr; + IPAddress addr; if (host == "*" || host == "+") addr = GetIpAnyAddress(listener); - else if (networkManager.TryParseIpAddress(host, out addr) == false) + else if (IPAddress.TryParse(host, out addr) == false) { try { var all = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false)); - addr = (all.Length == 0 ? null : all[0]) ?? + addr = (all.Length == 0 ? null : IPAddress.Parse(all[0].Address)) ?? GetIpAnyAddress(listener); } catch @@ -94,10 +94,10 @@ namespace SocketHttpListener.Net } Dictionary<int, EndPointListener> p = null; // Dictionary<int, EndPointListener> - if (!ip_to_endpoints.TryGetValue(addr.Address, out p)) + if (!ip_to_endpoints.TryGetValue(addr.ToString(), out p)) { p = new Dictionary<int, EndPointListener>(); - ip_to_endpoints[addr.Address] = p; + ip_to_endpoints[addr.ToString()] = p; } EndPointListener epl = null; @@ -107,25 +107,25 @@ namespace SocketHttpListener.Net } else { - epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo); + 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, IpEndPointInfo ep) + public static void RemoveEndPoint(EndPointListener epl, IPEndPoint ep) { lock (ip_to_endpoints) { // Dictionary<int, EndPointListener> p Dictionary<int, EndPointListener> p; - if (ip_to_endpoints.TryGetValue(ep.IpAddress.Address, out p)) + if (ip_to_endpoints.TryGetValue(ep.Address.ToString(), out p)) { p.Remove(ep.Port); if (p.Count == 0) { - ip_to_endpoints.Remove(ep.IpAddress.Address); + ip_to_endpoints.Remove(ep.Address.ToString()); } } epl.Close(); diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs index e66443c59..4e8158964 100644 --- a/SocketHttpListener/Net/HttpConnection.cs +++ b/SocketHttpListener/Net/HttpConnection.cs @@ -1,5 +1,9 @@ using System; using System.IO; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; using MediaBrowser.Model.Cryptography; @@ -16,7 +20,7 @@ namespace SocketHttpListener.Net { private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead); const int BufferSize = 8192; - IAcceptSocket _socket; + Socket _socket; Stream _stream; EndPointListener _epl; MemoryStream _memoryStream; @@ -31,21 +35,20 @@ namespace SocketHttpListener.Net bool _contextBound; bool secure; int _timeout = 300000; // 90k ms for first request, 15k ms from then on - IpEndPointInfo local_ep; + IPEndPoint local_ep; HttpListener _lastListener; int[] client_cert_errors; - ICertificate cert; - Stream ssl_stream; + X509Certificate cert; + SslStream ssl_stream; private readonly ILogger _logger; private readonly ICryptoProvider _cryptoProvider; private readonly IMemoryStreamFactory _memoryStreamFactory; private readonly ITextEncoding _textEncoding; - private readonly IStreamFactory _streamFactory; private readonly IFileSystem _fileSystem; private readonly IEnvironmentInfo _environment; - private HttpConnection(ILogger logger, IAcceptSocket socket, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + private HttpConnection(ILogger logger, Socket socket, EndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) { _logger = logger; this._socket = socket; @@ -57,14 +60,13 @@ namespace SocketHttpListener.Net _textEncoding = textEncoding; _fileSystem = fileSystem; _environment = environment; - _streamFactory = streamFactory; } private async Task InitStream() { if (secure == false) { - _stream = _streamFactory.CreateNetworkStream(_socket, false); + _stream = new SocketStream(_socket, false); } else { @@ -81,16 +83,16 @@ namespace SocketHttpListener.Net //}); //_stream = ssl_stream.AuthenticatedStream; - ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(_socket, false), false); - await _streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert).ConfigureAwait(false); + ssl_stream = new SslStream(new SocketStream(_socket, false), false); + await ssl_stream.AuthenticateAsServerAsync(cert).ConfigureAwait(false); _stream = ssl_stream; } Init(); } - public static async Task<HttpConnection> Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + public static async Task<HttpConnection> Create(ILogger logger, Socket sock, EndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) { - var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment); + var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, memoryStreamFactory, textEncoding, fileSystem, environment); await connection.InitStream().ConfigureAwait(false); @@ -134,21 +136,21 @@ namespace SocketHttpListener.Net get { return _reuses; } } - public IpEndPointInfo LocalEndPoint + public IPEndPoint LocalEndPoint { get { if (local_ep != null) return local_ep; - local_ep = (IpEndPointInfo)_socket.LocalEndPoint; + local_ep = (IPEndPoint)_socket.LocalEndPoint; return local_ep; } } - public IpEndPointInfo RemoteEndPoint + public IPEndPoint RemoteEndPoint { - get { return (IpEndPointInfo)_socket.RemoteEndPoint; } + get { return _socket.RemoteEndPoint as IPEndPoint; } } public bool IsSecure @@ -513,12 +515,12 @@ namespace SocketHttpListener.Net return; } - IAcceptSocket s = _socket; + Socket s = _socket; _socket = null; try { if (s != null) - s.Shutdown(true); + s.Shutdown(SocketShutdown.Both); } catch { diff --git a/SocketHttpListener/Net/HttpListener.cs b/SocketHttpListener/Net/HttpListener.cs index b3e01425c..32c5e90e0 100644 --- a/SocketHttpListener/Net/HttpListener.cs +++ b/SocketHttpListener/Net/HttpListener.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Net; +using System.Security.Cryptography.X509Certificates; using MediaBrowser.Common.Net; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.IO; @@ -17,7 +18,6 @@ namespace SocketHttpListener.Net public sealed class HttpListener : IDisposable { internal ICryptoProvider CryptoProvider { get; private set; } - internal IStreamFactory StreamFactory { get; private set; } internal ISocketFactory SocketFactory { get; private set; } internal IFileSystem FileSystem { get; private set; } internal ITextEncoding TextEncoding { get; private set; } @@ -38,15 +38,14 @@ namespace SocketHttpListener.Net Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext> Dictionary<HttpConnection, HttpConnection> connections; private ILogger _logger; - private ICertificate _certificate; + private X509Certificate _certificate; public Action<HttpListenerContext> OnContext { get; set; } - public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) { _logger = logger; CryptoProvider = cryptoProvider; - StreamFactory = streamFactory; SocketFactory = socketFactory; NetworkManager = networkManager; TextEncoding = textEncoding; @@ -59,18 +58,18 @@ namespace SocketHttpListener.Net auth_schemes = AuthenticationSchemes.Anonymous; } - public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) - :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) + public HttpListener(X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + :this(new NullLogger(), certificate, cryptoProvider, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) { } - public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) - : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) + public HttpListener(ILogger logger, X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + : this(logger, cryptoProvider, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) { _certificate = certificate; } - public void LoadCert(ICertificate cert) + public void LoadCert(X509Certificate cert) { _certificate = cert; } @@ -150,7 +149,7 @@ namespace SocketHttpListener.Net // } //} - internal ICertificate Certificate + internal X509Certificate Certificate { get { return _certificate; } } @@ -249,6 +248,7 @@ namespace SocketHttpListener.Net Close(true); //TODO: Should we force here or not? disposed = true; + GC.SuppressFinalize(this); } internal void CheckDisposed() diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs index f9df52593..5e391424f 100644 --- a/SocketHttpListener/Net/HttpListenerRequest.cs +++ b/SocketHttpListener/Net/HttpListenerRequest.cs @@ -3,6 +3,7 @@ using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Net; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; using MediaBrowser.Model.Net; @@ -513,7 +514,14 @@ namespace SocketHttpListener.Net public bool IsLocal { - get { return RemoteEndPoint.IpAddress.Equals(IpAddressInfo.Loopback) || RemoteEndPoint.IpAddress.Equals(IpAddressInfo.IPv6Loopback) || LocalEndPoint.IpAddress.Equals(RemoteEndPoint.IpAddress); } + get + { + var remoteEndPoint = RemoteEndPoint; + + return remoteEndPoint.Address.Equals(IPAddress.Loopback) || + remoteEndPoint.Address.Equals(IPAddress.IPv6Loopback) || + LocalEndPoint.Address.Equals(remoteEndPoint.Address); + } } public bool IsSecureConnection @@ -557,7 +565,7 @@ namespace SocketHttpListener.Net } } - public IpEndPointInfo LocalEndPoint + public IPEndPoint LocalEndPoint { get { return context.Connection.LocalEndPoint; } } @@ -577,7 +585,7 @@ namespace SocketHttpListener.Net get { return raw_url; } } - public IpEndPointInfo RemoteEndPoint + public IPEndPoint RemoteEndPoint { get { return context.Connection.RemoteEndPoint; } } @@ -651,10 +659,5 @@ namespace SocketHttpListener.Net return _websocketRequest; } } - - public Task<ICertificate> GetClientCertificateAsync() - { - return Task.FromResult<ICertificate>(null); - } } } diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs index b700c293d..2de3fbb94 100644 --- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs +++ b/SocketHttpListener/Net/HttpResponseStream.Managed.cs @@ -51,13 +51,13 @@ namespace SocketHttpListener.Net private bool _trailer_sent; private Stream _stream; private readonly IMemoryStreamFactory _memoryStreamFactory; - private readonly IAcceptSocket _socket; + private readonly Socket _socket; private readonly bool _supportsDirectSocketAccess; private readonly IEnvironmentInfo _environment; private readonly IFileSystem _fileSystem; private readonly ILogger _logger; - internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, IAcceptSocket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger) + internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, Socket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger) { _response = response; _ignore_errors = ignore_errors; @@ -285,17 +285,13 @@ namespace SocketHttpListener.Net } } - private bool EnableSendFileWithSocket = false; - public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) { - if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !_response.SendChunked && _response.ContentLength64 > 8192) - { - if (EnableSendFileWithSocket) - { - return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken); - } - } + //if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !_response.SendChunked) + //{ + // return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken); + //} + return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); } @@ -318,7 +314,9 @@ namespace SocketHttpListener.Net return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); } - //_logger.Info("Socket sending file {0} {1}", path, response.ContentLength64); + _stream.Flush(); + + _logger.Info("Socket sending file {0}", path); var taskCompletion = new TaskCompletionSource<bool>(); @@ -335,7 +333,7 @@ namespace SocketHttpListener.Net } }; - var result = _socket.BeginSendFile(path, preBuffer, _emptyBuffer, new AsyncCallback(callback), null); + var result = _socket.BeginSendFile(path, preBuffer, _emptyBuffer, TransmitFileOptions.UseDefaultWorkerThread, new AsyncCallback(callback), null); if (result.CompletedSynchronously) { diff --git a/SocketHttpListener/Net/ListenerPrefix.cs b/SocketHttpListener/Net/ListenerPrefix.cs index 2c314da50..605b7b88c 100644 --- a/SocketHttpListener/Net/ListenerPrefix.cs +++ b/SocketHttpListener/Net/ListenerPrefix.cs @@ -11,7 +11,7 @@ namespace SocketHttpListener.Net ushort port; string path; bool secure; - IpAddressInfo[] addresses; + IPAddress[] addresses; public HttpListener Listener; public ListenerPrefix(string prefix) @@ -25,7 +25,7 @@ namespace SocketHttpListener.Net return original; } - public IpAddressInfo[] Addresses + public IPAddress[] Addresses { get { return addresses; } set { addresses = value; } diff --git a/SocketHttpListener/Net/SocketAcceptor.cs b/SocketHttpListener/Net/SocketAcceptor.cs new file mode 100644 index 000000000..36332f52b --- /dev/null +++ b/SocketHttpListener/Net/SocketAcceptor.cs @@ -0,0 +1,124 @@ +using System; +using System.Net.Sockets; +using MediaBrowser.Model.Logging; + +namespace SocketHttpListener.Net +{ + public class SocketAcceptor + { + private readonly ILogger _logger; + private readonly Socket _originalSocket; + private readonly Func<bool> _isClosed; + private readonly Action<Socket> _onAccept; + + public SocketAcceptor(ILogger logger, Socket originalSocket, Action<Socket> onAccept, Func<bool> isClosed) + { + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + if (originalSocket == null) + { + throw new ArgumentNullException("originalSocket"); + } + if (onAccept == null) + { + throw new ArgumentNullException("onAccept"); + } + if (isClosed == null) + { + throw new ArgumentNullException("isClosed"); + } + + _logger = logger; + _originalSocket = originalSocket; + _isClosed = isClosed; + _onAccept = onAccept; + } + + public void StartAccept() + { + Socket dummy = null; + StartAccept(null, ref dummy); + } + + public void StartAccept(SocketAsyncEventArgs acceptEventArg, ref Socket accepted) + { + if (acceptEventArg == null) + { + acceptEventArg = new SocketAsyncEventArgs(); + acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed); + } + else + { + // acceptSocket must be cleared since the context object is being reused + acceptEventArg.AcceptSocket = null; + } + + try + { + bool willRaiseEvent = _originalSocket.AcceptAsync(acceptEventArg); + + if (!willRaiseEvent) + { + ProcessAccept(acceptEventArg); + } + } + catch (Exception ex) + { + if (accepted != null) + { + try + { +#if NET46 + accepted.Close(); +#else + accepted.Dispose(); +#endif + } + catch + { + } + accepted = null; + } + } + } + + // This method is the callback method associated with Socket.AcceptAsync + // operations and is invoked when an accept operation is complete + // + void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) + { + ProcessAccept(e); + } + + private void ProcessAccept(SocketAsyncEventArgs e) + { + if (_isClosed()) + { + return; + } + + // http://msdn.microsoft.com/en-us/library/system.net.sockets.acceptSocket.acceptasync%28v=vs.110%29.aspx + // Under certain conditions ConnectionReset can occur + // Need to attept to re-accept + if (e.SocketError == SocketError.ConnectionReset) + { + _logger.Error("SocketError.ConnectionReset reported. Attempting to re-accept."); + Socket dummy = null; + StartAccept(e, ref dummy); + return; + } + + var acceptSocket = e.AcceptSocket; + if (acceptSocket != null) + { + //ProcessAccept(acceptSocket); + _onAccept(acceptSocket); + } + + // Accept the next connection request + StartAccept(e, ref acceptSocket); + } + } +} diff --git a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs index 034ac17d2..803c67b83 100644 --- a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -254,7 +254,7 @@ namespace SocketHttpListener.Net.WebSockets /// </summary> /// <value> /// </value> - public override IpEndPointInfo ServerEndPoint + public override IPEndPoint ServerEndPoint { get { @@ -281,7 +281,7 @@ namespace SocketHttpListener.Net.WebSockets /// </summary> /// <value> /// </value> - public override IpEndPointInfo UserEndPoint + public override IPEndPoint UserEndPoint { get { diff --git a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs index 3ffa6e639..9665ab789 100644 --- a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs +++ b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs @@ -151,7 +151,7 @@ namespace SocketHttpListener.Net.WebSockets /// <value> /// A <see cref="System.Net.IPEndPoint"/> that represents the server endpoint. /// </value> - public abstract IpEndPointInfo ServerEndPoint { get; } + public abstract IPEndPoint ServerEndPoint { get; } /// <summary> /// Gets the client information (identity, authentication, and security roles). @@ -167,7 +167,7 @@ namespace SocketHttpListener.Net.WebSockets /// <value> /// A <see cref="System.Net.IPEndPoint"/> that represents the client endpoint. /// </value> - public abstract IpEndPointInfo UserEndPoint { get; } + public abstract IPEndPoint UserEndPoint { get; } /// <summary> /// Gets the <see cref="SocketHttpListener.WebSocket"/> instance used for two-way communication |
