update SocketHttpListener

This commit is contained in:
Luke Pulverenti 2017-09-02 22:42:13 -04:00
parent da3d8894a8
commit 78165d78a2
22 changed files with 214 additions and 274 deletions

View File

@ -128,6 +128,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
namespace Emby.Server.Implementations
{
@ -1168,7 +1169,7 @@ namespace Emby.Server.Implementations
}
}
private ICertificate GetCertificate(CertificateInfo info)
private X509Certificate GetCertificate(CertificateInfo info)
{
var certificateLocation = info == null ? null : info.Path;
@ -1195,7 +1196,7 @@ namespace Emby.Server.Implementations
return null;
}
return new Certificate(localCert);
return localCert;
}
catch (Exception ex)
{
@ -1584,7 +1585,7 @@ namespace Emby.Server.Implementations
}
private CertificateInfo CertificateInfo { get; set; }
private ICertificate Certificate { get; set; }
private X509Certificate Certificate { get; set; }
private IEnumerable<string> GetUrlPrefixes()
{

View File

@ -440,7 +440,6 @@
<Compile Include="Networking\NetworkManager.cs" />
<Compile Include="Net\DisposableManagedObjectBase.cs" />
<Compile Include="Net\NetAcceptSocket.cs" />
<Compile Include="Net\SocketAcceptor.cs" />
<Compile Include="Net\SocketFactory.cs" />
<Compile Include="Net\UdpSocket.cs" />
<Compile Include="News\NewsEntryPoint.cs" />

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -55,9 +56,8 @@ namespace Emby.Server.Implementations.HttpServer
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
private readonly IXmlSerializer _xmlSerializer;
private readonly ICertificate _certificate;
private readonly X509Certificate _certificate;
private readonly IEnvironmentInfo _environment;
private readonly IStreamFactory _streamFactory;
private readonly Func<Type, Func<string, object>> _funcParseFn;
private readonly bool _enableDualModeSockets;
@ -71,7 +71,7 @@ namespace Emby.Server.Implementations.HttpServer
ILogger logger,
IServerConfigurationManager config,
string serviceName,
string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, X509Certificate certificate, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
{
Instance = this;
@ -86,7 +86,6 @@ namespace Emby.Server.Implementations.HttpServer
_xmlSerializer = xmlSerializer;
_environment = environment;
_certificate = certificate;
_streamFactory = streamFactory;
_funcParseFn = funcParseFn;
_enableDualModeSockets = enableDualModeSockets;
_fileSystem = fileSystem;
@ -204,7 +203,6 @@ namespace Emby.Server.Implementations.HttpServer
_networkManager,
_socketFactory,
_cryptoProvider,
_streamFactory,
_enableDualModeSockets,
GetRequest,
_fileSystem,

View File

@ -4,6 +4,7 @@ using SocketHttpListener.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
@ -22,13 +23,12 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private HttpListener _listener;
private readonly ILogger _logger;
private readonly ICertificate _certificate;
private readonly X509Certificate _certificate;
private readonly IMemoryStreamFactory _memoryStreamProvider;
private readonly ITextEncoding _textEncoding;
private readonly INetworkManager _networkManager;
private readonly ISocketFactory _socketFactory;
private readonly ICryptoProvider _cryptoProvider;
private readonly IStreamFactory _streamFactory;
private readonly IFileSystem _fileSystem;
private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
private readonly bool _enableDualMode;
@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
private CancellationToken _disposeCancellationToken;
public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
public WebSocketSharpListener(ILogger logger, X509Certificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
{
_logger = logger;
_certificate = certificate;
@ -46,7 +46,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_networkManager = networkManager;
_socketFactory = socketFactory;
_cryptoProvider = cryptoProvider;
_streamFactory = streamFactory;
_enableDualMode = enableDualMode;
_httpRequestFactory = httpRequestFactory;
_fileSystem = fileSystem;
@ -65,7 +64,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
public void Start(IEnumerable<string> urlPrefixes)
{
if (_listener == null)
_listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
_listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
_listener.EnableDualMode = _enableDualMode;

View File

@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
return remoteIp ??
(remoteIp = (CheckBadChars(XForwardedFor)) ??
(NormalizeIp(CheckBadChars(XRealIp)) ??
(request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.IpAddress.ToString()) : null)));
(request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.Address.ToString()) : null)));
}
}

