예제 #1
0
            public void ReadCallback(UvStreamHandle dispatchPipe, int status)
            {
                if (status == LibuvConstants.EOF && _bytesRead == 0)
                {
                    // This is an unexpected immediate termination of the dispatch pipe most likely caused by an
                    // external process scanning the pipe, so don't we don't log it too severely.
                    // https://github.com/aspnet/AspNetCore/issues/4741

                    dispatchPipe.Dispose();
                    _bufHandle.Free();
                    _listener.Log.LogDebug("An internal pipe was opened unexpectedly.");
                    return;
                }

                try
                {
                    dispatchPipe.Libuv.ThrowIfErrored(status);

                    _bytesRead += status;

                    if (_bytesRead == _bufferLength)
                    {
                        var correctMessage = true;

                        for (var i = 0; i < _bufferLength; i++)
                        {
                            if (_buf[i] != _listener._pipeMessage[i])
                            {
                                correctMessage = false;
                            }
                        }

                        if (correctMessage)
                        {
                            _listener._dispatchPipes.Add((UvPipeHandle)dispatchPipe);
                            dispatchPipe.ReadStop();
                            _bufHandle.Free();
                        }
                        else
                        {
                            throw new IOException("Bad data sent over an internal pipe.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    dispatchPipe.Dispose();
                    _bufHandle.Free();
                    _listener.Log.LogError(0, ex, "ListenerPrimary.ReadCallback");
                }
            }
예제 #2
0
        protected void HandleConnectionAsync(UvStreamHandle socket)
        {
            try
            {
                IPEndPoint remoteEndPoint = null;
                IPEndPoint localEndPoint  = null;

                if (socket is UvTcpHandle tcpHandle)
                {
                    try
                    {
                        remoteEndPoint = tcpHandle.GetPeerIPEndPoint();
                        localEndPoint  = tcpHandle.GetSockIPEndPoint();
                    }
                    catch (UvException ex) when(LibuvConstants.IsConnectionReset(ex.StatusCode))
                    {
                        TransportContext.Log.ConnectionReset("(null)");
                        socket.Dispose();
                        return;
                    }
                }

                var connection = new LibuvConnection(socket, TransportContext.Log, Thread, remoteEndPoint, localEndPoint);
                TransportContext.ConnectionDispatcher.OnConnection(connection);
                _ = connection.Start();
            }
            catch (Exception ex)
            {
                TransportContext.Log.LogCritical(ex, $"Unexpected exception in {nameof(ListenerContext)}.{nameof(HandleConnectionAsync)}.");
            }
        }
예제 #3
0
        protected internal void HandleConnection(UvStreamHandle socket)
        {
            try
            {
                IPEndPoint remoteEndPoint = null;
                IPEndPoint localEndPoint  = null;

                if (socket is UvTcpHandle tcpHandle)
                {
                    try
                    {
                        remoteEndPoint = tcpHandle.GetPeerIPEndPoint();
                        localEndPoint  = tcpHandle.GetSockIPEndPoint();
                    }
                    catch (UvException ex) when(LibuvConstants.IsConnectionReset(ex.StatusCode))
                    {
                        TransportContext.Log.ConnectionReset("(null)");
                        socket.Dispose();
                        return;
                    }
                }

                var options    = TransportContext.Options;
                var connection = new LibuvConnection(socket, TransportContext.Log, Thread, remoteEndPoint, localEndPoint, InputOptions, OutputOptions, options.MaxReadBufferSize, options.MaxWriteBufferSize);
                connection.Start();

                bool accepted = _acceptQueue.Writer.TryWrite(connection);
                Debug.Assert(accepted, "The connection was not written to the channel!");
            }
            catch (Exception ex)
            {
                TransportContext.Log.LogCritical(ex, $"Unexpected exception in {nameof(ListenerContext)}.{nameof(HandleConnection)}.");
            }
        }
예제 #4
0
        public async Task Start()
        {
            try
            {
                OutputConsumer = new LibuvOutputConsumer(Output, Thread, _socket, ConnectionId, Log);

                StartReading();

                Exception inputError  = null;
                Exception outputError = null;

                try
                {
                    // This *must* happen after socket.ReadStart
                    // The socket output consumer is the only thing that can close the connection. If the
                    // output pipe is already closed by the time we start then it's fine since, it'll close gracefully afterwards.
                    await OutputConsumer.WriteOutputAsync();
                }
                catch (UvException ex)
                {
                    // The connection reset/error has already been logged by LibuvOutputConsumer
                    if (ex.StatusCode == LibuvConstants.ECANCELED)
                    {
                        // Connection was aborted.
                    }
                    else if (LibuvConstants.IsConnectionReset(ex.StatusCode))
                    {
                        // Don't cause writes to throw for connection resets.
                        inputError = new ConnectionResetException(ex.Message, ex);
                    }
                    else
                    {
                        inputError  = ex;
                        outputError = ex;
                    }
                }
                finally
                {
                    // Now, complete the input so that no more reads can happen
                    Input.Complete(inputError ?? _abortReason ?? new ConnectionAbortedException());
                    Output.Complete(outputError);

                    // Make sure it isn't possible for a paused read to resume reading after calling uv_close
                    // on the stream handle
                    Input.CancelPendingFlush();

                    // Send a FIN
                    Log.ConnectionWriteFin(ConnectionId);

                    // We're done with the socket now
                    _socket.Dispose();
                    ThreadPool.QueueUserWorkItem(state => ((LibuvConnection)state).CancelConnectionClosedToken(), this);
                }
            }
            catch (Exception e)
            {
                Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}");
            }
        }
예제 #5
0
        /// <summary>
        /// Handles an incoming connection
        /// </summary>
        /// <param name="listenSocket">Socket being used to listen on</param>
        /// <param name="status">Connection status</param>
        private void OnConnection(UvStreamHandle listenSocket, int status)
        {
            UvStreamHandle acceptSocket = null;

            try
            {
                acceptSocket = CreateAcceptSocket();
                listenSocket.Accept(acceptSocket);
                DispatchConnection(acceptSocket);
            }
            catch (UvException ex) when(LibuvConstants.IsConnectionReset(ex.StatusCode))
            {
                Log.ConnectionReset("(null)");
                acceptSocket?.Dispose();
            }
            catch (UvException ex)
            {
                Log.LogError(0, ex, "Listener.OnConnection");
                acceptSocket?.Dispose();
            }
        }
예제 #6
0
        public async Task Start()
        {
            try
            {
                _connectionContext = ConnectionHandler.OnConnection(this);
                ConnectionId       = _connectionContext.ConnectionId;

                Input  = _connectionContext.Input;
                Output = new LibuvOutputConsumer(_connectionContext.Output, Thread, _socket, ConnectionId, Log);

                StartReading();

                Exception error = null;

                try
                {
                    // This *must* happen after socket.ReadStart
                    // The socket output consumer is the only thing that can close the connection. If the
                    // output pipe is already closed by the time we start then it's fine since, it'll close gracefully afterwards.
                    await Output.WriteOutputAsync();
                }
                catch (UvException ex)
                {
                    error = new IOException(ex.Message, ex);
                }
                finally
                {
                    // Now, complete the input so that no more reads can happen
                    Input.Complete(error ?? new ConnectionAbortedException());
                    _connectionContext.Output.Complete(error);
                    _connectionContext.OnConnectionClosed(error);

                    // Make sure it isn't possible for a paused read to resume reading after calling uv_close
                    // on the stream handle
                    Input.CancelPendingFlush();

                    // Send a FIN
                    Log.ConnectionWriteFin(ConnectionId);

                    // We're done with the socket now
                    _socket.Dispose();
                }
            }
            catch (Exception e)
            {
                Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}");
            }
        }
예제 #7
0
        /// <summary>
        /// Handles an incoming connection
        /// </summary>
        /// <param name="listenSocket">Socket being used to listen on</param>
        /// <param name="status">Connection status</param>
        private void OnConnection(UvStreamHandle listenSocket, int status)
        {
            UvStreamHandle acceptSocket = null;

            try
            {
                acceptSocket = CreateAcceptSocket();
                listenSocket.Accept(acceptSocket);
                DispatchConnection(acceptSocket);
            }
            catch (UvException ex)
            {
                Log.LogError(0, ex, "Listener.OnConnection");
                acceptSocket?.Dispose();
            }
        }
예제 #8
0
            public void ReadCallback(UvStreamHandle dispatchPipe, int status)
            {
                try
                {
                    dispatchPipe.Libuv.ThrowIfErrored(status);

                    _bytesRead += status;

                    if (_bytesRead == _bufferLength)
                    {
                        var correctMessage = true;

                        for (var i = 0; i < _bufferLength; i++)
                        {
                            if (_buf[i] != _listener._pipeMessage[i])
                            {
                                correctMessage = false;
                            }
                        }

                        if (correctMessage)
                        {
                            _listener._dispatchPipes.Add((UvPipeHandle)dispatchPipe);
                            dispatchPipe.ReadStop();
                            _bufHandle.Free();
                        }
                        else
                        {
                            throw new IOException("Bad data sent over Kestrel pipe.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    dispatchPipe.Dispose();
                    _bufHandle.Free();
                    _listener.Log.LogError(0, ex, "ListenerPrimary.ReadCallback");
                }
            }
예제 #9
0
        private async Task StartCore()
        {
            try
            {
                OutputConsumer = new LibuvOutputConsumer(Output, Thread, _socket, ConnectionId, Log);

                StartReading();

                Exception inputError  = null;
                Exception outputError = null;

                try
                {
                    // This *must* happen after socket.ReadStart
                    // The socket output consumer is the only thing that can close the connection. If the
                    // output pipe is already closed by the time we start then it's fine since, it'll close gracefully afterwards.
                    await OutputConsumer.WriteOutputAsync();
                }
                catch (UvException ex)
                {
                    // The connection reset/error has already been logged by LibuvOutputConsumer
                    if (ex.StatusCode == LibuvConstants.ECANCELED)
                    {
                        // Connection was aborted.
                    }
                    else if (LibuvConstants.IsConnectionReset(ex.StatusCode))
                    {
                        // Don't cause writes to throw for connection resets.
                        inputError = new ConnectionResetException(ex.Message, ex);
                    }
                    else
                    {
                        // This is unexpected.
                        Log.ConnectionError(ConnectionId, ex);

                        inputError  = ex;
                        outputError = ex;
                    }
                }
                finally
                {
                    inputError ??= _abortReason ?? new ConnectionAbortedException("The libuv transport's send loop completed gracefully.");

                    // Now, complete the input so that no more reads can happen
                    Input.Complete(inputError);
                    Output.Complete(outputError);

                    // Make sure it isn't possible for a paused read to resume reading after calling uv_close
                    // on the stream handle
                    Input.CancelPendingFlush();

                    // Send a FIN
                    Log.ConnectionWriteFin(ConnectionId, inputError.Message);

                    // We're done with the socket now
                    _socket.Dispose();

                    // Fire the connection closed token and wait for it to complete
                    var waitForConnectionClosedTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

                    ThreadPool.UnsafeQueueUserWorkItem(state =>
                    {
                        (var connection, var tcs) = state;

                        connection.CancelConnectionClosedToken();

                        tcs.TrySetResult(null);
                    },
                                                       (this, waitForConnectionClosedTcs),
                                                       preferLocal: false);

                    await waitForConnectionClosedTcs.Task;
                }
            }
            catch (Exception e)
            {
                Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}");
            }
        }
예제 #10
0
        private async Task StartCore()
        {
            try
            {
                OutputConsumer = new LibuvOutputConsumer(Output, Thread, _socket, ConnectionId, Log);

                StartReading();

                Exception inputError  = null;
                Exception outputError = null;

                try
                {
                    // This *must* happen after socket.ReadStart
                    // The socket output consumer is the only thing that can close the connection. If the
                    // output pipe is already closed by the time we start then it's fine since, it'll close gracefully afterwards.
                    await OutputConsumer.WriteOutputAsync();
                }
                catch (UvException ex)
                {
                    // The connection reset/error has already been logged by LibuvOutputConsumer
                    if (ex.StatusCode == LibuvConstants.ECANCELED)
                    {
                        // Connection was aborted.
                    }
                    else if (LibuvConstants.IsConnectionReset(ex.StatusCode))
                    {
                        // Don't cause writes to throw for connection resets.
                        inputError = new ConnectionResetException(ex.Message, ex);
                    }
                    else
                    {
                        // This is unexpected.
                        LibuvTrace.ConnectionError(Log, ConnectionId, ex);

                        inputError  = ex;
                        outputError = ex;
                    }
                }
                finally
                {
                    inputError ??= _abortReason ?? new ConnectionAbortedException("The libuv transport's send loop completed gracefully.");

                    // Now, complete the input so that no more reads can happen
                    Input.Complete(inputError);
                    Output.Complete(outputError);

                    // Make sure it isn't possible for a paused read to resume reading after calling uv_close
                    // on the stream handle
                    Input.CancelPendingFlush();

                    // Send a FIN
                    LibuvTrace.ConnectionWriteFin(Log, ConnectionId, inputError.Message);

                    // We're done with the socket now
                    _socket.Dispose();

                    // Ensure this always fires
                    FireConnectionClosed();

                    await _waitForConnectionClosedTcs.Task;
                }
            }
            catch (Exception e)
            {
                Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}");
            }
        }