private static void OnAcceptCompleted(object _, SocketAsyncEventArgs socketAsyncEventArgs) { if (socketAsyncEventArgs == null) { throw new ArgumentNullException(nameof(socketAsyncEventArgs)); } var acceptCompletionSource = (TaskCompletionSource <Socket>)socketAsyncEventArgs.UserToken; socketAsyncEventArgs.UserToken = null; if (socketAsyncEventArgs.ConnectByNameError != null) { acceptCompletionSource.TrySetException(socketAsyncEventArgs.ConnectByNameError); } else if (socketAsyncEventArgs.SocketError != SocketError.Success) { acceptCompletionSource.TrySetException(new SocketException((int)socketAsyncEventArgs.SocketError)); } else { var socket = socketAsyncEventArgs.AcceptSocket; if (acceptCompletionSource.TrySetResult(socket) == false) { SafeEnd.Dispose(socket); } } }
private async Task NegotiateWebSocket(Socket client) { await Task.Yield(); ConfigureSocket(client); WebSocketNegotiationResult result; try { var timeoutTask = Task.Delay(_configuration.Options.NegotiationTimeout); var stream = await NegotiateStreamAsync(client, timeoutTask).ConfigureAwait(false); var handshake = await HandshakeAsync(stream, timeoutTask).ConfigureAwait(false); if (handshake.IsValid) { var ws = handshake.Factory.CreateWebSocket(stream, client, _configuration.Options, handshake); result = new WebSocketNegotiationResult(ws); } else { SafeEnd.Dispose(client); result = new WebSocketNegotiationResult(handshake.Error); } } catch (Exception ex) { SafeEnd.Dispose(client); result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(ex)); } await DeliverResultAsync(result).ConfigureAwait(false); }
public async Task CloseAsync() { var clients = this.connectedClients.ToArray(); var disconnectTasks = new Task[clients.Length]; for (var i = 0; i < clients.Length; i++) { try { disconnectTasks[i] = clients[i].CloseAsync().ContinueWith( (t, s) => SafeEnd.Dispose((IDisposable)s, this.log), clients[i], CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default ); } catch (Exception error) when(error is ThreadAbortException == false) { disconnectTasks[i] = TaskHelper.FailedTask(error); lock (this.DetailedErrors) this.DetailedErrors.Add(error.Unwrap()); Interlocked.Decrement(ref this.Errors); } } await Task.WhenAll(disconnectTasks).ConfigureAwait(false); await this.client.CloseAsync().ConfigureAwait(false); }
private NetworkConnection AcceptSocketAsConnection(Task <Socket> acceptTask, EndPoint acceptEndPoint) { var error = acceptTask.Exception.Unwrap(); if (acceptTask.Status != TaskStatus.RanToCompletion) { if (this.log.IsDebugEnabled && error != null && error is OperationCanceledException == false && this.state == STATE_ACCEPTING) { this.log.Debug($"Accept on '{acceptEndPoint}' has failed.", error); } return(null); } var socket = acceptTask.Result; if (this.log.IsDebugEnabled) { this.log.Debug($"New socket accepted. Remote address: '{socket.RemoteEndPoint}', Local address: {socket.LocalEndPoint}."); } try { return(this.CreateConnection(socket)); } catch { SafeEnd.Dispose(socket, this.log); throw; } }
public override async Task PingAsync() { if (this.connection.IsClosed) { return; } var elapsedTime = TimestampToTimeSpan(Stopwatch.GetTimestamp()) - this.lastActivityTime; if (elapsedTime > this.pingTimeout) { SafeEnd.Dispose(this.connection); if (this.connection.log.IsDebugEnabled) { this.connection.log.Debug($"WebSocket connection ({this.connection.GetHashCode():X}) has been closed due ping timeout. Time elapsed: {elapsedTime}, timeout: {this.pingTimeout}."); } return; } var messageType = (WebSocketMessageType)WebSocketFrameOption.Ping; var count = this.pingBuffer.Array[this.pingBuffer.Offset]; var payload = this.pingBuffer.Skip(1); // manual pinging is always enforces sending ping frames var pingFrame = this.connection.PrepareFrame(payload, count, true, false, messageType, WebSocketExtensionFlags.None); await this.connection.SendFrameAsync(pingFrame, Timeout.InfiniteTimeSpan, SendOptions.NoErrors, CancellationToken.None).ConfigureAwait(false); }
public void Queue(Socket socket) { if (!_sockets.Post(socket)) { SafeEnd.Dispose(socket); } }
/// <inheritdoc /> protected override void Dispose(bool disposed) { if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED) { return; } foreach (var socket in this.sockets) { SafeEnd.Dispose(socket, this.log); } foreach (var acceptEvent in this.activeAcceptEvents.Concat(this.availableAcceptEvents)) { var acceptCompletion = (TaskCompletionSource <Socket>)acceptEvent.UserToken; if (acceptCompletion != null) { acceptCompletion.TrySetCanceled(); if (acceptCompletion.Task.Status == TaskStatus.RanToCompletion) { SafeEnd.Dispose(acceptCompletion.Task.Result, this.log); } } SafeEnd.Dispose(acceptEvent, this.log); } }
private async Task NegotiateWebSocket(Socket client) { WebSocketNegotiationResult result; try { var timeoutTask = Task.Delay(_options.NegotiationTimeout); #if (NET45 || NET451 || NET452 || NET46) Stream stream = new NetworkStream(client, FileAccess.ReadWrite, true); #elif (DNX451 || DNX452 || DNX46 || NETSTANDARD || UAP10_0 || DOTNET5_4 || NETSTANDARDAPP1_5) Stream stream = new NetworkStream(client); #endif foreach (var conExt in _extensions) { var extTask = conExt.ExtendConnectionAsync(stream); await Task.WhenAny(timeoutTask, extTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { throw new WebSocketException("Negotiation timeout (Extension: " + conExt.GetType().Name + ")"); } stream = await extTask; } var handshakeTask = _handShaker.HandshakeAsync(stream); await Task.WhenAny(timeoutTask, handshakeTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { throw new WebSocketException("Negotiation timeout"); } var handshake = await handshakeTask; if (handshake.IsValid) { result = new WebSocketNegotiationResult(handshake.Factory.CreateWebSocket(stream, _options, (IPEndPoint)client.LocalEndPoint, (IPEndPoint)client.RemoteEndPoint, handshake.Request, handshake.Response, handshake.NegotiatedMessageExtensions)); } else { SafeEnd.Dispose(client); result = new WebSocketNegotiationResult(handshake.Error); } } catch (Exception ex) { SafeEnd.Dispose(client); result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(ex)); } try { await _negotiations.SendAsync(result, _cancel.Token).ConfigureAwait(false); } finally { _semaphore.Release(); } }
/// <inheritdoc /> protected override void Dispose(bool disposed) { if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED) { return; } SafeEnd.Dispose(this.server, this.log); }
/// <inheritdoc /> protected override void Dispose(bool disposing) { if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED) { return; } SafeEnd.Dispose(this.deflateStream); SafeEnd.Dispose(this.innerStream); }
public void Dispose() { SafeEnd.Dispose(_semaphore); if (_cancel != null) { _cancel.Cancel(); _cancel.Dispose(); } }
protected override void Dispose(bool disposing) { if (Interlocked.Exchange(ref this.state, STATE_DISPOSED) == STATE_DISPOSED) { return; } SafeEnd.Dispose(this.innerStream); this.bufferManager.ReturnBuffer(this.inflaterBuffer); }
protected SocketListener(SocketTransport transport, EndPoint[] endPointsToListen, ProtocolType protocolType, WebSocketListenerOptions options) { if (endPointsToListen == null) { throw new ArgumentNullException(nameof(endPointsToListen)); } if (endPointsToListen.Any(p => p == null)) { throw new ArgumentException("Null objects passed in array.", nameof(endPointsToListen)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } this.log = options.Logger; this.sockets = EmptySockets; this.localEndPoints = EmptyEndPoints; var boundSockets = new Socket[endPointsToListen.Length]; var boundEndpoints = new EndPoint[endPointsToListen.Length]; var activeEvents = new SocketAsyncEventArgs[endPointsToListen.Length]; var availableEvents = new SocketAsyncEventArgs[endPointsToListen.Length]; try { for (var i = 0; i < boundSockets.Length; i++) { boundSockets[i] = new Socket(endPointsToListen[i].AddressFamily, SocketType.Stream, protocolType); boundSockets[i].Bind(endPointsToListen[i]); boundSockets[i].Listen(transport.BacklogSize); boundEndpoints[i] = boundSockets[i].LocalEndPoint; activeEvents[i] = CreateSocketAsyncEvent(); availableEvents[i] = CreateSocketAsyncEvent(); } this.sockets = boundSockets; this.localEndPoints = boundEndpoints; this.acceptTasks = new Task <Socket> [boundSockets.Length]; this.availableAcceptEvents = activeEvents; this.activeAcceptEvents = availableEvents; boundSockets = null; } finally { if (boundSockets != null) { foreach (var socket in boundSockets) { SafeEnd.Dispose(socket); } } } }
/// <inheritdoc /> public override void Dispose(bool disposed) { if (Interlocked.Exchange(ref this.closeState, STATE_DISPOSED) == STATE_DISPOSED) { return; } SafeEnd.Dispose(this.networkStream); SafeEnd.Dispose(this.socket); foreach (var socketEvent in this.socketEvents) { SafeEnd.Dispose(socketEvent); } }
public override async Task CloseAsync() { if (_isClosed) { return; } _isClosed = true; await _deflate.FlushAsync().ConfigureAwait(false); SafeEnd.Dispose(_deflate); // TODO DeflateStream cant async flush buffer so this will cause sync Write call and blocks one thread from pool await _inner.WriteAsync(BFINAL, 0, 1).ConfigureAwait(false); await _inner.CloseAsync().ConfigureAwait(false); }
public void Dispose() { if (Interlocked.Exchange(ref this.closeState, WS_STATE_DISPOSED) == WS_STATE_DISPOSED) { return; } this.latency = Timeout.InfiniteTimeSpan; SafeEnd.Dispose(this.networkConnection, this.log); SafeEnd.Dispose(this.writeSemaphore, this.log); this.options.BufferManager.ReturnBuffer(this.SendBuffer.Array); this.options.BufferManager.ReturnBuffer(this.headerBuffer.Array); }
public void Dispose() { this.CloseAsync(WebSocketCloseReasons.NormalClose).Wait(); if (Interlocked.Exchange(ref this.closeState, CLOSE_STATE_DISPOSED) == CLOSE_STATE_DISPOSED) { return; } this.options.BufferManager.ReturnBuffer(this.SendBuffer.Array); this.options.BufferManager.ReturnBuffer(this.closeBuffer.Array); SafeEnd.Dispose(this.writeSemaphore, this.log); SafeEnd.Dispose(this.networkConnection, this.log); }
public void Dispose() { SafeEnd.Dispose(_semaphore, this.log); _cancel?.Cancel(throwOnFirstException: false); foreach (var connection in this._connections.TakeAllAndClose(closeError: new OperationCanceledException())) { SafeEnd.Dispose(connection, this.log); } foreach (var negotiation in this._negotiations.TakeAllAndClose()) { SafeEnd.Dispose(negotiation.Result, this.log); } SafeEnd.Dispose(this.pingQueue, this.log); }
public void Queue(NetworkConnection connection) { if (connection == null) { throw new ArgumentNullException(nameof(connection)); } if (!this._connections.TryEnqueue(connection)) { if (this.log.IsWarningEnabled) { this.log.Warning($"Negotiation queue is full and can't process new connection from '{connection.RemoteEndPoint}'. Connection will be closed."); } connection.CloseAsync().ContinueWith(_ => SafeEnd.Dispose(connection, this.log), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } }
public void Dispose() { try { this.Close(); } catch { } finally { if (_options != null && _options.BufferManager != null) { _options.BufferManager.ReturnBuffer(_buffer); } } SafeEnd.Dispose(_writeSemaphore); SafeEnd.Dispose(_clientStream); }
public override async Task PingAsync() { if (this.connection.IsClosed) { return; } var elapsedTime = TimestampToTimeSpan(Stopwatch.GetTimestamp()) - this.lastActivityTime; if (elapsedTime > this.pingTimeout) { this.connection.latency = Timeout.InfiniteTimeSpan; SafeEnd.Dispose(this.connection); if (this.connection.log.IsDebugEnabled) { this.connection.log.Debug($"WebSocket connection ({this.connection.GetHashCode():X}) has been closed due ping timeout. Time elapsed: {elapsedTime}, timeout: {this.pingTimeout}, interval: {this.pingInterval}."); } return; } ((ulong)Stopwatch.GetTimestamp()).ToBytes(this.pingBuffer.Array, this.pingBuffer.Offset); var messageType = (WebSocketMessageType)WebSocketFrameOption.Ping; var pingFrame = this.connection.PrepareFrame(this.pingBuffer, 8, true, false, messageType, WebSocketExtensionFlags.None); var pingFrameLockTimeout = elapsedTime < this.pingInterval ? TimeSpan.Zero : Timeout.InfiniteTimeSpan; // // ping_interval is 33% of ping_timeout time // // if elapsed_time < ping_interval then TRY to send ping frame // if elapsed_time > ping_interval then ENFORCE sending ping frame because ping_timeout is near // // pingFrameLockTimeout is controlling TRY/ENFORCE behaviour. Zero mean TRY to take write lock or skip. InfiniteTimeSpan mean wait indefinitely for write lock. // await this.connection.SendFrameAsync(pingFrame, pingFrameLockTimeout, SendOptions.NoErrors, CancellationToken.None).ConfigureAwait(false); }
/// <inheritdoc /> public override async Task CloseAsync() { if (Interlocked.CompareExchange(ref this.closeState, STATE_CLOSING, STATE_OPEN) != STATE_OPEN) { return; } // shutdown send try { if (this.socket.Connected) { this.socket.Shutdown(SocketShutdown.Send); } } catch (Exception shutdownError) when(shutdownError is ThreadAbortException == false) { /* ignore shutdown errors */ } // read and discard all remaining data if (this.socket.Connected || this.socket.Available > 0) { try { var receiveCompletionSource = default(TaskCompletionSource <int>); do { receiveCompletionSource = new TaskCompletionSource <int>(); Swap(ref this.socketEvents[EVENT_ACTIVE_RECEIVE], ref this.socketEvents[EVENT_PREVIOUS_RECEIVE]); var receiveEvent = this.socketEvents[EVENT_ACTIVE_RECEIVE]; receiveEvent.UserToken = receiveCompletionSource; receiveEvent.SetBuffer(JunkBytes, 0, JunkBytes.Length); if (this.socket.ReceiveAsync(receiveEvent) == false) { this.OnSocketOperationCompleted(this.socket, receiveEvent); } } while (await receiveCompletionSource.Task.ConfigureAwait(false) > 0); } catch (Exception readError) when(readError is ThreadAbortException == false) { /* ignore read errors */ } } // close socket try { this.socket.Dispose(); } catch (Exception closeError) when(closeError is ThreadAbortException == false) { /* ignore close errors */ } Interlocked.CompareExchange(ref this.closeState, STATE_CLOSED, STATE_CLOSING); SafeEnd.Dispose(this); }
private async Task NegotiateWebSocket(NetworkConnection networkConnection) { if (networkConnection == null) { throw new ArgumentNullException(nameof(networkConnection)); } await Task.Yield(); WebSocketNegotiationResult result; try { var timeoutTask = Task.Delay(_options.NegotiationTimeout); foreach (var conExt in _extensions) { var extTask = conExt.ExtendConnectionAsync(networkConnection); await Task.WhenAny(timeoutTask, extTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { #pragma warning disable 4014 extTask.IgnoreFaultOrCancellation(); // make connection exception observed #pragma warning restore 4014 throw new WebSocketException($"Negotiation timeout (Extension: {conExt.GetType().Name})"); } networkConnection = await extTask.ConfigureAwait(false); } var handshakeTask = _handShaker.HandshakeAsync(networkConnection); await Task.WhenAny(timeoutTask, handshakeTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { #pragma warning disable 4014 handshakeTask.IgnoreFaultOrCancellation(); // make connection exception observed #pragma warning restore 4014 throw new WebSocketException("Negotiation timeout"); } var handshake = await handshakeTask.ConfigureAwait(false); if (handshake.IsValidWebSocketRequest) { result = new WebSocketNegotiationResult(handshake.Factory.CreateWebSocket(networkConnection, _options, handshake.Request, handshake.Response, handshake.NegotiatedMessageExtensions)); } else if (handshake.IsValidHttpRequest && _options.HttpFallback != null) { _options.HttpFallback.Post(handshake.Request, networkConnection); return; } else { SafeEnd.Dispose(networkConnection, this.log); result = new WebSocketNegotiationResult(handshake.Error); } var webSocket = result.Result; if (_negotiations.TryEnqueue(result) == false) { SafeEnd.Dispose(webSocket); return; // too many negotiations } if (webSocket != null) { this.pingQueue?.GetSubscriptionList().Add(webSocket); } } catch (Exception negotiationError) { if (this.log.IsDebugEnabled) { this.log.Debug("An error occurred while negotiating WebSocket request.", negotiationError); } SafeEnd.Dispose(networkConnection, this.log); result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(negotiationError)); } finally { _semaphore.Release(); } }
public override void Dispose() { SafeEnd.Dispose(Connection); }
/// <inheritdoc /> public override void Dispose(bool disposed) { SafeEnd.Dispose(this.pipeStream); }
/// <inheritdoc /> internal override async Task <NetworkConnection> ConnectAsync(Uri address, WebSocketListenerOptions options, CancellationToken cancellation) { if (address == null) { throw new ArgumentNullException(nameof(address)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } var remoteEndPoint = this.GetRemoteEndPoint(address); var protocolType = this.GetProtocolType(address, remoteEndPoint); // prepare socket var socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Stream, protocolType); this.SetupClientSocket(socket, remoteEndPoint); try { // prepare connection var socketConnectedCondition = new AsyncConditionSource { ContinueOnCapturedContext = false }; var socketAsyncEventArgs = new SocketAsyncEventArgs { RemoteEndPoint = remoteEndPoint, UserToken = socketConnectedCondition }; // connect socketAsyncEventArgs.Completed += (_, e) => ((AsyncConditionSource)e.UserToken).Set(); // interrupt connection when cancellation token is set var connectInterruptRegistration = cancellation.CanBeCanceled ? cancellation.Register(s => ((AsyncConditionSource)s).Interrupt(new OperationCanceledException()), socketConnectedCondition) : default(CancellationTokenRegistration); using (connectInterruptRegistration) { if (socket.ConnectAsync(socketAsyncEventArgs) == false) { socketConnectedCondition.Set(); } await socketConnectedCondition; } cancellation.ThrowIfCancellationRequested(); // check connection result if (socketAsyncEventArgs.ConnectByNameError != null) { throw socketAsyncEventArgs.ConnectByNameError; } if (socketAsyncEventArgs.SocketError != SocketError.Success) { throw new WebSocketException($"Failed to open socket to '{address}' due error '{socketAsyncEventArgs.SocketError}'.", new SocketException((int)socketAsyncEventArgs.SocketError)); } var localEndPoint = default(EndPoint); try { localEndPoint = socket.LocalEndPoint; } catch { if (UnixSocketTransport.IsUnixEndPoint(remoteEndPoint)) { localEndPoint = remoteEndPoint; } } var connection = new SocketConnection(socket, localEndPoint); socket = null; return(connection); } finally { if (socket != null) { SafeEnd.Dispose(socket, options.Logger); } } }
public override void Dispose() { SafeEnd.Dispose(this.Connection, this.log); }
protected override void Dispose(Boolean disposing) { SafeEnd.Dispose(_deflate); SafeEnd.Dispose(_inner); base.Dispose(disposing); }