View File

@ -43,7 +43,7 @@ namespace Emby.Server.Implementations
IJsonSerializer json,
IXmlSerializer xml,
IEnvironmentInfo environment,
ICertificate certificate,
X509Certificate certificate,
IFileSystem fileSystem,
bool enableDualModeSockets)
{
@ -63,7 +63,6 @@ namespace Emby.Server.Implementations
xml,
environment,
certificate,
new StreamFactory(),
GetParseFn,
enableDualModeSockets,
fileSystem);
@ -74,37 +73,4 @@ namespace Emby.Server.Implementations
return s => JsvReader.GetParseFn(propertyType)(s);
}
}
public class StreamFactory : IStreamFactory
{
public Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket)
{
var netSocket = (NetAcceptSocket)acceptSocket;
return new SocketStream(netSocket.Socket, ownsSocket);
}
public Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate)
{
var sslStream = (SslStream)stream;
var cert = (Certificate)certificate;
return sslStream.AuthenticateAsServerAsync(cert.X509Certificate);
}
public Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen)
{
return new SslStream(innerStream, leaveInnerStreamOpen);
}
}
public class Certificate : ICertificate
{
public Certificate(X509Certificate x509Certificate)
{
X509Certificate = x509Certificate;
}
public X509Certificate X509Certificate { get; private set; }
}
}

View File

@ -89,63 +89,6 @@ namespace Emby.Server.Implementations.Net
Socket.Bind(nativeEndpoint);
}
private SocketAcceptor _acceptor;
public void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed)
{
_acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
_acceptor.StartAccept();
}
public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
{
var options = TransmitFileOptions.UseDefaultWorkerThread;
var completionSource = new TaskCompletionSource<bool>();
var result = Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), new Tuple<Socket, string, TaskCompletionSource<bool>>(Socket, path, completionSource));
return completionSource.Task;
}
public IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state)
{
var options = TransmitFileOptions.UseDefaultWorkerThread;
return Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), state);
}
public void EndSendFile(IAsyncResult result)
{
Socket.EndSendFile(result);
}
private void FileSendCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Tuple<Socket, string, TaskCompletionSource<bool>> data = (Tuple<Socket, string, TaskCompletionSource<bool>>)ar.AsyncState;
var client = data.Item1;
var path = data.Item2;
var taskCompletion = data.Item3;
// Complete sending the data to the remote device.
try
{
client.EndSendFile(ar);
taskCompletion.TrySetResult(true);
}
catch (SocketException ex)
{
_logger.Info("Socket.SendFile failed for {0}. error code {1}", path, ex.SocketErrorCode);
taskCompletion.TrySetException(ex);
}
catch (Exception ex)
{
taskCompletion.TrySetException(ex);
}
}
public void Dispose()
{
Socket.Dispose();

View File

@ -12,9 +12,6 @@ namespace MediaBrowser.Model.Net
void Listen(int backlog);
void Bind(IpEndPointInfo endpoint);
void Connect(IpEndPointInfo endPoint);
void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed);
IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state);
void EndSendFile(IAsyncResult result);
}
public class SocketCreateException : Exception

View File

@ -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)

View File

@ -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();

View File

@ -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
{

View File

@ -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; }
}

View File

@ -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);
}
}
}

View File

