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);
                }
            }
        }
예제 #2
0
        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);
                }
            }
        }
예제 #3
0
        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);
                        }
                    }
                }
            }
        }
예제 #4
0
        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);
            }
        }
예제 #5
0
    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();
            }
        }
    }
예제 #6
0
        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();
                    }
                });
            }
        }
예제 #7
0
        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();
        }
예제 #8
0
 public ValueTask <ConnectionContext?> AcceptAsync(CancellationToken cancellationToken = default)
 => _connectionListener.AcceptAsync(cancellationToken);
예제 #9
0
        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();
        }
예제 #10
0
 public async Task <IConnection> AcceptAsync()
 {
     return(new BufferedConnection(await connectionListener.AcceptAsync(), flushTimeout, writeBufferSize));
 }