Beispiel #1
0
        public IPromise Unvoid()
        {
            var promise = new TaskCompletionSource();

            if (_fireException)
            {
                _ = promise.Task.ContinueWith(FireExceptionOnFailureAction, _channel, TaskContinuationOptions.ExecuteSynchronously);
            }
            return(promise);
        }
Beispiel #2
0
            public override Task ConnectAsync(EndPoint remoteAddress, EndPoint localAddress)
            {
                var promise = new TaskCompletionSource();

                if (Volatile.Read(ref _channel.v_state) == State.Connected)
                {
                    var cause = new AlreadyConnectedException();
                    Util.SafeSetFailure(promise, cause, Logger);
                    _ = _channel.Pipeline.FireExceptionCaught(cause);
                    return(promise.Task);
                }

                if (Volatile.Read(ref _channel.v_connectPromise) is object)
                {
                    ThrowHelper.ThrowConnectionPendingException();
                }

                _ = Interlocked.Exchange(ref _channel.v_connectPromise, promise);

                if (Volatile.Read(ref _channel.v_state) != State.Bound)
                {
                    // Not bound yet and no localAddress specified - get one.
                    if (localAddress is null)
                    {
                        localAddress = new LocalAddress(_channel);
                    }
                }

                if (localAddress is object)
                {
                    try
                    {
                        _channel.DoBind(localAddress);
                    }
                    catch (Exception ex)
                    {
                        Util.SafeSetFailure(promise, ex, Logger);
                        _ = _channel.CloseAsync();
                        return(promise.Task);
                    }
                }

                IChannel boundChannel = LocalChannelRegistry.Get(remoteAddress);

                if (!(boundChannel is LocalServerChannel serverChannel))
                {
                    Exception cause = new ConnectException($"connection refused: {remoteAddress}", null);
                    Util.SafeSetFailure(promise, cause, Logger);
                    _ = _channel.CloseAsync();
                    return(promise.Task);
                }

                _ = Interlocked.Exchange(ref _channel.v_peer, serverChannel.Serve(_channel));
                return(promise.Task);
            }
Beispiel #3
0
        protected override void DoClose()
        {
            var peer     = Volatile.Read(ref v_peer);
            var oldState = Volatile.Read(ref v_state);

            try
            {
                if (oldState != State.Closed)
                {
                    // Update all internal state before the closeFuture is notified.
                    var thisLocalAddr = Volatile.Read(ref v_localAddress);
                    if (thisLocalAddr is object)
                    {
                        if (Parent is null)
                        {
                            LocalChannelRegistry.Unregister(thisLocalAddr);
                        }
                        _ = Interlocked.Exchange(ref v_localAddress, null);
                    }

                    // State change must happen before finishPeerRead to ensure writes are released either in doWrite or
                    // channelRead.
                    _ = Interlocked.Exchange(ref v_state, State.Closed);

                    // Preserve order of event and force a read operation now before the close operation is processed.
                    if (SharedConstants.False < (uint)Volatile.Read(ref v_writeInProgress) && peer is object)
                    {
                        FinishPeerRead(peer);
                    }

                    TaskCompletionSource promise = Volatile.Read(ref v_connectPromise);
                    if (promise is object)
                    {
                        // Use tryFailure() instead of setFailure() to avoid the race against cancel().
                        _ = promise.TrySetException(DoCloseClosedChannelException);
                        _ = Interlocked.Exchange(ref v_connectPromise, null);
                    }
                }

                if (peer is object)
                {
                    _ = Interlocked.Exchange(ref v_peer, null);
                    // Always call peer.eventLoop().execute() even if peer.eventLoop().inEventLoop() is true.
                    // This ensures that if both channels are on the same event loop, the peer's channelInActive
                    // event is triggered *after* this peer's channelInActive event
                    IEventLoop peerEventLoop = peer.EventLoop;
                    bool       peerIsActive  = peer.IsActive;
                    try
                    {
                        peerEventLoop.Execute(() => peer.TryClose(peerIsActive));
                    }
                    catch (Exception cause)
                    {
                        Logger.Warn("Releasing Inbound Queues for channels {}-{} because exception occurred!", this, peer, cause);

                        if (peerEventLoop.InEventLoop)
                        {
                            peer.ReleaseInboundBuffers();
                        }
                        else
                        {
                            // inboundBuffers is a SPSC so we may leak if the event loop is shutdown prematurely or
                            // rejects the close Runnable but give a best effort.
                            _ = peer.CloseAsync();
                        }
                        throw;
                    }
                }
            }
            finally
            {
                // Release all buffers if the Channel was already registered in the past and if it was not closed before.
                if (oldState != State.Closed)
                {
                    // We need to release all the buffers that may be put into our inbound queue since we closed the Channel
                    // to ensure we not leak any memory. This is fine as it basically gives the same guarantees as TCP which
                    // means even if the promise was notified before its not really guaranteed that the "remote peer" will
                    // see the buffer at all.
                    ReleaseInboundBuffers();
                }
            }
        }