@ -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;
@ -289,64 +289,9 @@ namespace SocketHttpListener.Net
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);
}
}
return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
}
private readonly byte[] _emptyBuffer = new byte[] { };
private Task TransmitFileOverSocket(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
{
var ms = GetHeaders(false);
byte[] preBuffer;
if (ms != null)
{
using (var msCopy = new MemoryStream())
{
ms.CopyTo(msCopy);
preBuffer = msCopy.ToArray();
}
}
else
{
return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
}
//_logger.Info("Socket sending file {0} {1}", path, response.ContentLength64);
var taskCompletion = new TaskCompletionSource<bool>();
Action<IAsyncResult> callback = callbackResult =>
{
try
{
_socket.EndSendFile(callbackResult);
taskCompletion.TrySetResult(true);
}
catch (Exception ex)
{
taskCompletion.TrySetException(ex);
}
};
var result = _socket.BeginSendFile(path, preBuffer, _emptyBuffer, new AsyncCallback(callback), null);
if (result.CompletedSynchronously)
{
callback(result);
}
cancellationToken.Register(() => taskCompletion.TrySetCanceled());
return taskCompletion.Task;
}
const int StreamCopyToBufferSize = 81920;
private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
{

View File

@ -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; }

View File

@ -1,19 +1,17 @@
using System;
using System.Net.Sockets;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
namespace Emby.Server.Implementations.Net
namespace SocketHttpListener.Net
{
public class SocketAcceptor
{
private readonly ILogger _logger;
private readonly Socket _originalSocket;
private readonly Func<bool> _isClosed;
private readonly Action<IAcceptSocket> _onAccept;
private readonly bool _isDualMode;
private readonly Action<Socket> _onAccept;
public SocketAcceptor(ILogger logger, Socket originalSocket, Action<IAcceptSocket> onAccept, Func<bool> isClosed, bool isDualMode)
public SocketAcceptor(ILogger logger, Socket originalSocket, Action<Socket> onAccept, Func<bool> isClosed)
{
if (logger == null)
{
@ -35,7 +33,6 @@ namespace Emby.Server.Implementations.Net
_logger = logger;
_originalSocket = originalSocket;
_isClosed = isClosed;
_isDualMode = isDualMode;
_onAccept = onAccept;
}
@ -117,7 +114,7 @@ namespace Emby.Server.Implementations.Net
if (acceptSocket != null)
{
//ProcessAccept(acceptSocket);
_onAccept(new NetAcceptSocket(acceptSocket, _logger, _isDualMode));
_onAccept(acceptSocket);
}
// Accept the next connection request

View File

@ -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
{

View File

@ -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

View File

@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace SocketHttpListener.Primitives
{
public interface ICertificate
{
}
}

View File

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
namespace SocketHttpListener.Primitives
{
public interface IStreamFactory
{
Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket);
Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen);
Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate);
}
}

View File

@ -82,6 +82,7 @@
<Compile Include="Net\HttpStreamAsyncResult.cs" />
<Compile Include="Net\HttpVersion.cs" />
<Compile Include="Net\ListenerPrefix.cs" />
<Compile Include="Net\SocketAcceptor.cs" />
<Compile Include="Net\UriScheme.cs" />
<Compile Include="Net\WebHeaderCollection.cs" />
<Compile Include="Net\WebHeaderEncoding.cs" />
@ -89,11 +90,10 @@
<Compile Include="Net\WebSockets\WebSocketContext.cs" />
<Compile Include="Opcode.cs" />
<Compile Include="PayloadData.cs" />
<Compile Include="Primitives\ICertificate.cs" />
<Compile Include="Primitives\IStreamFactory.cs" />
<Compile Include="Primitives\ITextEncoding.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Rsv.cs" />
<Compile Include="SocketStream.cs" />
<Compile Include="WebSocket.cs" />
<Compile Include="WebSocketException.cs" />
<Compile Include="WebSocketFrame.cs" />

View File

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace SocketHttpListener
{
public class SocketStream : Stream
{
private readonly Socket _socket;
public SocketStream(Socket socket, bool ownsSocket)
{
_socket = socket;
}
public override void Flush()
{
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return true; }
}
public override long Length
{
get { throw new NotImplementedException(); }
}
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public override void Write(byte[] buffer, int offset, int count)
{
_socket.Send(buffer, offset, count, SocketFlags.None);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
return _socket.BeginSend(buffer, offset, count, SocketFlags.None, callback, state);
}
public override void EndWrite(IAsyncResult asyncResult)
{
_socket.EndSend(asyncResult);
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _socket.Receive(buffer, offset, count, SocketFlags.None);
}
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
return _socket.BeginReceive(buffer, offset, count, SocketFlags.None, callback, state);
}
public override int EndRead(IAsyncResult asyncResult)
{
return _socket.EndReceive(asyncResult);
}
}
}