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

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

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

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