|
|
#if !NET20
using System; using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks;
namespace Apewer.WebSocket { internal class SocketWrapper {
public const UInt32 KeepAliveInterval = 60000; public const UInt32 RetryInterval = 10000;
private readonly Socket _socket; private Stream _stream; private CancellationTokenSource _tokenSource; private TaskFactory _taskFactory;
public string RemoteIpAddress { get { var endpoint = _socket.RemoteEndPoint as IPEndPoint; return endpoint != null ? endpoint.Address.ToString() : null; } }
public int RemotePort { get { var endpoint = _socket.RemoteEndPoint as IPEndPoint; return endpoint != null ? endpoint.Port : -1; } }
public void SetKeepAlive(Socket socket, UInt32 keepAliveInterval, UInt32 retryInterval) { int size = sizeof(UInt32); UInt32 on = 1;
byte[] inArray = new byte[size * 3]; Array.Copy(BitConverter.GetBytes(on), 0, inArray, 0, size); Array.Copy(BitConverter.GetBytes(keepAliveInterval), 0, inArray, size, size); Array.Copy(BitConverter.GetBytes(retryInterval), 0, inArray, size * 2, size); socket.IOControl(IOControlCode.KeepAliveValues, inArray, null); }
public SocketWrapper(Socket socket) { _tokenSource = new CancellationTokenSource(); _taskFactory = new TaskFactory(_tokenSource.Token); _socket = socket; if (_socket.Connected) _stream = new NetworkStream(_socket);
// The tcp keepalive default values on most systems
// are huge (~7200s). Set them to something more reasonable.
if (Runtime.IsRunningOnWindows()) { SetKeepAlive(socket, KeepAliveInterval, RetryInterval); } }
public Task Authenticate(X509Certificate2 certificate, SslProtocols enabledSslProtocols, Action callback, Action<Exception> error) { var ssl = new SslStream(_stream, false); _stream = new QueuedStream(ssl); Func<AsyncCallback, object, IAsyncResult> begin = (cb, s) => ssl.BeginAuthenticateAsServer(certificate, false, enabledSslProtocols, false, cb, s);
Task task = Task.Factory.FromAsync(begin, ssl.EndAuthenticateAsServer, null); task.ContinueWith(t => callback(), TaskContinuationOptions.NotOnFaulted) .ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted); task.ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
return task; }
public void Listen(int backlog) { _socket.Listen(backlog); }
public void Bind(EndPoint endPoint) { _socket.Bind(endPoint); }
public bool Connected { get { return _socket.Connected; } }
public Stream Stream { get { return _stream; } }
public bool NoDelay { get { return _socket.NoDelay; } set { _socket.NoDelay = value; } }
public EndPoint LocalEndPoint { get { return _socket.LocalEndPoint; } }
public Task<int> Receive(byte[] buffer, Action<int> callback, Action<Exception> error, int offset = 0) { try { Func<AsyncCallback, object, IAsyncResult> begin = (cb, s) => _stream.BeginRead(buffer, offset, buffer.Length, cb, s);
Task<int> task = Task.Factory.FromAsync<int>(begin, _stream.EndRead, null); task.ContinueWith(t => callback(t.Result), TaskContinuationOptions.NotOnFaulted) .ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted); task.ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted); return task; } catch (Exception e) { error(e); return null; } }
public Task<SocketWrapper> Accept(Action<SocketWrapper> callback, Action<Exception> error) { Func<IAsyncResult, SocketWrapper> end = r => _tokenSource.Token.IsCancellationRequested ? null : new SocketWrapper(_socket.EndAccept(r)); var task = _taskFactory.FromAsync(_socket.BeginAccept, end, null); task.ContinueWith(t => callback(t.Result), TaskContinuationOptions.OnlyOnRanToCompletion) .ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted); task.ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted); return task; }
public void Dispose() { _tokenSource.Cancel(); if (_stream != null) _stream.Dispose(); if (_socket != null) _socket.Dispose(); }
public void Close() { _tokenSource.Cancel(); if (_stream != null) _stream.Close(); if (_socket != null) _socket.Close(); }
public int EndSend(IAsyncResult asyncResult) { _stream.EndWrite(asyncResult); return 0; }
public Task Send(byte[] buffer, Action callback, Action<Exception> error) { if (_tokenSource.IsCancellationRequested) return null;
try { Func<AsyncCallback, object, IAsyncResult> begin = (cb, s) => _stream.BeginWrite(buffer, 0, buffer.Length, cb, s);
Task task = Task.Factory.FromAsync(begin, _stream.EndWrite, null); task.ContinueWith(t => callback(), TaskContinuationOptions.NotOnFaulted) .ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted); task.ContinueWith(t => error(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
return task; } catch (Exception e) { error(e); return null; } } } }
#endif
|