private void StartAcceptingConnectionsCore(IConnectionListener listener) { // REVIEW: Multiple accept loops in parallel? _ = AcceptConnectionsAsync(); async Task AcceptConnectionsAsync() { try { while (true) { var connection = await listener.AcceptAsync(); if (connection == null) { // We're done listening break; } var id = Interlocked.Increment(ref _lastConnectionId); var kestrelConnection = new KestrelConnection(id, _serviceContext, _connectionDelegate, connection, _serviceContext.Log); ThreadPool.UnsafeQueueUserWorkItem(kestrelConnection, preferLocal: false); } } catch (Exception ex) { // REVIEW: If the accept loop ends should this trigger a server shutdown? It will manifest as a hang Log.LogCritical(0, ex, "The connection listener failed to accept any new connections."); } finally { _acceptLoopTcs.TrySetResult(null); } } }
private void StartAcceptingConnectionsCore(IConnectionListener listener) { // REVIEW: Multiple accept loops in parallel? _ = AcceptConnectionsAsync(); async Task AcceptConnectionsAsync() { try { while (true) { var connection = await listener.AcceptAsync(); if (connection == null) { // We're done listening break; } _ = Execute(new KestrelConnection(connection, _serviceContext.Log)); } } catch (Exception ex) { // REVIEW: If the accept loop ends should this trigger a server shutdown? It will manifest as a hang Log.LogCritical(0, ex, "The connection listener failed to accept any new connections."); } finally { _acceptLoopTcs.TrySetResult(null); } } }
async void AcceptIfNecessaryAsync(bool startAccepting) { if (IsAcceptNecessary) { using (await ThisLock.TakeLockAsync()) { while (IsAcceptNecessary) { Exception unexpectedException = null; try { var acceptTask = listener.AcceptAsync(); // Assigning task to variable to supress warning about not awaiting the task var continuation = acceptTask.ContinueWith( handleCompletedAcceptAsync, CancellationToken.None, TaskContinuationOptions.RunContinuationsAsynchronously, // don't block our accept processing loop ActionItem.IOTaskScheduler); // Run the continuation on the IO Thread Scheduler. Protects against thread starvation pendingAccepts++; } catch (CommunicationException exception) { DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } if (startAccepting) { // Since we're under a call to StartAccepting(), just throw the exception up the stack. throw; } if ((errorCallback == null) && !ExceptionHandlerHelper.HandleTransportExceptionHelper(exception)) { throw; } unexpectedException = exception; } if ((unexpectedException != null) && (errorCallback != null)) { errorCallback(unexpectedException); } } } } }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _connectionListener = await _connectionListenerFactory.BindAsync(new IPEndPoint(IPAddress.Loopback, 6000), stoppingToken); while (true) { ConnectionContext connection = await _connectionListener.AcceptAsync(stoppingToken); // AcceptAsync will return null upon disposing the listener if (connection == null) { break; } // In an actual server, ensure all accepted connections are disposed prior to completing _ = Accept(connection); } }
private void StartAcceptingConnectionsCore(IConnectionListener <T> listener) { // REVIEW: Multiple accept loops in parallel? _ = AcceptConnectionsAsync(); async Task AcceptConnectionsAsync() { try { while (true) { var connection = await listener.AcceptAsync(); if (connection == null) { // We're done listening break; } // Add the connection to the connection manager before we queue it for execution var id = _transportConnectionManager.GetNewConnectionId(); var kestrelConnection = new KestrelConnection <T>( id, _serviceContext, _transportConnectionManager, _connectionDelegate, connection, Log); _transportConnectionManager.AddConnection(id, kestrelConnection); Log.ConnectionAccepted(connection.ConnectionId); KestrelEventSource.Log.ConnectionQueuedStart(connection); ThreadPool.UnsafeQueueUserWorkItem(kestrelConnection, preferLocal: false); } } catch (Exception ex) { // REVIEW: If the accept loop ends should this trigger a server shutdown? It will manifest as a hang Log.LogCritical(0, ex, "The connection listener failed to accept any new connections."); } finally { _acceptLoopTcs.TrySetResult(); } } }
public static async Task RunEchoServerAsync(IConnectionListener listener, CancellationToken cancellationToken = default) { while (true) { var connection = await listener.AcceptAsync(cancellationToken); _ = Task.Run(async() => { try { // This is the simplest implementation of an echo server, copy the input to the output await connection.Transport.Input.CopyToAsync(connection.Transport.Output, cancellationToken); } finally { await connection.DisposeAsync(); } }); } }
public static async Task RunServerAsync(IConnectionListener listener, ConnectionDelegate connectionDelegate, CancellationToken cancellationToken = default) { ValueTask unbindTask = default; cancellationToken.Register(() => { unbindTask = listener.UnbindAsync(); }); while (true) { var connection = await listener.AcceptAsync(cancellationToken); if (connection == null) { break; } _ = Task.Run(async() => { try { await connectionDelegate(connection); } finally { await connection.DisposeAsync(); } }); } await unbindTask; // TODO: Wait for opened connections to close await listener.DisposeAsync(); }
public ValueTask <ConnectionContext?> AcceptAsync(CancellationToken cancellationToken = default) => _connectionListener.AcceptAsync(cancellationToken);
public async Task RunListenerAsync(IConnectionListener listener, ConnectionDelegate connectionDelegate, CancellationToken cancellationToken = default) { var unbindTask = new TaskCompletionSource <object>(); var connections = new ConcurrentDictionary <string, (ConnectionContext Connection, Task ExecutionTask)>(); cancellationToken.Register(async() => { try { await listener.UnbindAsync(); } finally { unbindTask.TrySetResult(null); } }); async Task ExecuteConnectionAsync(ConnectionContext connection) { await Task.Yield(); try { await connectionDelegate(connection); } catch (ConnectionAbortedException) { // Don't let connection aborted exceptions out } catch (Exception ex) { _logger.LogError(ex, "Unexpected exception from connection {ConnectionId}", connection.ConnectionId); } finally { await connection.DisposeAsync(); // Remove the connection from tracking connections.TryRemove(connection.ConnectionId, out _); } } while (true) { try { var connection = await listener.AcceptAsync(cancellationToken); if (connection == null) { // Null means we don't have anymore connections break; } connections[connection.ConnectionId] = (connection, ExecuteConnectionAsync(connection)); } catch (OperationCanceledException) { // The accept loop was cancelled break; } } // Wait for the listener to close, no new connections will be established await unbindTask.Task; // TODO: Give connections a chance to close gracefully var tasks = new List <Task>(connections.Count); // Abort all connections still in flight foreach (var pair in connections) { pair.Value.Connection.Abort(); tasks.Add(pair.Value.ExecutionTask); } await Task.WhenAll(tasks); await listener.DisposeAsync(); }
public async Task <IConnection> AcceptAsync() { return(new BufferedConnection(await connectionListener.AcceptAsync(), flushTimeout, writeBufferSize)); }